Skip to content

Commit 9135795

Browse files
author
Jay Conrod
committed
cmd/go/internal/load: report positions for embed errors
Fixes #43469 Fixes #43632 Change-Id: I862bb9da8bc3e4f15635bc33fd7cb5f12b917d71 Reviewed-on: https://go-review.googlesource.com/c/go/+/283638 Run-TryBot: Jay Conrod <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Jay Conrod <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
1 parent d9b79e5 commit 9135795

File tree

3 files changed

+64
-20
lines changed

3 files changed

+64
-20
lines changed

src/cmd/go/internal/load/pkg.go

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,9 @@ type PackageError struct {
412412
}
413413

414414
func (p *PackageError) Error() string {
415+
// TODO(#43696): decide when to print the stack or the position based on
416+
// the error type and whether the package is in the main module.
417+
// Document the rationale.
415418
if p.Pos != "" && (len(p.ImportStack) == 0 || !p.alwaysPrintStack) {
416419
// Omit import stack. The full path to the file where the error
417420
// is the most important thing.
@@ -1663,11 +1666,6 @@ func (p *Package) load(ctx context.Context, path string, stk *ImportStack, impor
16631666
p.setLoadPackageDataError(err, path, stk, importPos)
16641667
}
16651668

1666-
p.EmbedFiles, p.Internal.Embed, err = p.resolveEmbed(p.EmbedPatterns)
1667-
if err != nil {
1668-
setError(err)
1669-
}
1670-
16711669
useBindir := p.Name == "main"
16721670
if !p.Standard {
16731671
switch cfg.BuildBuildmode {
@@ -1803,9 +1801,19 @@ func (p *Package) load(ctx context.Context, path string, stk *ImportStack, impor
18031801
return
18041802
}
18051803

1804+
// Errors after this point are caused by this package, not the importing
1805+
// package. Pushing the path here prevents us from reporting the error
1806+
// with the position of the import declaration.
18061807
stk.Push(path)
18071808
defer stk.Pop()
18081809

1810+
p.EmbedFiles, p.Internal.Embed, err = p.resolveEmbed(p.EmbedPatterns)
1811+
if err != nil {
1812+
setError(err)
1813+
embedErr := err.(*EmbedError)
1814+
p.Error.setPos(p.Internal.Build.EmbedPatternPos[embedErr.Pattern])
1815+
}
1816+
18091817
// Check for case-insensitive collision of input files.
18101818
// To avoid problems on case-insensitive files, we reject any package
18111819
// where two different input files have equal names under a case-insensitive
@@ -1909,6 +1917,20 @@ func (p *Package) load(ctx context.Context, path string, stk *ImportStack, impor
19091917
}
19101918
}
19111919

1920+
// An EmbedError indicates a problem with a go:embed directive.
1921+
type EmbedError struct {
1922+
Pattern string
1923+
Err error
1924+
}
1925+
1926+
func (e *EmbedError) Error() string {
1927+
return fmt.Sprintf("pattern %s: %v", e.Pattern, e.Err)
1928+
}
1929+
1930+
func (e *EmbedError) Unwrap() error {
1931+
return e.Err
1932+
}
1933+
19121934
// ResolveEmbed resolves //go:embed patterns and returns only the file list.
19131935
// For use by go list to compute p.TestEmbedFiles and p.XTestEmbedFiles.
19141936
func (p *Package) ResolveEmbed(patterns []string) []string {
@@ -1920,24 +1942,33 @@ func (p *Package) ResolveEmbed(patterns []string) []string {
19201942
// It sets files to the list of unique files matched (for go list),
19211943
// and it sets pmap to the more precise mapping from
19221944
// patterns to files.
1923-
// TODO(rsc): All these messages need position information for better error reports.
19241945
func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[string][]string, err error) {
1946+
var pattern string
1947+
defer func() {
1948+
if err != nil {
1949+
err = &EmbedError{
1950+
Pattern: pattern,
1951+
Err: err,
1952+
}
1953+
}
1954+
}()
1955+
19251956
pmap = make(map[string][]string)
19261957
have := make(map[string]int)
19271958
dirOK := make(map[string]bool)
19281959
pid := 0 // pattern ID, to allow reuse of have map
1929-
for _, pattern := range patterns {
1960+
for _, pattern = range patterns {
19301961
pid++
19311962

19321963
// Check pattern is valid for //go:embed.
19331964
if _, err := path.Match(pattern, ""); err != nil || !validEmbedPattern(pattern) {
1934-
return nil, nil, fmt.Errorf("pattern %s: invalid pattern syntax", pattern)
1965+
return nil, nil, fmt.Errorf("invalid pattern syntax")
19351966
}
19361967

19371968
// Glob to find matches.
19381969
match, err := fsys.Glob(p.Dir + string(filepath.Separator) + filepath.FromSlash(pattern))
19391970
if err != nil {
1940-
return nil, nil, fmt.Errorf("pattern %s: %v", pattern, err)
1971+
return nil, nil, err
19411972
}
19421973

19431974
// Filter list of matches down to the ones that will still exist when
@@ -1961,26 +1992,26 @@ func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[stri
19611992
// (do not contain a go.mod).
19621993
for dir := file; len(dir) > len(p.Dir)+1 && !dirOK[dir]; dir = filepath.Dir(dir) {
19631994
if _, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil {
1964-
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in different module", pattern, what, rel)
1995+
return nil, nil, fmt.Errorf("cannot embed %s %s: in different module", what, rel)
19651996
}
19661997
if dir != file {
19671998
if info, err := fsys.Lstat(dir); err == nil && !info.IsDir() {
1968-
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in non-directory %s", pattern, what, rel, dir[len(p.Dir)+1:])
1999+
return nil, nil, fmt.Errorf("cannot embed %s %s: in non-directory %s", what, rel, dir[len(p.Dir)+1:])
19692000
}
19702001
}
19712002
dirOK[dir] = true
19722003
if elem := filepath.Base(dir); isBadEmbedName(elem) {
19732004
if dir == file {
1974-
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: invalid name %s", pattern, what, rel, elem)
2005+
return nil, nil, fmt.Errorf("cannot embed %s %s: invalid name %s", what, rel, elem)
19752006
} else {
1976-
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in invalid directory %s", pattern, what, rel, elem)
2007+
return nil, nil, fmt.Errorf("cannot embed %s %s: in invalid directory %s", what, rel, elem)
19772008
}
19782009
}
19792010
}
19802011

19812012
switch {
19822013
default:
1983-
return nil, nil, fmt.Errorf("pattern %s: cannot embed irregular file %s", pattern, rel)
2014+
return nil, nil, fmt.Errorf("cannot embed irregular file %s", rel)
19842015

19852016
case info.Mode().IsRegular():
19862017
if have[rel] != pid {
@@ -2027,13 +2058,13 @@ func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[stri
20272058
return nil, nil, err
20282059
}
20292060
if count == 0 {
2030-
return nil, nil, fmt.Errorf("pattern %s: cannot embed directory %s: contains no embeddable files", pattern, rel)
2061+
return nil, nil, fmt.Errorf("cannot embed directory %s: contains no embeddable files", rel)
20312062
}
20322063
}
20332064
}
20342065

20352066
if len(list) == 0 {
2036-
return nil, nil, fmt.Errorf("pattern %s: no matching files found", pattern)
2067+
return nil, nil, fmt.Errorf("no matching files found")
20372068
}
20382069
sort.Strings(list)
20392070
pmap[pattern] = list

src/cmd/go/internal/load/test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (p
130130
ImportStack: stk.Copy(),
131131
Err: err,
132132
}
133+
embedErr := err.(*EmbedError)
134+
ptestErr.setPos(p.Internal.Build.TestEmbedPatternPos[embedErr.Pattern])
133135
}
134136
stk.Pop()
135137

@@ -151,6 +153,8 @@ func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (p
151153
ImportStack: stk.Copy(),
152154
Err: err,
153155
}
156+
embedErr := err.(*EmbedError)
157+
pxtestErr.setPos(p.Internal.Build.XTestEmbedPatternPos[embedErr.Pattern])
154158
}
155159
stk.Pop()
156160

src/cmd/go/testdata/script/embed.txt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ cp x.go2 x.go
2020
go build -x
2121
cp x.txt .git
2222
! go build -x
23-
stderr 'pattern [*]t: cannot embed file [.]git'
23+
stderr '^x.go:5:12: pattern [*]t: cannot embed file [.]git: invalid name [.]git$'
2424
rm .git
2525

2626
# build rejects symlinks
@@ -32,19 +32,24 @@ rm .git
3232
# build rejects empty directories
3333
mkdir t
3434
! go build -x
35-
stderr 'pattern [*]t: cannot embed directory t: contains no embeddable files'
35+
stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$'
3636

3737
# build ignores symlinks and invalid names in directories
3838
cp x.txt t/.git
3939
! go build -x
40-
stderr 'pattern [*]t: cannot embed directory t: contains no embeddable files'
40+
stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$'
4141
[symlink] symlink t/x.link -> ../x.txt
4242
[symlink] ! go build -x
43-
[symlink] stderr 'pattern [*]t: cannot embed directory t: contains no embeddable files'
43+
[symlink] stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$'
4444

4545
cp x.txt t/x.txt
4646
go build -x
4747

48+
# build reports errors with positions in imported packages
49+
rm t/x.txt
50+
! go build m/use
51+
stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$'
52+
4853
-- x.go --
4954
package p
5055

@@ -67,6 +72,10 @@ hello
6772
-- x.txt2 --
6873
not hello
6974

75+
-- use/use.go --
76+
package use
77+
78+
import _ "m"
7079
-- go.mod --
7180
module m
7281

0 commit comments

Comments
 (0)