From 915f55e54fbfa07dc1b730cf70f77570a473f766 Mon Sep 17 00:00:00 2001 From: Leo Zhang Date: Mon, 6 Aug 2018 19:27:40 -0700 Subject: [PATCH] refactor(monad): Remove polymorphic monads --- analyzers/golang/find.go | 10 ------- analyzers/golang/lockfile.go | 32 +++++++++++---------- cli.go | 13 --------- files/files_test.go | 16 +++++++++++ files/find.go | 20 ------------- monad/monad.go | 54 ------------------------------------ vcs/find.go | 28 ------------------- vcs/types.go | 34 +++++++++++++++++++++++ vcs/vcs.go | 48 +++++++++++++++----------------- 9 files changed, 89 insertions(+), 166 deletions(-) delete mode 100644 analyzers/golang/find.go delete mode 100644 cli.go create mode 100644 files/files_test.go delete mode 100644 monad/monad.go delete mode 100644 vcs/find.go create mode 100644 vcs/types.go diff --git a/analyzers/golang/find.go b/analyzers/golang/find.go deleted file mode 100644 index b3cef7f7a3..0000000000 --- a/analyzers/golang/find.go +++ /dev/null @@ -1,10 +0,0 @@ -package golang - -import ( - "github.com/fossas/fossa-cli/files" - "github.com/fossas/fossa-cli/monad" -) - -func findFile(tool string, pathElems ...string) monad.EitherStrFunc { - return files.BindFinder(tool, files.Exists, pathElems...) -} diff --git a/analyzers/golang/lockfile.go b/analyzers/golang/lockfile.go index 69e34c016b..f84e7599c3 100644 --- a/analyzers/golang/lockfile.go +++ b/analyzers/golang/lockfile.go @@ -6,7 +6,6 @@ import ( "github.com/fossas/fossa-cli/analyzers/golang/resolver" "github.com/fossas/fossa-cli/files" "github.com/fossas/fossa-cli/log" - "github.com/fossas/fossa-cli/monad" "github.com/pkg/errors" ) @@ -21,22 +20,25 @@ var ( func LockfileIn(dirname string) (resolver.Type, error) { log.Logger.Debugf("%#v", dirname) - either := monad.EitherStr{} - result := either. - Bind(findFile("godep", filepath.Join(dirname, "Godeps", "Godeps.json"))). - Bind(findFile("govendor", filepath.Join(dirname, "vendor", "vendor.json"))). - Bind(findFile("dep", filepath.Join(dirname, "Gopkg.toml"))). - Bind(findFile("vndr", filepath.Join(dirname, "vendor.conf"))). - Bind(findFile("glide", filepath.Join(dirname, "glide.yaml"))). - Bind(findFile("gdm", filepath.Join(dirname, "Godeps"))) - if result.Err != nil { - log.Logger.Debugf("Err: %#v", result.Err.Error()) - return "", result.Err + lockfiles := [][2]string{ + [2]string{"godep", filepath.Join(dirname, "Godeps", "Godeps.json")}, + [2]string{"govendor", filepath.Join(dirname, "vendor", "vendor.json")}, + [2]string{"dep", filepath.Join(dirname, "Gopkg.toml")}, + [2]string{"vndr", filepath.Join(dirname, "vendor.conf")}, + [2]string{"glide", filepath.Join(dirname, "glide.yaml")}, + [2]string{"gdm", filepath.Join(dirname, "Godeps")}, } - if result.Result == "" { - return "", ErrNoLockfileInDir + + for _, lockfile := range lockfiles { + ok, err := files.Exists(lockfile[1]) + if err != nil { + return "", err + } + if ok { + return resolver.Type(lockfile[0]), nil + } } - return resolver.Type(result.Result), nil + return "", ErrNoLockfileInDir } // NearestLockfile returns the type and directory of the nearest lockfile in an diff --git a/cli.go b/cli.go deleted file mode 100644 index 7f2d47e89d..0000000000 --- a/cli.go +++ /dev/null @@ -1,13 +0,0 @@ -// Package cli encompasses domain types for the CLI app. -package cli - -// VCS represents a type of version control system. -type VCS int - -const ( - _ VCS = iota - Subversion - Git - Mercurial - Bazaar -) diff --git a/files/files_test.go b/files/files_test.go new file mode 100644 index 0000000000..d6486f62ab --- /dev/null +++ b/files/files_test.go @@ -0,0 +1,16 @@ +package files_test + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/fossas/fossa-cli/files" +) + +func TestNonExistentParentIsNotErr(t *testing.T) { + ok, err := files.Exists(filepath.Join("testdata", "parent", "does", "not", "exist", "file")) + assert.NoError(t, err) + assert.False(t, ok) +} diff --git a/files/find.go b/files/find.go index c93fd8d8a7..a97263ad2a 100644 --- a/files/find.go +++ b/files/find.go @@ -3,11 +3,8 @@ package files import ( "errors" "path/filepath" - - "github.com/fossas/fossa-cli/monad" ) -// blaf var ( ErrDirNotFound = errors.New("no directory found during walk") ErrStopWalk = errors.New("WalkUp: stop") @@ -50,20 +47,3 @@ func WalkUp(startdir string, walker WalkUpFunc) (string, error) { } return "", ErrDirNotFound } - -// finder, bindFinder, and friends are EitherStr functions for finding whether -// one of many files exist. -type finder func(pathElems ...string) (bool, error) - -func BindFinder(name string, find finder, pathElems ...string) monad.EitherStrFunc { - return func(prev string) (string, error) { - ok, err := find(pathElems...) - if err != nil { - return "", err - } - if ok { - return name, nil - } - return prev, nil - } -} diff --git a/monad/monad.go b/monad/monad.go deleted file mode 100644 index 42dde8f691..0000000000 --- a/monad/monad.go +++ /dev/null @@ -1,54 +0,0 @@ -// Package monad implements common monomorphic monads. -package monad - -import "github.com/fossas/fossa-cli" - -// EitherStr is a monomorphic Either monad specialized to string. I miss Haskell. -type EitherStr struct { - Result string - Err error -} - -// EitherStrFunc defines monadic EitherStr functions. -type EitherStrFunc func(previous string) (string, error) - -// Bind lifts EitherStrFuncs into the EitherStr monad. -func (r *EitherStr) Bind(f EitherStrFunc) *EitherStr { - if r.Err != nil { - return r - } - - result, err := f(r.Result) - if err != nil { - r.Err = err - return r - } - - r.Result = result - return r -} - -// EitherVCS is an Either monad specialized to VCS. -type EitherVCS struct { - Result cli.VCS - Err error -} - -// EitherVCSFunc defines monadic EitherVCS functions. -type EitherVCSFunc func(previous cli.VCS) (cli.VCS, error) - -// BindVCS lifts EitherVCSFuncs into the EitherVCS monad. -func (r *EitherVCS) BindVCS(f EitherVCSFunc) *EitherVCS { - if r.Err != nil { - return r - } - - result, err := f(r.Result) - if err != nil { - r.Err = err - return r - } - - r.Result = result - return r -} diff --git a/vcs/find.go b/vcs/find.go deleted file mode 100644 index f4e4cc71f2..0000000000 --- a/vcs/find.go +++ /dev/null @@ -1,28 +0,0 @@ -package vcs - -import ( - "github.com/fossas/fossa-cli" - "github.com/fossas/fossa-cli/files" - "github.com/fossas/fossa-cli/monad" -) - -// vcsFinder, bindVCSFinder, and friends are EitherVCS functions for finding whether -// one of many files exist. -type vcsFinder func(pathElems ...string) (bool, error) - -func bindVCSFinder(tool cli.VCS, find vcsFinder, pathElems ...string) monad.EitherVCSFunc { - return func(prev cli.VCS) (cli.VCS, error) { - ok, err := find(pathElems...) - if err != nil { - return 0, err - } - if ok { - return tool, nil - } - return prev, nil - } -} - -func findVCSFolder(tool cli.VCS, pathElems ...string) monad.EitherVCSFunc { - return bindVCSFinder(tool, files.ExistsFolder, pathElems...) -} diff --git a/vcs/types.go b/vcs/types.go new file mode 100644 index 0000000000..64a5e67081 --- /dev/null +++ b/vcs/types.go @@ -0,0 +1,34 @@ +package vcs + +// VCS represents a type of version control system. +type VCS int + +const ( + _ VCS = iota + Subversion + Git + Mercurial + Bazaar +) + +var Types = [4]VCS{ + Subversion, + Git, + Mercurial, + Bazaar, +} + +func MetadataFolder(vcs VCS) string { + switch vcs { + case Subversion: + return ".svn" + case Git: + return ".git" + case Mercurial: + return ".hg" + case Bazaar: + return ".bzr" + default: + return "" + } +} diff --git a/vcs/vcs.go b/vcs/vcs.go index 390a705a17..7a31bb465c 100644 --- a/vcs/vcs.go +++ b/vcs/vcs.go @@ -6,10 +6,8 @@ import ( "errors" "path/filepath" - "github.com/fossas/fossa-cli" "github.com/fossas/fossa-cli/errutil" "github.com/fossas/fossa-cli/files" - "github.com/fossas/fossa-cli/monad" ) // Errors that occur when finding VCS repositories. @@ -20,26 +18,24 @@ var ( // VCSIn returns the type of VCS repository rooted at a directory, or // ErrNoVCSInDir if none is found. -func vcsIn(dirname string) (cli.VCS, error) { - either := monad.EitherVCS{} - result := either. - BindVCS(findVCSFolder(cli.Git, filepath.Join(dirname, ".git"))). - BindVCS(findVCSFolder(cli.Subversion, filepath.Join(dirname, ".svn"))). - BindVCS(findVCSFolder(cli.Mercurial, filepath.Join(dirname, ".hg"))). - BindVCS(findVCSFolder(cli.Bazaar, filepath.Join(dirname, ".bzr"))) - if result.Err != nil { - return 0, result.Err - } - if result.Result == 0 { - return 0, ErrNoVCSInDir +func vcsIn(dirname string) (VCS, error) { + for _, vcs := range Types { + ok, err := files.ExistsFolder(filepath.Join(dirname, MetadataFolder(vcs))) + if err != nil { + return 0, err + } + if ok { + return vcs, nil + } } - return result.Result, nil + return 0, ErrNoVCSInDir } // NearestVCS returns the type and directory of the nearest VCS repository // containing the directory, or ErrNoNearestVCS if none is found. -func NearestVCS(dirname string) (vcsType cli.VCS, vcsDir string, err error) { - vcsDir, err = files.WalkUp(dirname, func(d string) error { +func NearestVCS(dirname string) (VCS, string, error) { + var vcs VCS + dir, err := files.WalkUp(dirname, func(d string) error { tool, err := vcsIn(d) if err == ErrNoVCSInDir { return nil @@ -47,34 +43,34 @@ func NearestVCS(dirname string) (vcsType cli.VCS, vcsDir string, err error) { if err != nil { return err } - vcsType = tool + vcs = tool return files.ErrStopWalk }) if err == files.ErrDirNotFound { return 0, "", ErrNoNearestVCS } - return vcsType, vcsDir, err + return vcs, dir, err } // GetRepository returns the location of the repository containing dirname, // errutil.ErrRepositoryNotFound if none is found, or errutil.ErrNotImplemented // if an unsupported VCS is found. func GetRepository(dirname string) (string, error) { - vcsType, vcsDir, err := NearestVCS(dirname) + vcs, dir, err := NearestVCS(dirname) if err == ErrNoNearestVCS { return "", errutil.ErrRepositoryNotFound } if err != nil { return "", err } - switch vcsType { - case cli.Git: - return vcsDir, nil - case cli.Subversion: + switch vcs { + case Git: + return dir, nil + case Subversion: return "", errutil.ErrNotImplemented - case cli.Mercurial: + case Mercurial: return "", errutil.ErrNotImplemented - case cli.Bazaar: + case Bazaar: return "", errutil.ErrNotImplemented default: return "", errutil.ErrNotImplemented