@@ -3,12 +3,13 @@ package interp
3
3
import (
4
4
"fmt"
5
5
"io/fs"
6
- "os"
7
6
"path/filepath"
8
7
"strings"
8
+
9
+ "golang.org/x/tools/go/packages"
9
10
)
10
11
11
- // importSrc calls gta on the source code for the package identified by
12
+ // importSrc calls global tag analysis on the source code for the package identified by
12
13
// importPath. rPath is the relative path to the directory containing the source
13
14
// code for the package. It can also be "main" as a special value.
14
15
func (interp * Interpreter ) importSrc (rPath , importPath string , skipTest bool ) (string , error ) {
@@ -23,24 +24,9 @@ func (interp *Interpreter) importSrc(rPath, importPath string, skipTest bool) (s
23
24
return name , nil
24
25
}
25
26
26
- // For relative import paths in the form "./xxx" or "../xxx", the initial
27
- // base path is the directory of the interpreter input file, or "." if no file
28
- // was provided.
29
- // In all other cases, absolute import paths are resolved from the GOPATH
30
- // and the nested "vendor" directories.
31
- if isPathRelative (importPath ) {
32
- if rPath == mainID {
33
- rPath = "."
34
- }
35
- dir = filepath .Join (filepath .Dir (interp .name ), rPath , importPath )
36
- } else if dir , rPath , err = interp .pkgDir (interp .context .GOPATH , rPath , importPath ); err != nil {
37
- // Try again, assuming a root dir at the source location.
38
- if rPath , err = interp .rootFromSourceLocation (); err != nil {
39
- return "" , err
40
- }
41
- if dir , rPath , err = interp .pkgDir (interp .context .GOPATH , rPath , importPath ); err != nil {
42
- return "" , err
43
- }
27
+ // resolve relative and absolute import paths.
28
+ if dir , err = interp .getPackageDir (importPath ); err != nil {
29
+ return "" , err
44
30
}
45
31
46
32
if interp .rdir [importPath ] {
@@ -171,119 +157,39 @@ func (interp *Interpreter) importSrc(rPath, importPath string, skipTest bool) (s
171
157
return pkgName , nil
172
158
}
173
159
174
- // rootFromSourceLocation returns the path to the directory containing the input
175
- // Go file given to the interpreter, relative to $GOPATH/src.
176
- // It is meant to be called in the case when the initial input is a main package.
177
- func (interp * Interpreter ) rootFromSourceLocation () (string , error ) {
178
- sourceFile := interp .name
179
- if sourceFile == DefaultSourceName {
180
- return "" , nil
181
- }
182
- wd , err := os .Getwd ()
160
+ // getPackageDir uses the provided Go module environment variables to find the absolute path of an import path.
161
+ func (interp * Interpreter ) getPackageDir (importPath string ) (string , error ) {
162
+ absImportPath , err := filepath .Abs (importPath )
183
163
if err != nil {
184
- return "" , err
185
- }
186
- pkgDir := filepath .Join (wd , filepath .Dir (sourceFile ))
187
- root := strings .TrimPrefix (pkgDir , filepath .Join (interp .context .GOPATH , "src" )+ "/" )
188
- if root == wd {
189
- return "" , fmt .Errorf ("package location %s not in GOPATH" , pkgDir )
190
- }
191
- return root , nil
192
- }
193
-
194
- // pkgDir returns the absolute path in filesystem for a package given its import path
195
- // and the root of the subtree dependencies.
196
- func (interp * Interpreter ) pkgDir (goPath string , root , importPath string ) (string , string , error ) {
197
- rPath := filepath .Join (root , "vendor" )
198
- dir := filepath .Join (goPath , "src" , rPath , importPath )
199
-
200
- if _ , err := fs .Stat (interp .opt .filesystem , dir ); err == nil {
201
- return dir , rPath , nil // found!
164
+ return "" , fmt .Errorf ("an error occurred determining the absolute path of import path %v: %w" , importPath , err )
202
165
}
203
166
204
- dir = filepath .Join (goPath , "src" , effectivePkg (root , importPath ))
205
-
206
- if _ , err := fs .Stat (interp .opt .filesystem , dir ); err == nil {
207
- return dir , root , nil // found!
208
- }
209
-
210
- if len (root ) == 0 {
211
- if interp .context .GOPATH == "" {
212
- return "" , "" , fmt .Errorf ("unable to find source related to: %q. Either the GOPATH environment variable, or the Interpreter.Options.GoPath needs to be set" , importPath )
213
- }
214
- return "" , "" , fmt .Errorf ("unable to find source related to: %q" , importPath )
167
+ config := packages.Config {
168
+ Env : []string {
169
+ "GOPATH=" + interp .context .GOPATH ,
170
+ "GOCACHE=" + interp .opt .env ["GOCACHE" ],
171
+ "GOROOT=" + interp .opt .env ["GOROOT" ],
172
+ "GOPRIVATE=" + interp .opt .env ["GOPRIVATE" ],
173
+ "GOMODCACHE=" + interp .opt .env ["GOMODCACHE" ],
174
+ "GO111MODULE=" + interp .opt .env ["GO111MODULE" ],
175
+ },
215
176
}
216
177
217
- rootPath := filepath .Join (goPath , "src" , root )
218
- prevRoot , err := previousRoot (interp .opt .filesystem , rootPath , root )
178
+ pkgs , err := packages .Load (& config , absImportPath )
219
179
if err != nil {
220
- return "" , " " , err
180
+ return "" , fmt . Errorf ( "an error occurred retrieving a package: %v \n %v \n If Access is denied, run in administrator " , absImportPath , err )
221
181
}
222
182
223
- return interp .pkgDir (goPath , prevRoot , importPath )
224
- }
225
-
226
- const vendor = "vendor"
227
-
228
- // Find the previous source root (vendor > vendor > ... > GOPATH).
229
- func previousRoot (filesystem fs.FS , rootPath , root string ) (string , error ) {
230
- rootPath = filepath .Clean (rootPath )
231
- parent , final := filepath .Split (rootPath )
232
- parent = filepath .Clean (parent )
233
-
234
- // TODO(mpl): maybe it works for the special case main, but can't be bothered for now.
235
- if root != mainID && final != vendor {
236
- root = strings .TrimSuffix (root , string (filepath .Separator ))
237
- prefix := strings .TrimSuffix (strings .TrimSuffix (rootPath , root ), string (filepath .Separator ))
238
-
239
- // look for the closest vendor in one of our direct ancestors, as it takes priority.
240
- var vendored string
241
- for {
242
- fi , err := fs .Stat (filesystem , filepath .Join (parent , vendor ))
243
- if err == nil && fi .IsDir () {
244
- vendored = strings .TrimPrefix (strings .TrimPrefix (parent , prefix ), string (filepath .Separator ))
245
- break
246
- }
247
- if ! os .IsNotExist (err ) {
248
- return "" , err
249
- }
250
-
251
- // stop when we reach GOPATH/src/blah
252
- parent = filepath .Dir (parent )
253
- if parent == prefix {
254
- break
183
+ // confirm the import path is found.
184
+ for _ , pkg := range pkgs {
185
+ for _ , goFile := range pkg .GoFiles {
186
+ if strings .Contains (filepath .Dir (goFile ), pkg .Name ) {
187
+ return filepath .Dir (goFile ), nil
255
188
}
256
-
257
- // just an additional failsafe, stop if we reach the filesystem root, or dot (if
258
- // we are dealing with relative paths).
259
- // TODO(mpl): It should probably be a critical error actually,
260
- // as we shouldn't have gone that high up in the tree.
261
- if parent == string (filepath .Separator ) || parent == "." {
262
- break
263
- }
264
- }
265
-
266
- if vendored != "" {
267
- return vendored , nil
268
189
}
269
190
}
270
191
271
- // TODO(mpl): the algorithm below might be redundant with the one above,
272
- // but keeping it for now. Investigate/simplify/remove later.
273
- splitRoot := strings .Split (root , string (filepath .Separator ))
274
- var index int
275
- for i := len (splitRoot ) - 1 ; i >= 0 ; i -- {
276
- if splitRoot [i ] == "vendor" {
277
- index = i
278
- break
279
- }
280
- }
281
-
282
- if index == 0 {
283
- return "" , nil
284
- }
285
-
286
- return filepath .Join (splitRoot [:index ]... ), nil
192
+ return "" , fmt .Errorf ("an import source could not be found: %q. Did you set the required environment variable in the Interpreter.Options?" , absImportPath )
287
193
}
288
194
289
195
func effectivePkg (root , path string ) string {
@@ -313,9 +219,3 @@ func effectivePkg(root, path string) string {
313
219
314
220
return filepath .Join (root , frag )
315
221
}
316
-
317
- // isPathRelative returns true if path starts with "./" or "../".
318
- // It is intended for use on import paths, where "/" is always the directory separator.
319
- func isPathRelative (s string ) bool {
320
- return strings .HasPrefix (s , "./" ) || strings .HasPrefix (s , "../" )
321
- }
0 commit comments