Skip to content

Commit

Permalink
cmd: fail go mod vendor on case-insensitive import collisions
Browse files Browse the repository at this point in the history
The existing implementation of go mod vendor allows having
case-insensitive imports, which will anyway fail during go build.
This improvement validates such collisions during go mod vendor command.

Fixes golang#38571
  • Loading branch information
anton-kuklin committed Sep 27, 2020
1 parent 72a9dec commit dc34f68
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 1 deletion.
19 changes: 19 additions & 0 deletions src/cmd/go/internal/modcmd/vendor.go
Expand Up @@ -19,6 +19,7 @@ import (
"cmd/go/internal/cfg"
"cmd/go/internal/imports"
"cmd/go/internal/modload"
"cmd/go/internal/str"

"golang.org/x/mod/module"
"golang.org/x/mod/semver"
Expand Down Expand Up @@ -64,6 +65,8 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
}
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")

checkCaseInsensitivePathsDuplications(modload.LoadBuildList())

vdir := filepath.Join(modload.ModRoot(), "vendor")
if err := os.RemoveAll(vdir); err != nil {
base.Fatalf("go mod vendor: %v", err)
Expand Down Expand Up @@ -298,3 +301,19 @@ func copyDir(dst, src string, match func(dir string, info os.FileInfo) bool) {
}
}
}

// checkCaseInsensitivePathsDuplications verifies that given paths have
// no case-insensitive duplications.
//
// (See https://golang.org/issue/38571).
func checkCaseInsensitivePathsDuplications(mods []module.Version) {
paths := make(map[string]string, len(mods))
for _, mod := range mods {
fold := str.ToFold(mod.Path)
if other := paths[fold]; other == "" {
paths[fold] = mod.Path
} else if other != mod.Path {
base.Fatalf("go mod vendor: case-insensitive module path collision: %s and %s", other, mod.Path)
}
}
}
2 changes: 1 addition & 1 deletion src/cmd/go/internal/str/str.go
Expand Up @@ -30,7 +30,7 @@ func StringList(args ...interface{}) []string {
}

// ToFold returns a string with the property that
// strings.EqualFold(s, t) iff ToFold(s) == ToFold(t)
// strings.EqualFold(s, t) if ToFold(s) == ToFold(t)
// This lets us test a large set of strings for fold-equivalent
// duplicates without making a quadratic number of calls
// to EqualFold. Note that strings.ToUpper and strings.ToLower
Expand Down
33 changes: 33 additions & 0 deletions src/cmd/go/testdata/script/mod_vendor_case_insensitive.txt
@@ -0,0 +1,33 @@
# Tests issue #38571
# Tests that go mod vendor fails on case-insensitive import collision.

env GO111MODULE=on

! go mod vendor
stderr 'case-insensitive module path collision'

-- go.mod --
module m

go 1.14

require (
example.com/foo v0.1.0
example.com/Foo v0.1.0
)

replace (
example.com/foo => ./foo
example.com/Foo => ./!foo
)
-- foo/go.mod --
module example.com/foo

-- foo/foo.go --
package foo

-- !foo/go.mod --
module example.com/Foo

-- !foo/foo.go --
package Foo

0 comments on commit dc34f68

Please sign in to comment.