Skip to content

Commit

Permalink
feat(v2): handle modules with replace directive
Browse files Browse the repository at this point in the history
  • Loading branch information
Bobgy committed Jan 23, 2022
1 parent 514ef23 commit b265450
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 16 deletions.
18 changes: 9 additions & 9 deletions licenses/library.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type Library struct {
// It may not be the complete set of all packages in the library.
Packages []string
// Parent go module.
Module *packages.Module
module *Module
}

// PackagesError aggregates all Packages[].Errors into a single error.
Expand Down Expand Up @@ -118,7 +118,7 @@ func Libraries(ctx context.Context, classifier Classifier, importPaths ...string
for _, p := range pkgs {
libraries = append(libraries, &Library{
Packages: []string{p.PkgPath},
Module: p.Module,
module: newModule(p.Module),
})
}
continue
Expand All @@ -128,15 +128,15 @@ func Libraries(ctx context.Context, classifier Classifier, importPaths ...string
}
for _, pkg := range pkgs {
lib.Packages = append(lib.Packages, pkg.PkgPath)
if lib.Module == nil {
if lib.module == nil {
// All the sub packages should belong to the same module.
lib.Module = pkg.Module
lib.module = newModule(pkg.Module)
}
if lib.Module != nil && lib.Module.Path != "" && lib.Module.Dir == "" {
if lib.module != nil && lib.module.Path != "" && lib.module.Dir == "" {
// A known cause is that the module is vendored, so some information is lost.
splits := strings.SplitN(lib.LicensePath, "/vendor/", 2)
if len(splits) != 2 {
glog.Warningf("module %s does not have dir and it's not vendored, cannot discover the license URL. Report to go-licenses developer if you see this.", lib.Module.Path)
glog.Warningf("module %s does not have dir and it's not vendored, cannot discover the license URL. Report to go-licenses developer if you see this.", lib.module.Path)
} else {
// This is vendored. Handle this known special case.
parentModDir := splits[0]
Expand All @@ -148,11 +148,11 @@ func Libraries(ctx context.Context, classifier Classifier, importPaths ...string
}
}
if parentPkg == nil {
glog.Warningf("cannot find parent package of vendored module %s", lib.Module.Path)
glog.Warningf("cannot find parent package of vendored module %s", lib.module.Path)
} else {
// Vendored modules should be commited in the parent module, so it counts as part of the
// parent module.
lib.Module = parentPkg.Module
lib.module = newModule(parentPkg.Module)
}
}
}
Expand Down Expand Up @@ -205,7 +205,7 @@ func (l *Library) FileURL(ctx context.Context, filePath string) (string, error)
wrap := func(err error) error {
return fmt.Errorf("getting file URL in library %s: %w", l.Name(), err)
}
m := l.Module
m := l.module
if m == nil {
return "", wrap(fmt.Errorf("empty go module info"))
}
Expand Down
11 changes: 5 additions & 6 deletions licenses/library_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"golang.org/x/tools/go/packages"
)

func TestLibraries(t *testing.T) {
Expand Down Expand Up @@ -155,7 +154,7 @@ func TestLibraryFileURL(t *testing.T) {
"github.com/google/trillian/crypto",
},
LicensePath: "/go/src/github.com/google/trillian/LICENSE",
Module: &packages.Module{
module: &Module{
Path: "github.com/google/trillian",
Dir: "/go/src/github.com/google/trillian",
Version: "v1.2.3",
Expand All @@ -172,7 +171,7 @@ func TestLibraryFileURL(t *testing.T) {
"bitbucket.org/user/project/pkg2",
},
LicensePath: "/foo/bar/bitbucket.org/user/project/LICENSE",
Module: &packages.Module{
module: &Module{
Path: "bitbucket.org/user/project",
Dir: "/foo/bar/bitbucket.org/user/project",
Version: "v1.2.3",
Expand All @@ -189,7 +188,7 @@ func TestLibraryFileURL(t *testing.T) {
"example.com/user/project/pkg2",
},
LicensePath: "/foo/bar/example.com/user/project/LICENSE",
Module: &packages.Module{
module: &Module{
Path: "example.com/user/project",
Dir: "/foo/bar/example.com/user/project",
Version: "v1.2.3",
Expand All @@ -206,7 +205,7 @@ func TestLibraryFileURL(t *testing.T) {
"github.com/google/trillian/crypto",
},
LicensePath: "/go/src/github.com/google/trillian/LICENSE",
Module: &packages.Module{
module: &Module{
Path: "github.com/google/trillian",
Dir: "/go/src/github.com/google/trillian",
},
Expand All @@ -221,7 +220,7 @@ func TestLibraryFileURL(t *testing.T) {
"k8s.io/api/core/v1",
},
LicensePath: "/go/modcache/k8s.io/api/LICENSE",
Module: &packages.Module{
module: &Module{
Path: "k8s.io/api",
Dir: "/go/modcache/k8s.io/api",
Version: "v0.23.1",
Expand Down
69 changes: 69 additions & 0 deletions licenses/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2022 Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package licenses

import (
"strings"

"golang.org/x/tools/go/packages"
)

// Module provides module information for a package.
type Module struct {
// Differences from packages.Module:
// * Replace field is removed, it's only an implementation detail in this package.
// If a module is replaced, we'll directly return the replaced module.
// * Version field +incompatible suffix is trimmed.
// * Main, ModuleError, Time, Indirect, GoMod, GoVersion fields are removed, because they are not used.
Path string // module path
Version string // module version
Dir string // directory holding files for this module, if any
}

func newModule(mod *packages.Module) *Module {
if mod == nil {
return nil
}
// Example of a module with replace directive: k8s.io/kubernetes => k8s.io/kubernetes v1.11.1
// {
// "Path": "k8s.io/kubernetes",
// "Version": "v0.17.9",
// "Replace": {
// "Path": "k8s.io/kubernetes",
// "Version": "v1.11.1",
// "Time": "2018-07-17T04:20:29Z",
// "Dir": "/home/gongyuan_kubeflow_org/go/pkg/mod/k8s.io/[email protected]",
// "GoMod": "/home/gongyuan_kubeflow_org/go/pkg/mod/cache/download/k8s.io/kubernetes/@v/v1.11.1.mod"
// },
// "Dir": "/home/gongyuan_kubeflow_org/go/pkg/mod/k8s.io/[email protected]",
// "GoMod": "/home/gongyuan_kubeflow_org/go/pkg/mod/cache/download/k8s.io/kubernetes/@v/v1.11.1.mod"
// }
// handle replace directives
// Note, we specifically want to replace version field.
// Haven't confirmed, but we may also need to override the
// entire struct when using replace directive with local folders.
tmp := *mod
if tmp.Replace != nil {
tmp = *tmp.Replace
}
// The +incompatible suffix does not affect module version.
// ref: https://golang.org/ref/mod#incompatible-versions
tmp.Version = strings.TrimSuffix(tmp.Version, "+incompatible")
return &Module{
Path: tmp.Path,
Version: tmp.Version,
Dir: tmp.Dir,
}
}
2 changes: 1 addition & 1 deletion testdata/modules/replace04/licenses.csv
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github.com/google/go-licenses/testdata/modules/replace04, https://github.com/google/go-licenses/blob/HEAD/testdata/modules/replace04/LICENSE, Apache-2.0
github.com/mitchellh/go-homedir, https://github.com/mitchellh/go-homedir/blob/v1.1.0/LICENSE, MIT
github.com/mitchellh/go-homedir, https://github.com/mitchellh/go-homedir/blob/v1.0.0/LICENSE, MIT

0 comments on commit b265450

Please sign in to comment.