🌐 AI搜索 & 代理 主页
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
diff --git a/go.mod b/go.mod
index a675ec4..edfb6d4 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 9009852..21dbce5 100644
--- a/go.sum
+++ b/go.sum
@@ -2,6 +2,12 @@
 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 0885f3d..41277d5 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 @@
 
 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 @@
 }
 
 // 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 d7c4769..847112d 100644
--- a/mockgen/internal/tests/import_source/source_mock.go
+++ b/mockgen/internal/tests/import_source/source_mock.go
@@ -6,7 +6,7 @@
 
 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 @@
 }
 
 // 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 b02aaf4..1f14aa7 100644
--- a/mockgen/mockgen.go
+++ b/mockgen/mockgen.go
@@ -20,6 +20,7 @@
 
 import (
 	"bytes"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"go/build"
@@ -29,6 +30,7 @@
 	"io/ioutil"
 	"log"
 	"os"
+	"os/exec"
 	"path"
 	"path/filepath"
 	"sort"
@@ -287,7 +289,10 @@
 	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 @@
 	}
 	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 1c139d7..130d3cf 100644
--- a/mockgen/mockgen_test.go
+++ b/mockgen/mockgen_test.go
@@ -334,3 +334,31 @@
 		})
 	}
 }
+
+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 e35d16f..2fdda65 100644
--- a/mockgen/parse.go
+++ b/mockgen/parse.go
@@ -453,15 +453,15 @@
 			}
 			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 4cf24bb..34fec0d 100644
--- a/sample/mock_user/mock_user.go
+++ b/sample/mock_user/mock_user.go
@@ -11,7 +11,7 @@
 	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 @@
 }
 
 // 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 0000000..c1ea623
--- /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"
+)