@@ -15,29 +15,41 @@ import (
15
15
"golang.org/x/tools/refactor/importgraph"
16
16
)
17
17
18
- func get ( gopath , repo string ) error {
18
+ func clone ( srcdir , repo string ) ( string , error ) {
19
19
done := make (chan struct {})
20
20
defer close (done )
21
- go progressSize ("go get" , filepath .Join (gopath , "src" ), done )
22
-
23
- // As per https://groups.google.com/forum/#!topic/golang-nuts/N5apfenE4m4,
24
- // the arguments to “go get” are packages, not repositories. Hence, we
25
- // specify “gopkg/...” in order to cover all packages.
26
- // As a concrete example, github.com/jacobsa/util is a repository we want
27
- // to package into a single Debian package, and using “go get -d
28
- // github.com/jacobsa/util” fails because there are no buildable go files
29
- // in the top level of that repository.
30
- cmd := exec .Command ("go" , "get" , "-d" , "-t" , repo + "/..." )
21
+ go progressSize ("vcs clone" , srcdir , done )
22
+
23
+ // Get the sources of the module in a temporary dir to be able to run
24
+ // go get in module mode, as the gopath mode has been removed in latest
25
+ // version of Go.
26
+ rr , err := vcs .RepoRootForImportPath (repo , false )
27
+ if err != nil {
28
+ return "" , fmt .Errorf ("get repo root: %w" , err )
29
+ }
30
+ dir := filepath .Join (srcdir , rr .Root )
31
+ // Run "git clone {repo} {dir}" (or the equivalent command for hg, svn, bzr)
32
+ return dir , rr .VCS .Create (dir , rr .Repo )
33
+ }
34
+
35
+ func get (gopath , repodir , repo string ) error {
36
+ done := make (chan struct {})
37
+ defer close (done )
38
+ go progressSize ("go get" , repodir , done )
39
+
40
+ // Run go get without arguments directly in the module directory to
41
+ // download all its dependencies (with -t to include the test dependencies).
42
+ cmd := exec .Command ("go" , "get" , "-t" )
43
+ cmd .Dir = repodir
31
44
cmd .Stderr = os .Stderr
32
45
cmd .Env = append ([]string {
33
- "GO111MODULE=off" ,
34
46
"GOPATH=" + gopath ,
35
47
}, passthroughEnv ()... )
36
48
return cmd .Run ()
37
49
}
38
50
39
51
func removeVendor (gopath string ) (found bool , _ error ) {
40
- err := filepath .Walk (filepath . Join ( gopath , "src" ) , func (path string , info os.FileInfo , err error ) error {
52
+ err := filepath .Walk (gopath , func (path string , info os.FileInfo , err error ) error {
41
53
if err != nil {
42
54
return err
43
55
}
@@ -56,6 +68,13 @@ func removeVendor(gopath string) (found bool, _ error) {
56
68
return found , err
57
69
}
58
70
71
+ func isFile (path string ) bool {
72
+ if info , err := os .Stat (path ); err == nil {
73
+ return ! info .IsDir ()
74
+ }
75
+ return false
76
+ }
77
+
59
78
func estimate (importpath string ) error {
60
79
// construct a separate GOPATH in a temporary directory
61
80
gopath , err := os .MkdirTemp ("" , "dh-make-golang" )
@@ -64,18 +83,33 @@ func estimate(importpath string) error {
64
83
}
65
84
defer os .RemoveAll (gopath )
66
85
67
- if err := get (gopath , importpath ); err != nil {
86
+ // clone the repo inside the src directory of the GOPATH
87
+ // and init a Go module if it is not yet one.
88
+ srcdir := filepath .Join (gopath , "src" )
89
+ repodir , err := clone (srcdir , importpath )
90
+ if err != nil {
91
+ return fmt .Errorf ("vcs clone: %w" , err )
92
+ }
93
+ if ! isFile (filepath .Join (repodir , "go.mod" )) {
94
+ cmd := exec .Command ("go" , "mod" , "init" , importpath )
95
+ cmd .Dir = repodir
96
+ if err := cmd .Run (); err != nil {
97
+ return fmt .Errorf ("go mod init: %w" , err )
98
+ }
99
+ }
100
+
101
+ if err := get (gopath , repodir , importpath ); err != nil {
68
102
return fmt .Errorf ("go get: %w" , err )
69
103
}
70
104
71
- found , err := removeVendor (gopath )
105
+ found , err := removeVendor (repodir )
72
106
if err != nil {
73
107
return fmt .Errorf ("remove vendor: %w" , err )
74
108
}
75
109
76
110
if found {
77
111
// Fetch un-vendored dependencies
78
- if err := get (gopath , importpath ); err != nil {
112
+ if err := get (gopath , repodir , importpath ); err != nil {
79
113
return fmt .Errorf ("fetch un-vendored: go get: %w" , err )
80
114
}
81
115
}
@@ -84,7 +118,6 @@ func estimate(importpath string) error {
84
118
cmd := exec .Command ("go" , "list" , "std" )
85
119
cmd .Stderr = os .Stderr
86
120
cmd .Env = append ([]string {
87
- "GO111MODULE=off" ,
88
121
"GOPATH=" + gopath ,
89
122
}, passthroughEnv ()... )
90
123
@@ -106,13 +139,21 @@ func estimate(importpath string) error {
106
139
}
107
140
108
141
build .Default .GOPATH = gopath
142
+ build .Default .Dir = repodir
109
143
forward , _ , errors := importgraph .Build (& build .Default )
110
- if len (errors ) > 0 {
111
- lines := make ([]string , 0 , len (errors ))
112
- for importPath , err := range errors {
113
- lines = append (lines , fmt .Sprintf ("%s: %v" , importPath , err ))
144
+ errLines := make ([]string , 0 , len (errors ))
145
+ for importPath , err := range errors {
146
+ // For an unknown reason, parent directories and subpackages
147
+ // of the current module report an error about not being able
148
+ // to import them. We can safely ignore them.
149
+ isSubpackage := strings .HasPrefix (importPath , importpath + "/" )
150
+ isParentDir := strings .HasPrefix (importpath , importPath + "/" )
151
+ if ! isSubpackage && ! isParentDir && importPath != importPath {
152
+ errLines = append (errLines , fmt .Sprintf ("%s: %v" , importPath , err ))
114
153
}
115
- return fmt .Errorf ("could not load packages: %v" , strings .Join (lines , "\n " ))
154
+ }
155
+ if len (errLines ) > 0 {
156
+ return fmt .Errorf ("could not load packages: %v" , strings .Join (errLines , "\n " ))
116
157
}
117
158
118
159
var lines []string
0 commit comments