mirror of https://github.com/golang/go.git
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 <jayconrod@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Jay Conrod <jayconrod@google.com> Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
parent
d9b79e53bb
commit
9135795891
|
|
@ -412,6 +412,9 @@ type PackageError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PackageError) Error() string {
|
func (p *PackageError) Error() string {
|
||||||
|
// TODO(#43696): decide when to print the stack or the position based on
|
||||||
|
// the error type and whether the package is in the main module.
|
||||||
|
// Document the rationale.
|
||||||
if p.Pos != "" && (len(p.ImportStack) == 0 || !p.alwaysPrintStack) {
|
if p.Pos != "" && (len(p.ImportStack) == 0 || !p.alwaysPrintStack) {
|
||||||
// Omit import stack. The full path to the file where the error
|
// Omit import stack. The full path to the file where the error
|
||||||
// is the most important thing.
|
// is the most important thing.
|
||||||
|
|
@ -1663,11 +1666,6 @@ func (p *Package) load(ctx context.Context, path string, stk *ImportStack, impor
|
||||||
p.setLoadPackageDataError(err, path, stk, importPos)
|
p.setLoadPackageDataError(err, path, stk, importPos)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.EmbedFiles, p.Internal.Embed, err = p.resolveEmbed(p.EmbedPatterns)
|
|
||||||
if err != nil {
|
|
||||||
setError(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
useBindir := p.Name == "main"
|
useBindir := p.Name == "main"
|
||||||
if !p.Standard {
|
if !p.Standard {
|
||||||
switch cfg.BuildBuildmode {
|
switch cfg.BuildBuildmode {
|
||||||
|
|
@ -1803,9 +1801,19 @@ func (p *Package) load(ctx context.Context, path string, stk *ImportStack, impor
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Errors after this point are caused by this package, not the importing
|
||||||
|
// package. Pushing the path here prevents us from reporting the error
|
||||||
|
// with the position of the import declaration.
|
||||||
stk.Push(path)
|
stk.Push(path)
|
||||||
defer stk.Pop()
|
defer stk.Pop()
|
||||||
|
|
||||||
|
p.EmbedFiles, p.Internal.Embed, err = p.resolveEmbed(p.EmbedPatterns)
|
||||||
|
if err != nil {
|
||||||
|
setError(err)
|
||||||
|
embedErr := err.(*EmbedError)
|
||||||
|
p.Error.setPos(p.Internal.Build.EmbedPatternPos[embedErr.Pattern])
|
||||||
|
}
|
||||||
|
|
||||||
// Check for case-insensitive collision of input files.
|
// Check for case-insensitive collision of input files.
|
||||||
// To avoid problems on case-insensitive files, we reject any package
|
// To avoid problems on case-insensitive files, we reject any package
|
||||||
// where two different input files have equal names under a case-insensitive
|
// 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// An EmbedError indicates a problem with a go:embed directive.
|
||||||
|
type EmbedError struct {
|
||||||
|
Pattern string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EmbedError) Error() string {
|
||||||
|
return fmt.Sprintf("pattern %s: %v", e.Pattern, e.Err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EmbedError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
// ResolveEmbed resolves //go:embed patterns and returns only the file list.
|
// ResolveEmbed resolves //go:embed patterns and returns only the file list.
|
||||||
// For use by go list to compute p.TestEmbedFiles and p.XTestEmbedFiles.
|
// For use by go list to compute p.TestEmbedFiles and p.XTestEmbedFiles.
|
||||||
func (p *Package) ResolveEmbed(patterns []string) []string {
|
func (p *Package) ResolveEmbed(patterns []string) []string {
|
||||||
|
|
@ -1920,24 +1942,33 @@ func (p *Package) ResolveEmbed(patterns []string) []string {
|
||||||
// It sets files to the list of unique files matched (for go list),
|
// It sets files to the list of unique files matched (for go list),
|
||||||
// and it sets pmap to the more precise mapping from
|
// and it sets pmap to the more precise mapping from
|
||||||
// patterns to files.
|
// patterns to files.
|
||||||
// TODO(rsc): All these messages need position information for better error reports.
|
|
||||||
func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[string][]string, err error) {
|
func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[string][]string, err error) {
|
||||||
|
var pattern string
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
err = &EmbedError{
|
||||||
|
Pattern: pattern,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
pmap = make(map[string][]string)
|
pmap = make(map[string][]string)
|
||||||
have := make(map[string]int)
|
have := make(map[string]int)
|
||||||
dirOK := make(map[string]bool)
|
dirOK := make(map[string]bool)
|
||||||
pid := 0 // pattern ID, to allow reuse of have map
|
pid := 0 // pattern ID, to allow reuse of have map
|
||||||
for _, pattern := range patterns {
|
for _, pattern = range patterns {
|
||||||
pid++
|
pid++
|
||||||
|
|
||||||
// Check pattern is valid for //go:embed.
|
// Check pattern is valid for //go:embed.
|
||||||
if _, err := path.Match(pattern, ""); err != nil || !validEmbedPattern(pattern) {
|
if _, err := path.Match(pattern, ""); err != nil || !validEmbedPattern(pattern) {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: invalid pattern syntax", pattern)
|
return nil, nil, fmt.Errorf("invalid pattern syntax")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Glob to find matches.
|
// Glob to find matches.
|
||||||
match, err := fsys.Glob(p.Dir + string(filepath.Separator) + filepath.FromSlash(pattern))
|
match, err := fsys.Glob(p.Dir + string(filepath.Separator) + filepath.FromSlash(pattern))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: %v", pattern, err)
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Filter list of matches down to the ones that will still exist when
|
// 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
|
||||||
// (do not contain a go.mod).
|
// (do not contain a go.mod).
|
||||||
for dir := file; len(dir) > len(p.Dir)+1 && !dirOK[dir]; dir = filepath.Dir(dir) {
|
for dir := file; len(dir) > len(p.Dir)+1 && !dirOK[dir]; dir = filepath.Dir(dir) {
|
||||||
if _, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil {
|
if _, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in different module", pattern, what, rel)
|
return nil, nil, fmt.Errorf("cannot embed %s %s: in different module", what, rel)
|
||||||
}
|
}
|
||||||
if dir != file {
|
if dir != file {
|
||||||
if info, err := fsys.Lstat(dir); err == nil && !info.IsDir() {
|
if info, err := fsys.Lstat(dir); err == nil && !info.IsDir() {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in non-directory %s", pattern, what, rel, dir[len(p.Dir)+1:])
|
return nil, nil, fmt.Errorf("cannot embed %s %s: in non-directory %s", what, rel, dir[len(p.Dir)+1:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dirOK[dir] = true
|
dirOK[dir] = true
|
||||||
if elem := filepath.Base(dir); isBadEmbedName(elem) {
|
if elem := filepath.Base(dir); isBadEmbedName(elem) {
|
||||||
if dir == file {
|
if dir == file {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: invalid name %s", pattern, what, rel, elem)
|
return nil, nil, fmt.Errorf("cannot embed %s %s: invalid name %s", what, rel, elem)
|
||||||
} else {
|
} else {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed %s %s: in invalid directory %s", pattern, what, rel, elem)
|
return nil, nil, fmt.Errorf("cannot embed %s %s: in invalid directory %s", what, rel, elem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
default:
|
default:
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed irregular file %s", pattern, rel)
|
return nil, nil, fmt.Errorf("cannot embed irregular file %s", rel)
|
||||||
|
|
||||||
case info.Mode().IsRegular():
|
case info.Mode().IsRegular():
|
||||||
if have[rel] != pid {
|
if have[rel] != pid {
|
||||||
|
|
@ -2027,13 +2058,13 @@ func (p *Package) resolveEmbed(patterns []string) (files []string, pmap map[stri
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: cannot embed directory %s: contains no embeddable files", pattern, rel)
|
return nil, nil, fmt.Errorf("cannot embed directory %s: contains no embeddable files", rel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(list) == 0 {
|
if len(list) == 0 {
|
||||||
return nil, nil, fmt.Errorf("pattern %s: no matching files found", pattern)
|
return nil, nil, fmt.Errorf("no matching files found")
|
||||||
}
|
}
|
||||||
sort.Strings(list)
|
sort.Strings(list)
|
||||||
pmap[pattern] = list
|
pmap[pattern] = list
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,8 @@ func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (p
|
||||||
ImportStack: stk.Copy(),
|
ImportStack: stk.Copy(),
|
||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
|
embedErr := err.(*EmbedError)
|
||||||
|
ptestErr.setPos(p.Internal.Build.TestEmbedPatternPos[embedErr.Pattern])
|
||||||
}
|
}
|
||||||
stk.Pop()
|
stk.Pop()
|
||||||
|
|
||||||
|
|
@ -151,6 +153,8 @@ func TestPackagesAndErrors(ctx context.Context, p *Package, cover *TestCover) (p
|
||||||
ImportStack: stk.Copy(),
|
ImportStack: stk.Copy(),
|
||||||
Err: err,
|
Err: err,
|
||||||
}
|
}
|
||||||
|
embedErr := err.(*EmbedError)
|
||||||
|
pxtestErr.setPos(p.Internal.Build.XTestEmbedPatternPos[embedErr.Pattern])
|
||||||
}
|
}
|
||||||
stk.Pop()
|
stk.Pop()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ cp x.go2 x.go
|
||||||
go build -x
|
go build -x
|
||||||
cp x.txt .git
|
cp x.txt .git
|
||||||
! go build -x
|
! go build -x
|
||||||
stderr 'pattern [*]t: cannot embed file [.]git'
|
stderr '^x.go:5:12: pattern [*]t: cannot embed file [.]git: invalid name [.]git$'
|
||||||
rm .git
|
rm .git
|
||||||
|
|
||||||
# build rejects symlinks
|
# build rejects symlinks
|
||||||
|
|
@ -32,19 +32,24 @@ rm .git
|
||||||
# build rejects empty directories
|
# build rejects empty directories
|
||||||
mkdir t
|
mkdir t
|
||||||
! go build -x
|
! go build -x
|
||||||
stderr 'pattern [*]t: cannot embed directory t: contains no embeddable files'
|
stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$'
|
||||||
|
|
||||||
# build ignores symlinks and invalid names in directories
|
# build ignores symlinks and invalid names in directories
|
||||||
cp x.txt t/.git
|
cp x.txt t/.git
|
||||||
! go build -x
|
! go build -x
|
||||||
stderr 'pattern [*]t: cannot embed directory t: contains no embeddable files'
|
stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$'
|
||||||
[symlink] symlink t/x.link -> ../x.txt
|
[symlink] symlink t/x.link -> ../x.txt
|
||||||
[symlink] ! go build -x
|
[symlink] ! go build -x
|
||||||
[symlink] stderr 'pattern [*]t: cannot embed directory t: contains no embeddable files'
|
[symlink] stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$'
|
||||||
|
|
||||||
cp x.txt t/x.txt
|
cp x.txt t/x.txt
|
||||||
go build -x
|
go build -x
|
||||||
|
|
||||||
|
# build reports errors with positions in imported packages
|
||||||
|
rm t/x.txt
|
||||||
|
! go build m/use
|
||||||
|
stderr '^x.go:5:12: pattern [*]t: cannot embed directory t: contains no embeddable files$'
|
||||||
|
|
||||||
-- x.go --
|
-- x.go --
|
||||||
package p
|
package p
|
||||||
|
|
||||||
|
|
@ -67,6 +72,10 @@ hello
|
||||||
-- x.txt2 --
|
-- x.txt2 --
|
||||||
not hello
|
not hello
|
||||||
|
|
||||||
|
-- use/use.go --
|
||||||
|
package use
|
||||||
|
|
||||||
|
import _ "m"
|
||||||
-- go.mod --
|
-- go.mod --
|
||||||
module m
|
module m
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue