From 3dcdcb6994c4de42a73bd2e4790178be3ed4554b Mon Sep 17 00:00:00 2001 From: Cody Oss <6331106+codyoss@users.noreply.github.com> Date: Mon, 20 Jan 2020 12:21:39 -0700 Subject: [PATCH] fix not resolving go module major versions (#385) This change now makes use of go list to check for package names. This tool is module aware and allows for better named imports. To test this change I needed to also add a small package to our mod file. To keep this import from disappearing from go.mod I made use of the tools file strategy. Note this change will change the import names in generated code. This should not be a breaking change in user code. Fixes #326 --- go.mod | 5 +++- go.sum | 6 ++++ .../greeter/greeter_mock_test.go | 6 ++-- .../tests/import_source/source_mock.go | 4 +-- mockgen/mockgen.go | 25 ++++++++++++++++- mockgen/mockgen_test.go | 28 +++++++++++++++++++ mockgen/parse.go | 6 ++-- sample/mock_user/mock_user.go | 4 +-- tools.go | 22 +++++++++++++++ 9 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 tools.go diff --git a/go.mod b/go.mod index a675ec40..edfb6d40 100644 --- a/go.mod +++ b/go.mod @@ -1,5 +1,8 @@ module github.com/golang/mock -require golang.org/x/tools v0.0.0-20190425150028-36563e24a262 +require ( + golang.org/x/tools v0.0.0-20190425150028-36563e24a262 + rsc.io/quote/v3 v3.1.0 +) go 1.11 diff --git a/go.sum b/go.sum index 9009852e..21dbce53 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,12 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190425150028-36563e24a262 h1:qsl9y/CJx34tuA7QCPNp86JNJe4spst6Ff8MjvPUdPg= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/mockgen/internal/tests/custom_package_name/greeter/greeter_mock_test.go b/mockgen/internal/tests/custom_package_name/greeter/greeter_mock_test.go index 0885f3d5..41277d51 100644 --- a/mockgen/internal/tests/custom_package_name/greeter/greeter_mock_test.go +++ b/mockgen/internal/tests/custom_package_name/greeter/greeter_mock_test.go @@ -6,7 +6,7 @@ package greeter import ( gomock "github.com/golang/mock/gomock" - v1 "github.com/golang/mock/mockgen/internal/tests/custom_package_name/client/v1" + client "github.com/golang/mock/mockgen/internal/tests/custom_package_name/client/v1" reflect "reflect" ) @@ -34,10 +34,10 @@ func (m *MockInputMaker) EXPECT() *MockInputMakerMockRecorder { } // MakeInput mocks base method -func (m *MockInputMaker) MakeInput() v1.GreetInput { +func (m *MockInputMaker) MakeInput() client.GreetInput { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "MakeInput") - ret0, _ := ret[0].(v1.GreetInput) + ret0, _ := ret[0].(client.GreetInput) return ret0 } diff --git a/mockgen/internal/tests/import_source/source_mock.go b/mockgen/internal/tests/import_source/source_mock.go index d7c47692..847112d2 100644 --- a/mockgen/internal/tests/import_source/source_mock.go +++ b/mockgen/internal/tests/import_source/source_mock.go @@ -6,7 +6,7 @@ package mock_source import ( gomock "github.com/golang/mock/gomock" - definition "github.com/golang/mock/mockgen/internal/tests/import_source/definition" + source "github.com/golang/mock/mockgen/internal/tests/import_source/definition" reflect "reflect" ) @@ -34,7 +34,7 @@ func (m *MockS) EXPECT() *MockSMockRecorder { } // F mocks base method -func (m *MockS) F(arg0 definition.X) { +func (m *MockS) F(arg0 source.X) { m.ctrl.T.Helper() m.ctrl.Call(m, "F", arg0) } diff --git a/mockgen/mockgen.go b/mockgen/mockgen.go index b02aaf46..1f14aa7c 100644 --- a/mockgen/mockgen.go +++ b/mockgen/mockgen.go @@ -20,6 +20,7 @@ package main import ( "bytes" + "encoding/json" "flag" "fmt" "go/build" @@ -29,6 +30,7 @@ import ( "io/ioutil" "log" "os" + "os/exec" "path" "path/filepath" "sort" @@ -287,7 +289,10 @@ func (g *generator) Generate(pkg *model.Package, outputPkgName string, outputPac g.packageMap = make(map[string]string, len(im)) localNames := make(map[string]bool, len(im)) for _, pth := range sortedPaths { - base := sanitize(path.Base(pth)) + base, ok := lookupPackageName(pth) + if !ok { + base = sanitize(path.Base(pth)) + } // Local names for an imported package can usually be the basename of the import path. // A couple of situations don't permit that, such as duplicate local names @@ -598,3 +603,21 @@ func (g *generator) Output() []byte { } return src } + +func lookupPackageName(importPath string) (string, bool) { + var pkg struct { + Name string + } + b := bytes.NewBuffer(nil) + cmd := exec.Command("go", "list", "-json", importPath) + cmd.Stdout = b + err := cmd.Run() + if err != nil { + return "", false + } + err = json.Unmarshal(b.Bytes(), &pkg) + if err != nil { + return "", false + } + return pkg.Name, true +} diff --git a/mockgen/mockgen_test.go b/mockgen/mockgen_test.go index 1c139d70..130d3cf4 100644 --- a/mockgen/mockgen_test.go +++ b/mockgen/mockgen_test.go @@ -334,3 +334,31 @@ func TestGetArgNames(t *testing.T) { }) } } + +func Test_lookupPackageName(t *testing.T) { + type args struct { + importPath string + } + tests := []struct { + name string + importPath string + wantPackageName string + wantOK bool + }{ + {"golang package", "context", "context", true}, + {"third party", "golang.org/x/tools/present", "present", true}, + {"modules", "rsc.io/quote/v3", "quote", true}, + {"fail", "this/should/not/work", "", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotPackageName, gotOk := lookupPackageName(tt.importPath) + if gotPackageName != tt.wantPackageName { + t.Errorf("lookupPackageName() gotPackageName = %v, wantPackageName %v", gotPackageName, tt.wantPackageName) + } + if gotOk != tt.wantOK { + t.Errorf("lookupPackageName() gotOk = %v, wantOK %v", gotOk, tt.wantOK) + } + }) + } +} diff --git a/mockgen/parse.go b/mockgen/parse.go index e35d16f5..2fdda65e 100644 --- a/mockgen/parse.go +++ b/mockgen/parse.go @@ -453,15 +453,15 @@ func importsOfFile(file *ast.File) (normalImports map[string]string, dotImports } pkgName = is.Name.Name } else { - pkg, err := build.Import(importPath, "", 0) - if err != nil { + pkg, ok := lookupPackageName(importPath) + if !ok { // Fallback to import path suffix. Note that this is uncertain. _, last := path.Split(importPath) // If the last path component has dots, the first dot-delimited // field is used as the name. pkgName = strings.SplitN(last, ".", 2)[0] } else { - pkgName = pkg.Name + pkgName = pkg } } diff --git a/sample/mock_user/mock_user.go b/sample/mock_user/mock_user.go index 4cf24bb7..34fec0d9 100644 --- a/sample/mock_user/mock_user.go +++ b/sample/mock_user/mock_user.go @@ -11,7 +11,7 @@ import ( imp1 "github.com/golang/mock/sample/imp1" imp2 "github.com/golang/mock/sample/imp2" imp3 "github.com/golang/mock/sample/imp3" - imp4 "github.com/golang/mock/sample/imp4" + imp_four "github.com/golang/mock/sample/imp4" hash "hash" template "html/template" io "io" @@ -115,7 +115,7 @@ func (mr *MockIndexMockRecorder) EllipOnly(arg0 ...interface{}) *gomock.Call { } // ForeignFour mocks base method -func (m *MockIndex) ForeignFour(arg0 imp4.Imp4) { +func (m *MockIndex) ForeignFour(arg0 imp_four.Imp4) { m.ctrl.T.Helper() m.ctrl.Call(m, "ForeignFour", arg0) } diff --git a/tools.go b/tools.go new file mode 100644 index 00000000..c1ea6236 --- /dev/null +++ b/tools.go @@ -0,0 +1,22 @@ +// +build tools + +// Copyright 2020 Google Inc. +// +// 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 mock + +// These imports are included here so they don't disappear from go.mod file. +import ( + _ "rsc.io/quote/v3" +)