2
2
// Use of this source code is governed by a BSD-style
3
3
// license that can be found in the LICENSE file.
4
4
5
- // This file is a copy of $GOROOT/src/go/internal/gcimporter/exportdata.go.
6
-
7
- // This file implements FindExportData.
5
+ // This file should be kept in sync with $GOROOT/src/internal/exportdata/exportdata.go.
6
+ // This file also additionally implements FindExportData for gcexportdata.NewReader.
8
7
9
8
package gcimporter
10
9
11
10
import (
12
11
"bufio"
13
12
"bytes"
13
+ "errors"
14
14
"fmt"
15
15
"go/build"
16
16
"os"
@@ -110,10 +110,13 @@ func FindExportData(r *bufio.Reader) (size int64, err error) {
110
110
// path based on package information provided by build.Import (using
111
111
// the build.Default build.Context). A relative srcDir is interpreted
112
112
// relative to the current working directory.
113
- // If no file was found, an empty filename is returned.
114
- func FindPkg (path , srcDir string ) (filename , id string ) {
113
+ //
114
+ // FindPkg is only used in tests within x/tools.
115
+ func FindPkg (path , srcDir string ) (filename , id string , err error ) {
116
+ // TODO(taking): Move internal/exportdata.FindPkg into its own file,
117
+ // and then this copy into a _test package.
115
118
if path == "" {
116
- return
119
+ return "" , "" , errors . New ( "path is empty" )
117
120
}
118
121
119
122
var noext string
@@ -124,20 +127,23 @@ func FindPkg(path, srcDir string) (filename, id string) {
124
127
if abs , err := filepath .Abs (srcDir ); err == nil { // see issue 14282
125
128
srcDir = abs
126
129
}
127
- bp , _ := build .Import (path , srcDir , build .FindOnly | build .AllowBinary )
130
+ var bp * build.Package
131
+ bp , err = build .Import (path , srcDir , build .FindOnly | build .AllowBinary )
128
132
if bp .PkgObj == "" {
129
- var ok bool
130
133
if bp .Goroot && bp .Dir != "" {
131
- filename , ok = lookupGorootExport (bp .Dir )
132
- }
133
- if ! ok {
134
- id = path // make sure we have an id to print in error message
135
- return
134
+ filename , err = lookupGorootExport (bp .Dir )
135
+ if err == nil {
136
+ _ , err = os .Stat (filename )
137
+ }
138
+ if err == nil {
139
+ return filename , bp .ImportPath , nil
140
+ }
136
141
}
142
+ goto notfound
137
143
} else {
138
144
noext = strings .TrimSuffix (bp .PkgObj , ".a" )
139
- id = bp .ImportPath
140
145
}
146
+ id = bp .ImportPath
141
147
142
148
case build .IsLocalImport (path ):
143
149
// "./x" -> "/this/directory/x.ext", "/this/directory/x"
@@ -158,27 +164,28 @@ func FindPkg(path, srcDir string) (filename, id string) {
158
164
}
159
165
}
160
166
161
- if filename != "" {
162
- if f , err := os .Stat (filename ); err == nil && ! f .IsDir () {
163
- return
164
- }
165
- }
166
-
167
167
// try extensions
168
168
for _ , ext := range pkgExts {
169
169
filename = noext + ext
170
- if f , err := os .Stat (filename ); err == nil && ! f .IsDir () {
171
- return
170
+ f , statErr := os .Stat (filename )
171
+ if statErr == nil && ! f .IsDir () {
172
+ return filename , id , nil
173
+ }
174
+ if err == nil {
175
+ err = statErr
172
176
}
173
177
}
174
178
175
- filename = "" // not found
176
- return
179
+ notfound:
180
+ if err == nil {
181
+ return "" , path , fmt .Errorf ("can't find import: %q" , path )
182
+ }
183
+ return "" , path , fmt .Errorf ("can't find import: %q: %w" , path , err )
177
184
}
178
185
179
- var pkgExts = [... ]string {".a" , ".o" }
186
+ var pkgExts = [... ]string {".a" , ".o" } // a file from the build cache will have no extension
180
187
181
- var exportMap sync.Map // package dir → func() (string, bool )
188
+ var exportMap sync.Map // package dir → func() (string, error )
182
189
183
190
// lookupGorootExport returns the location of the export data
184
191
// (normally found in the build cache, but located in GOROOT/pkg
@@ -187,34 +194,42 @@ var exportMap sync.Map // package dir → func() (string, bool)
187
194
// (We use the package's directory instead of its import path
188
195
// mainly to simplify handling of the packages in src/vendor
189
196
// and cmd/vendor.)
190
- func lookupGorootExport (pkgDir string ) (string , bool ) {
197
+ //
198
+ // lookupGorootExport is only used in tests within x/tools.
199
+ func lookupGorootExport (pkgDir string ) (string , error ) {
191
200
f , ok := exportMap .Load (pkgDir )
192
201
if ! ok {
193
202
var (
194
203
listOnce sync.Once
195
204
exportPath string
205
+ err error
196
206
)
197
- f , _ = exportMap .LoadOrStore (pkgDir , func () (string , bool ) {
207
+ f , _ = exportMap .LoadOrStore (pkgDir , func () (string , error ) {
198
208
listOnce .Do (func () {
199
- cmd := exec .Command (" go" , "list" , "-export" , "-f" , "{{.Export}}" , pkgDir )
209
+ cmd := exec .Command (filepath . Join ( build . Default . GOROOT , "bin" , " go") , "list" , "-export" , "-f" , "{{.Export}}" , pkgDir )
200
210
cmd .Dir = build .Default .GOROOT
211
+ cmd .Env = append (os .Environ (), "PWD=" + cmd .Dir , "GOROOT=" + build .Default .GOROOT )
201
212
var output []byte
202
- output , err : = cmd .Output ()
213
+ output , err = cmd .Output ()
203
214
if err != nil {
215
+ if ee , ok := err .(* exec.ExitError ); ok && len (ee .Stderr ) > 0 {
216
+ err = errors .New (string (ee .Stderr ))
217
+ }
204
218
return
205
219
}
206
220
207
221
exports := strings .Split (string (bytes .TrimSpace (output )), "\n " )
208
222
if len (exports ) != 1 {
223
+ err = fmt .Errorf ("go list reported %d exports; expected 1" , len (exports ))
209
224
return
210
225
}
211
226
212
227
exportPath = exports [0 ]
213
228
})
214
229
215
- return exportPath , exportPath != ""
230
+ return exportPath , err
216
231
})
217
232
}
218
233
219
- return f .(func () (string , bool ))()
234
+ return f .(func () (string , error ))()
220
235
}
0 commit comments