Skip to content

Commit dfc474a

Browse files
committed
loader: support "all:" prefix in //go:embed patterns
The "all:" prefix in //go:embed directives instructs the compiler to include hidden files (starting with "." or "_") when embedding a directory. Previously, the prefix was passed literally to path.Match, which would never match. This change parses the "all:" prefix once in parseGoEmbed and stores it in an embedPattern struct, which carries both the glob pattern and the includeHidden flag through validation and matching. Fixes embedding with patterns like "//go:embed all:static".
1 parent c56c359 commit dfc474a

1 file changed

Lines changed: 27 additions & 27 deletions

File tree

loader/loader.go

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ func (p *Package) extractEmbedLines(addError func(error)) {
549549
}
550550

551551
// Look for //go:embed comments.
552-
var allPatterns []string
552+
var allPatterns []embedPattern
553553
for _, comment := range doc.List {
554554
if comment.Text != "//go:embed" && !strings.HasPrefix(comment.Text, "//go:embed ") {
555555
continue
@@ -577,20 +577,20 @@ func (p *Package) extractEmbedLines(addError func(error)) {
577577
})
578578
continue
579579
}
580-
for _, pattern := range patterns {
580+
for _, ep := range patterns {
581581
// Check that the pattern is well-formed.
582582
// It must be valid: the Go toolchain has already
583583
// checked for invalid patterns. But let's check
584584
// anyway to be sure.
585-
if _, err := path.Match(pattern, ""); err != nil {
585+
if _, err := path.Match(ep.pattern, ""); err != nil {
586586
addError(types.Error{
587587
Fset: p.program.fset,
588588
Pos: comment.Pos(),
589589
Msg: "invalid pattern syntax",
590590
})
591591
continue
592592
}
593-
allPatterns = append(allPatterns, pattern)
593+
allPatterns = append(allPatterns, ep)
594594
}
595595
}
596596

@@ -624,16 +624,8 @@ func (p *Package) extractEmbedLines(addError func(error)) {
624624
// Match all //go:embed patterns against the embed files
625625
// provided by `go list`.
626626
for _, name := range p.EmbedFiles {
627-
for _, pattern := range allPatterns {
628-
// Check for "all:" prefix which includes hidden files.
629-
// See: https://pkg.go.dev/embed#hdr-Directives
630-
includeHidden := false
631-
matchPat := pattern
632-
if strings.HasPrefix(pattern, "all:") {
633-
includeHidden = true
634-
matchPat = pattern[4:] // strip "all:" prefix
635-
}
636-
if matchPattern(matchPat, name, includeHidden) {
627+
for _, ep := range allPatterns {
628+
if matchPattern(ep.pattern, name, ep.includeHidden) {
637629
p.EmbedGlobals[globalName] = append(p.EmbedGlobals[globalName], &EmbedFile{
638630
Name: name,
639631
NeedsData: byteSlice,
@@ -651,8 +643,7 @@ func (p *Package) extractEmbedLines(addError func(error)) {
651643

652644
// matchPattern returns true if (and only if) the given pattern would match the
653645
// filename. The pattern could also match a parent directory of name, in which
654-
// case hidden files do not match (unless includeHidden is true, which happens
655-
// when the pattern had an "all:" prefix).
646+
// case hidden files do not match (unless includeHidden is true).
656647
func matchPattern(pattern, name string, includeHidden bool) bool {
657648
// Match this file.
658649
matched, _ := path.Match(pattern, name)
@@ -690,13 +681,21 @@ func matchPattern(pattern, name string, includeHidden bool) bool {
690681
}
691682
}
692683

684+
// embedPattern represents a parsed //go:embed pattern.
685+
// The "all:" prefix (if present) is stripped and reflected in includeHidden.
686+
type embedPattern struct {
687+
pattern string // the glob pattern (without "all:" prefix)
688+
includeHidden bool // true if "all:" prefix was present
689+
}
690+
693691
// parseGoEmbed is like strings.Fields but for a //go:embed line. It parses
694692
// regular fields and quoted fields (that may contain spaces).
695-
func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []string, err error) {
693+
func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []embedPattern, err error) {
696694
args = strings.TrimSpace(args)
697695
initialLen := len(args)
698696
for args != "" {
699697
patternPos := pos + token.Pos(initialLen-len(args))
698+
var pattern string
700699
switch args[0] {
701700
case '`', '"', '\\':
702701
// Parse the next pattern using the Go scanner.
@@ -715,8 +714,7 @@ func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []string, e
715714
Msg: "invalid quoted string in //go:embed",
716715
}
717716
}
718-
pattern := constant.StringVal(constant.MakeFromLiteral(lit, tok, 0))
719-
patterns = append(patterns, pattern)
717+
pattern = constant.StringVal(constant.MakeFromLiteral(lit, tok, 0))
720718
args = strings.TrimLeftFunc(args[len(lit):], unicode.IsSpace)
721719
default:
722720
// The value is just a regular value.
@@ -725,23 +723,25 @@ func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []string, e
725723
if index < 0 {
726724
index = len(args)
727725
}
728-
pattern := args[:index]
729-
patterns = append(patterns, pattern)
726+
pattern = args[:index]
730727
args = strings.TrimLeftFunc(args[len(pattern):], unicode.IsSpace)
731728
}
732-
// Validate the pattern syntax. Strip "all:" prefix before validation
733-
// since it's a directive, not part of the glob pattern.
734-
validatePattern := patterns[len(patterns)-1]
735-
if strings.HasPrefix(validatePattern, "all:") {
736-
validatePattern = validatePattern[4:]
729+
// Parse the "all:" prefix which includes hidden files.
730+
// See: https://pkg.go.dev/embed#hdr-Directives
731+
ep := embedPattern{pattern: pattern}
732+
if strings.HasPrefix(pattern, "all:") {
733+
ep.pattern = pattern[4:]
734+
ep.includeHidden = true
737735
}
738-
if _, err := path.Match(validatePattern, ""); err != nil {
736+
// Validate the pattern syntax.
737+
if _, err := path.Match(ep.pattern, ""); err != nil {
739738
return nil, types.Error{
740739
Fset: p.program.fset,
741740
Pos: patternPos,
742741
Msg: "invalid pattern syntax",
743742
}
744743
}
744+
patterns = append(patterns, ep)
745745
}
746746
return patterns, nil
747747
}

0 commit comments

Comments
 (0)