@@ -13,6 +13,7 @@ import (
13
13
"log"
14
14
"os"
15
15
"os/exec"
16
+ "path"
16
17
"path/filepath"
17
18
"reflect"
18
19
"regexp"
@@ -86,6 +87,23 @@ func goListDriver(cfg *Config, patterns ...string) (*driverResponse, error) {
86
87
}()
87
88
}
88
89
90
+ // start fetching rootDirs
91
+ var rootDirs map [string ]string
92
+ var rootDirsReady = make (chan struct {})
93
+ go func () {
94
+ rootDirs = determineRootDirs (cfg )
95
+ close (rootDirsReady )
96
+ }()
97
+ getRootDirs := func () map [string ]string {
98
+ <- rootDirsReady
99
+ return rootDirs
100
+ }
101
+
102
+ // always pass getRootDirs to golistDriver
103
+ golistDriver := func (cfg * Config , patterns ... string ) (* driverResponse , error ) {
104
+ return golistDriver (cfg , getRootDirs , patterns ... )
105
+ }
106
+
89
107
// Determine files requested in contains patterns
90
108
var containFiles []string
91
109
var packagesNamed []string
@@ -147,7 +165,7 @@ extractQueries:
147
165
var containsCandidates []string
148
166
149
167
if len (containFiles ) != 0 {
150
- if err := runContainsQueries (cfg , golistDriver , response , containFiles ); err != nil {
168
+ if err := runContainsQueries (cfg , golistDriver , response , containFiles , getRootDirs ); err != nil {
151
169
return nil , err
152
170
}
153
171
}
@@ -158,15 +176,15 @@ extractQueries:
158
176
}
159
177
}
160
178
161
- modifiedPkgs , needPkgs , err := processGolistOverlay (cfg , response )
179
+ modifiedPkgs , needPkgs , err := processGolistOverlay (cfg , response , getRootDirs )
162
180
if err != nil {
163
181
return nil , err
164
182
}
165
183
if len (containFiles ) > 0 {
166
184
containsCandidates = append (containsCandidates , modifiedPkgs ... )
167
185
containsCandidates = append (containsCandidates , needPkgs ... )
168
186
}
169
- if err := addNeededOverlayPackages (cfg , golistDriver , response , needPkgs ); err != nil {
187
+ if err := addNeededOverlayPackages (cfg , golistDriver , response , needPkgs , getRootDirs ); err != nil {
170
188
return nil , err
171
189
}
172
190
// Check candidate packages for containFiles.
@@ -198,7 +216,7 @@ extractQueries:
198
216
return response .dr , nil
199
217
}
200
218
201
- func addNeededOverlayPackages (cfg * Config , driver driver , response * responseDeduper , pkgs []string ) error {
219
+ func addNeededOverlayPackages (cfg * Config , driver driver , response * responseDeduper , pkgs []string , getRootDirs func () map [ string ] string ) error {
202
220
if len (pkgs ) == 0 {
203
221
return nil
204
222
}
@@ -209,17 +227,17 @@ func addNeededOverlayPackages(cfg *Config, driver driver, response *responseDedu
209
227
for _ , pkg := range dr .Packages {
210
228
response .addPackage (pkg )
211
229
}
212
- _ , needPkgs , err := processGolistOverlay (cfg , response )
230
+ _ , needPkgs , err := processGolistOverlay (cfg , response , getRootDirs )
213
231
if err != nil {
214
232
return err
215
233
}
216
- if err := addNeededOverlayPackages (cfg , driver , response , needPkgs ); err != nil {
234
+ if err := addNeededOverlayPackages (cfg , driver , response , needPkgs , getRootDirs ); err != nil {
217
235
return err
218
236
}
219
237
return nil
220
238
}
221
239
222
- func runContainsQueries (cfg * Config , driver driver , response * responseDeduper , queries []string ) error {
240
+ func runContainsQueries (cfg * Config , driver driver , response * responseDeduper , queries []string , rootDirs func () map [ string ] string ) error {
223
241
for _ , query := range queries {
224
242
// TODO(matloob): Do only one query per directory.
225
243
fdir := filepath .Dir (query )
@@ -567,7 +585,7 @@ func otherFiles(p *jsonPackage) [][]string {
567
585
// golistDriver uses the "go list" command to expand the pattern
568
586
// words and return metadata for the specified packages. dir may be
569
587
// "" and env may be nil, as per os/exec.Command.
570
- func golistDriver (cfg * Config , words ... string ) (* driverResponse , error ) {
588
+ func golistDriver (cfg * Config , rootsDirs func () map [ string ] string , words ... string ) (* driverResponse , error ) {
571
589
// go list uses the following identifiers in ImportPath and Imports:
572
590
//
573
591
// "p" -- importable package or main (command)
@@ -608,6 +626,20 @@ func golistDriver(cfg *Config, words ...string) (*driverResponse, error) {
608
626
return nil , fmt .Errorf ("package missing import path: %+v" , p )
609
627
}
610
628
629
+ // Work around https://golang.org/issue/33157:
630
+ // go list -e, when given an absolute path, will find the package contained at
631
+ // that directory. But when no package exists there, it will return a fake package
632
+ // with an error and the ImportPath set to the absolute path provided to go list.
633
+ // Try toto convert that absolute path to what its package path would be if it's
634
+ // contained in a known module or GOPATH entry. This will allow the package to be
635
+ // properly "reclaimed" when overlays are processed.
636
+ if filepath .IsAbs (p .ImportPath ) && p .Error != nil {
637
+ pkgPath , ok := getPkgPath (p .ImportPath , rootsDirs )
638
+ if ok {
639
+ p .ImportPath = pkgPath
640
+ }
641
+ }
642
+
611
643
if old , found := seen [p .ImportPath ]; found {
612
644
if ! reflect .DeepEqual (p , old ) {
613
645
return nil , fmt .Errorf ("internal error: go list gives conflicting information for package %v" , p .ImportPath )
@@ -711,6 +743,27 @@ func golistDriver(cfg *Config, words ...string) (*driverResponse, error) {
711
743
return & response , nil
712
744
}
713
745
746
+ // getPkgPath finds the package path of a directory if it's relative to a root directory.
747
+ func getPkgPath (dir string , rootDirs func () map [string ]string ) (string , bool ) {
748
+ for rdir , rpath := range rootDirs () {
749
+ // TODO(matloob): This doesn't properly handle symlinks.
750
+ r , err := filepath .Rel (rdir , dir )
751
+ if err != nil {
752
+ continue
753
+ }
754
+ if rpath != "" {
755
+ // We choose only ore root even though the directory even it can belong in multiple modules
756
+ // or GOPATH entries. This is okay because we only need to work with absolute dirs when a
757
+ // file is missing from disk, for instance when gopls calls go/packages in an overlay.
758
+ // Once the file is saved, gopls, or the next invocation of the tool will get the correct
759
+ // result straight from golist.
760
+ // TODO(matloob): Implement module tiebreaking?
761
+ return path .Join (rpath , filepath .ToSlash (r )), true
762
+ }
763
+ }
764
+ return "" , false
765
+ }
766
+
714
767
// absJoin absolutizes and flattens the lists of files.
715
768
func absJoin (dir string , fileses ... []string ) (res []string ) {
716
769
for _ , files := range fileses {
0 commit comments