Skip to content

Commit 47df42f

Browse files
timothy-kingGo LUCI
authored and
Go LUCI
committedDec 11, 2024·
internal/gcimporter: synchronizing FindPkg implementations
Synchronizes the implementation of FindPkg with the implementation of FindPkg in $GOROOT/src/internal/exportdata/exportdata.go. This adds an error return value. Updates golang/go#70651 Change-Id: If0295b6d396ffca30ee75d958a50aa7f5b93848e Reviewed-on: https://go-review.googlesource.com/c/tools/+/633658 Commit-Queue: Tim King <taking@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Findley <rfindley@google.com>
1 parent 82b6f75 commit 47df42f

File tree

3 files changed

+53
-38
lines changed

3 files changed

+53
-38
lines changed
 

‎internal/gcimporter/exportdata.go

+47-32
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

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.
87

98
package gcimporter
109

1110
import (
1211
"bufio"
1312
"bytes"
13+
"errors"
1414
"fmt"
1515
"go/build"
1616
"os"
@@ -110,10 +110,13 @@ func FindExportData(r *bufio.Reader) (size int64, err error) {
110110
// path based on package information provided by build.Import (using
111111
// the build.Default build.Context). A relative srcDir is interpreted
112112
// 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.
115118
if path == "" {
116-
return
119+
return "", "", errors.New("path is empty")
117120
}
118121

119122
var noext string
@@ -124,20 +127,23 @@ func FindPkg(path, srcDir string) (filename, id string) {
124127
if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
125128
srcDir = abs
126129
}
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)
128132
if bp.PkgObj == "" {
129-
var ok bool
130133
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+
}
136141
}
142+
goto notfound
137143
} else {
138144
noext = strings.TrimSuffix(bp.PkgObj, ".a")
139-
id = bp.ImportPath
140145
}
146+
id = bp.ImportPath
141147

142148
case build.IsLocalImport(path):
143149
// "./x" -> "/this/directory/x.ext", "/this/directory/x"
@@ -158,27 +164,28 @@ func FindPkg(path, srcDir string) (filename, id string) {
158164
}
159165
}
160166

161-
if filename != "" {
162-
if f, err := os.Stat(filename); err == nil && !f.IsDir() {
163-
return
164-
}
165-
}
166-
167167
// try extensions
168168
for _, ext := range pkgExts {
169169
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
172176
}
173177
}
174178

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)
177184
}
178185

179-
var pkgExts = [...]string{".a", ".o"}
186+
var pkgExts = [...]string{".a", ".o"} // a file from the build cache will have no extension
180187

181-
var exportMap sync.Map // package dir → func() (string, bool)
188+
var exportMap sync.Map // package dir → func() (string, error)
182189

183190
// lookupGorootExport returns the location of the export data
184191
// (normally found in the build cache, but located in GOROOT/pkg
@@ -187,34 +194,42 @@ var exportMap sync.Map // package dir → func() (string, bool)
187194
// (We use the package's directory instead of its import path
188195
// mainly to simplify handling of the packages in src/vendor
189196
// 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) {
191200
f, ok := exportMap.Load(pkgDir)
192201
if !ok {
193202
var (
194203
listOnce sync.Once
195204
exportPath string
205+
err error
196206
)
197-
f, _ = exportMap.LoadOrStore(pkgDir, func() (string, bool) {
207+
f, _ = exportMap.LoadOrStore(pkgDir, func() (string, error) {
198208
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)
200210
cmd.Dir = build.Default.GOROOT
211+
cmd.Env = append(os.Environ(), "PWD="+cmd.Dir, "GOROOT="+build.Default.GOROOT)
201212
var output []byte
202-
output, err := cmd.Output()
213+
output, err = cmd.Output()
203214
if err != nil {
215+
if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
216+
err = errors.New(string(ee.Stderr))
217+
}
204218
return
205219
}
206220

207221
exports := strings.Split(string(bytes.TrimSpace(output)), "\n")
208222
if len(exports) != 1 {
223+
err = fmt.Errorf("go list reported %d exports; expected 1", len(exports))
209224
return
210225
}
211226

212227
exportPath = exports[0]
213228
})
214229

215-
return exportPath, exportPath != ""
230+
return exportPath, err
216231
})
217232
}
218233

219-
return f.(func() (string, bool))()
234+
return f.(func() (string, error))()
220235
}

‎internal/gcimporter/gcimporter.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,12 @@ func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDi
6565
}
6666
rc = f
6767
} else {
68-
filename, id = FindPkg(path, srcDir)
68+
filename, id, err = FindPkg(path, srcDir)
6969
if filename == "" {
7070
if path == "unsafe" {
7171
return types.Unsafe, nil
7272
}
73-
return nil, fmt.Errorf("can't find import: %q", id)
73+
return nil, err
7474
}
7575

7676
// no need to re-import if the package was imported completely before

‎internal/gcimporter/gcimporter_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ func testImportTestdata(t *testing.T) {
129129

130130
packageFiles := map[string]string{}
131131
for _, pkg := range []string{"go/ast", "go/token"} {
132-
export, _ := gcimporter.FindPkg(pkg, "testdata")
132+
export, _, err := gcimporter.FindPkg(pkg, "testdata")
133133
if export == "" {
134-
t.Fatalf("no export data found for %s", pkg)
134+
t.Fatalf("no export data found for %s: %s", pkg, err)
135135
}
136136
packageFiles[pkg] = export
137137
}
@@ -587,9 +587,9 @@ func TestIssue13566(t *testing.T) {
587587
t.Fatal(err)
588588
}
589589

590-
jsonExport, _ := gcimporter.FindPkg("encoding/json", "testdata")
590+
jsonExport, _, err := gcimporter.FindPkg("encoding/json", "testdata")
591591
if jsonExport == "" {
592-
t.Fatalf("no export data found for encoding/json")
592+
t.Fatalf("no export data found for encoding/json: %s", err)
593593
}
594594

595595
compilePkg(t, "testdata", "a.go", testoutdir, map[string]string{"encoding/json": jsonExport}, apkg(testoutdir))

0 commit comments

Comments
 (0)
Please sign in to comment.