diff --git a/v2/csv.go b/v2/csv.go index 2dc13c8..9b92849 100644 --- a/v2/csv.go +++ b/v2/csv.go @@ -18,7 +18,6 @@ import ( "context" "encoding/csv" "os" - "strings" "github.com/golang/glog" "github.com/google/go-licenses/v2/licenses" @@ -56,41 +55,12 @@ func csvMain(_ *cobra.Command, args []string) error { } for _, lib := range libs { licenseURL := "Unknown" - licenseName := "Unknown" - if lib.LicensePath != "" { - // Find a URL for the license file, based on the URL of a remote for the Git repository. - var errs []string - repo, err := licenses.FindGitRepo(lib.LicensePath) - if err != nil { - // Can't find Git repo (possibly a Go Module?) - derive URL from lib name instead. - lURL, err := lib.FileURL(lib.LicensePath) - if err != nil { - errs = append(errs, err.Error()) - } else { - licenseURL = lURL.String() - } - } else { - for _, remote := range gitRemotes { - url, err := repo.FileURL(lib.LicensePath, remote) - if err != nil { - errs = append(errs, err.Error()) - continue - } - licenseURL = url.String() - break - } - } - if licenseURL == "Unknown" { - glog.Errorf("Error discovering URL for %q:\n- %s", lib.LicensePath, strings.Join(errs, "\n- ")) - } - licenseName, _, err = classifier.Identify(lib.LicensePath) - if err != nil { - glog.Errorf("Error identifying license in %q: %v", lib.LicensePath, err) - licenseName = "Unknown" - } + licenseName, _, err := classifier.Identify(lib.LicensePath) + if err != nil { + glog.Errorf("Error identifying license in %q: %v", lib.LicensePath, err) + licenseName = "Unknown" } - // Remove the "*/vendor/" prefix from the library name for conciseness. - if err := writer.Write([]string{unvendor(lib.Name()), licenseURL, licenseName}); err != nil { + if err := writer.Write([]string{lib.Name(), licenseURL, licenseName}); err != nil { return err } } diff --git a/v2/licenses/find.go b/v2/licenses/find.go index 6bef1cf..269f545 100644 --- a/v2/licenses/find.go +++ b/v2/licenses/find.go @@ -16,30 +16,34 @@ package licenses import ( "fmt" - "go/build" "io/ioutil" "path/filepath" "regexp" + "strings" ) var ( licenseRegexp = regexp.MustCompile(`^(?i)(LICEN(S|C)E|COPYING|README|NOTICE).*$`) - srcDirRegexps = func() []*regexp.Regexp { - var rs []*regexp.Regexp - for _, s := range build.Default.SrcDirs() { - rs = append(rs, regexp.MustCompile("^"+regexp.QuoteMeta(s)+"$")) - } - return rs - }() - vendorRegexp = regexp.MustCompile(`.+/vendor(/)?$`) ) // Find returns the file path of the license for this package. -func Find(dir string, classifier Classifier) (string, error) { - var stopAt []*regexp.Regexp - stopAt = append(stopAt, srcDirRegexps...) - stopAt = append(stopAt, vendorRegexp) - return findUpwards(dir, licenseRegexp, stopAt, func(path string) bool { +// +// dir is path of the directory where we want to find a license. +// rootDir is path of the module containing this package. Find will not search out of the +// rootDir. +func Find(dir string, rootDir string, classifier Classifier) (string, error) { + dir, err := filepath.Abs(dir) + if err != nil { + return "", err + } + rootDir, err = filepath.Abs(rootDir) + if err != nil { + return "", err + } + if !strings.HasPrefix(dir, rootDir) { + return "", fmt.Errorf("licenses.Find: rootDir %s should contain dir %s", rootDir, dir) + } + return findUpwards(dir, licenseRegexp, rootDir, func(path string) bool { // TODO(RJPercival): Return license details if _, _, err := classifier.Identify(path); err != nil { return false @@ -48,15 +52,15 @@ func Find(dir string, classifier Classifier) (string, error) { }) } -func findUpwards(dir string, r *regexp.Regexp, stopAt []*regexp.Regexp, predicate func(path string) bool) (string, error) { +func findUpwards(dir string, r *regexp.Regexp, stopAt string, predicate func(path string) bool) (string, error) { // Dir must be made absolute for reliable matching with stopAt regexps dir, err := filepath.Abs(dir) if err != nil { return "", err } start := dir - // Stop once dir matches a stopAt regexp or dir is the filesystem root - for !matchAny(stopAt, dir) { + // Stop once we go out of the stopAt dir. + for strings.HasPrefix(dir, stopAt) { dirContents, err := ioutil.ReadDir(dir) if err != nil { return "", err @@ -79,12 +83,3 @@ func findUpwards(dir string, r *regexp.Regexp, stopAt []*regexp.Regexp, predicat } return "", fmt.Errorf("no file/directory matching regexp %q found for %s", r, start) } - -func matchAny(patterns []*regexp.Regexp, s string) bool { - for _, p := range patterns { - if p.MatchString(s) { - return true - } - } - return false -} diff --git a/v2/licenses/git.go b/v2/licenses/git.go index e3c619e..f647c40 100644 --- a/v2/licenses/git.go +++ b/v2/licenses/git.go @@ -46,11 +46,12 @@ type GitRepo struct { // FindGitRepo finds the Git repository that contains the specified filePath // by searching upwards through the directory tree for a ".git" directory. func FindGitRepo(filePath string) (*GitRepo, error) { - path, err := findUpwards(filepath.Dir(filePath), gitRegexp, srcDirRegexps, nil) - if err != nil { - return nil, err - } - return &GitRepo{dotGitPath: path}, nil + return nil, nil + // path, err := findUpwards(filepath.Dir(filePath), gitRegexp, srcDirRegexps, nil) + // if err != nil { + // return nil, err + // } + // return &GitRepo{dotGitPath: path}, nil } // FileURL returns the URL of a file stored in a Git repository. diff --git a/v2/licenses/library.go b/v2/licenses/library.go index 1ac665b..24b2e2f 100644 --- a/v2/licenses/library.go +++ b/v2/licenses/library.go @@ -68,7 +68,7 @@ func (e PackagesError) Error() string { func Libraries(ctx context.Context, classifier Classifier, importPaths ...string) ([]*Library, error) { cfg := &packages.Config{ Context: ctx, - Mode: packages.NeedImports | packages.NeedDeps | packages.NeedFiles | packages.NeedName, + Mode: packages.NeedImports | packages.NeedDeps | packages.NeedFiles | packages.NeedName | packages.NeedModule, } rootPkgs, err := packages.Load(cfg, importPaths...) @@ -103,7 +103,7 @@ func Libraries(ctx context.Context, classifier Classifier, importPaths ...string // This package is empty - nothing to do. return true } - licensePath, err := Find(pkgDir, classifier) + licensePath, err := Find(pkgDir, p.Module.Dir, classifier) if err != nil { glog.Errorf("Failed to find license for %s: %v", p.PkgPath, err) } @@ -202,6 +202,10 @@ func (l *Library) FileURL(filePath string) (*url.URL, error) { // isStdLib returns true if this package is part of the Go standard library. func isStdLib(pkg *packages.Package) bool { + if pkg.Name == "unsafe" { + // Special case unsafe stdlib, because it does not contain go files. + return true + } if len(pkg.GoFiles) == 0 { return false } diff --git a/v2/third_party/licenses.csv b/v2/third_party/licenses.csv index 4aaedd7..3c64f5b 100644 --- a/v2/third_party/licenses.csv +++ b/v2/third_party/licenses.csv @@ -1,17 +1,18 @@ -github.com/emirpasic/gods,https://github.com/emirpasic/gods/blob/master/LICENSE,BSD-2-Clause -github.com/golang/glog,https://github.com/golang/glog/blob/master/LICENSE,Apache-2.0 -github.com/google/go-licenses/v2,Unknown,Apache-2.0 -github.com/google/licenseclassifier,https://github.com/google/licenseclassifier/blob/master/LICENSE,Apache-2.0 -github.com/google/licenseclassifier/stringclassifier,https://github.com/google/licenseclassifier/blob/master/stringclassifier/LICENSE,Apache-2.0 -github.com/jbenet/go-context/io,https://github.com/jbenet/go-context/blob/master/io/LICENSE,MIT -github.com/kevinburke/ssh_config,https://github.com/kevinburke/ssh_config/blob/master/LICENSE,MIT -github.com/mitchellh/go-homedir,https://github.com/mitchellh/go-homedir/blob/master/LICENSE,MIT -github.com/otiai10/copy,https://github.com/otiai10/copy/blob/master/LICENSE,MIT -github.com/sergi/go-diff/diffmatchpatch,https://github.com/sergi/go-diff/blob/master/diffmatchpatch/LICENSE,MIT -github.com/spf13/cobra,https://github.com/spf13/cobra/blob/master/LICENSE.txt,Apache-2.0 -github.com/spf13/pflag,https://github.com/spf13/pflag/blob/master/LICENSE,BSD-3-Clause -github.com/src-d/gcfg,https://github.com/src-d/gcfg/blob/master/LICENSE,BSD-3-Clause -github.com/xanzy/ssh-agent,https://github.com/xanzy/ssh-agent/blob/master/LICENSE,Apache-2.0 +github.com/emirpasic/gods,Unknown,BSD-2-Clause +github.com/golang/glog,Unknown,Apache-2.0 +github.com/google/go-licenses/v2,Unknown, +github.com/google/go-licenses/v2/licenses,Unknown, +github.com/google/licenseclassifier,Unknown,Apache-2.0 +github.com/google/licenseclassifier/stringclassifier,Unknown,Apache-2.0 +github.com/jbenet/go-context/io,Unknown,MIT +github.com/kevinburke/ssh_config,Unknown,MIT +github.com/mitchellh/go-homedir,Unknown,MIT +github.com/otiai10/copy,Unknown,MIT +github.com/sergi/go-diff/diffmatchpatch,Unknown,MIT +github.com/spf13/cobra,Unknown,Apache-2.0 +github.com/spf13/pflag,Unknown,BSD-3-Clause +github.com/src-d/gcfg,Unknown,BSD-3-Clause +github.com/xanzy/ssh-agent,Unknown,Apache-2.0 golang.org/x/crypto,Unknown,BSD-3-Clause golang.org/x/mod/semver,Unknown,BSD-3-Clause golang.org/x/net,Unknown,BSD-3-Clause