1
2
3
4
5
6 package load
7
8 import (
9 "bytes"
10 "context"
11 "encoding/json"
12 "errors"
13 "fmt"
14 "go/build"
15 "go/scanner"
16 "go/token"
17 "internal/goroot"
18 "io/fs"
19 "os"
20 "os/exec"
21 "path"
22 pathpkg "path"
23 "path/filepath"
24 "runtime"
25 "runtime/debug"
26 "sort"
27 "strconv"
28 "strings"
29 "time"
30 "unicode"
31 "unicode/utf8"
32
33 "cmd/go/internal/base"
34 "cmd/go/internal/cfg"
35 "cmd/go/internal/fsys"
36 "cmd/go/internal/imports"
37 "cmd/go/internal/modfetch"
38 "cmd/go/internal/modinfo"
39 "cmd/go/internal/modload"
40 "cmd/go/internal/par"
41 "cmd/go/internal/search"
42 "cmd/go/internal/str"
43 "cmd/go/internal/trace"
44 "cmd/go/internal/vcs"
45 "cmd/internal/sys"
46
47 "golang.org/x/mod/modfile"
48 "golang.org/x/mod/module"
49 )
50
51
52 type Package struct {
53 PackagePublic
54 Internal PackageInternal
55 }
56
57 type PackagePublic struct {
58
59
60
61 Dir string `json:",omitempty"`
62 ImportPath string `json:",omitempty"`
63 ImportComment string `json:",omitempty"`
64 Name string `json:",omitempty"`
65 Doc string `json:",omitempty"`
66 Target string `json:",omitempty"`
67 Shlib string `json:",omitempty"`
68 Root string `json:",omitempty"`
69 ConflictDir string `json:",omitempty"`
70 ForTest string `json:",omitempty"`
71 Export string `json:",omitempty"`
72 BuildID string `json:",omitempty"`
73 Module *modinfo.ModulePublic `json:",omitempty"`
74 Match []string `json:",omitempty"`
75 Goroot bool `json:",omitempty"`
76 Standard bool `json:",omitempty"`
77 DepOnly bool `json:",omitempty"`
78 BinaryOnly bool `json:",omitempty"`
79 Incomplete bool `json:",omitempty"`
80
81
82
83
84 Stale bool `json:",omitempty"`
85 StaleReason string `json:",omitempty"`
86
87
88
89
90 GoFiles []string `json:",omitempty"`
91 CgoFiles []string `json:",omitempty"`
92 CompiledGoFiles []string `json:",omitempty"`
93 IgnoredGoFiles []string `json:",omitempty"`
94 InvalidGoFiles []string `json:",omitempty"`
95 IgnoredOtherFiles []string `json:",omitempty"`
96 CFiles []string `json:",omitempty"`
97 CXXFiles []string `json:",omitempty"`
98 MFiles []string `json:",omitempty"`
99 HFiles []string `json:",omitempty"`
100 FFiles []string `json:",omitempty"`
101 SFiles []string `json:",omitempty"`
102 SwigFiles []string `json:",omitempty"`
103 SwigCXXFiles []string `json:",omitempty"`
104 SysoFiles []string `json:",omitempty"`
105
106
107 EmbedPatterns []string `json:",omitempty"`
108 EmbedFiles []string `json:",omitempty"`
109
110
111 CgoCFLAGS []string `json:",omitempty"`
112 CgoCPPFLAGS []string `json:",omitempty"`
113 CgoCXXFLAGS []string `json:",omitempty"`
114 CgoFFLAGS []string `json:",omitempty"`
115 CgoLDFLAGS []string `json:",omitempty"`
116 CgoPkgConfig []string `json:",omitempty"`
117
118
119 Imports []string `json:",omitempty"`
120 ImportMap map[string]string `json:",omitempty"`
121 Deps []string `json:",omitempty"`
122
123
124
125 Error *PackageError `json:",omitempty"`
126 DepsErrors []*PackageError `json:",omitempty"`
127
128
129
130
131 TestGoFiles []string `json:",omitempty"`
132 TestImports []string `json:",omitempty"`
133 TestEmbedPatterns []string `json:",omitempty"`
134 TestEmbedFiles []string `json:",omitempty"`
135 XTestGoFiles []string `json:",omitempty"`
136 XTestImports []string `json:",omitempty"`
137 XTestEmbedPatterns []string `json:",omitempty"`
138 XTestEmbedFiles []string `json:",omitempty"`
139 }
140
141
142
143
144
145
146 func (p *Package) AllFiles() []string {
147 files := str.StringList(
148 p.GoFiles,
149 p.CgoFiles,
150
151 p.IgnoredGoFiles,
152
153 p.IgnoredOtherFiles,
154 p.CFiles,
155 p.CXXFiles,
156 p.MFiles,
157 p.HFiles,
158 p.FFiles,
159 p.SFiles,
160 p.SwigFiles,
161 p.SwigCXXFiles,
162 p.SysoFiles,
163 p.TestGoFiles,
164 p.XTestGoFiles,
165 )
166
167
168
169
170
171 var have map[string]bool
172 for _, file := range p.EmbedFiles {
173 if !strings.Contains(file, "/") {
174 if have == nil {
175 have = make(map[string]bool)
176 for _, file := range files {
177 have[file] = true
178 }
179 }
180 if have[file] {
181 continue
182 }
183 }
184 files = append(files, file)
185 }
186 return files
187 }
188
189
190 func (p *Package) Desc() string {
191 if p.ForTest != "" {
192 return p.ImportPath + " [" + p.ForTest + ".test]"
193 }
194 return p.ImportPath
195 }
196
197
198
199
200
201
202
203 func (p *Package) IsTestOnly() bool {
204 return p.ForTest != "" ||
205 p.Internal.TestmainGo != nil ||
206 len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 && len(p.GoFiles)+len(p.CgoFiles) == 0
207 }
208
209 type PackageInternal struct {
210
211 Build *build.Package
212 Imports []*Package
213 CompiledImports []string
214 RawImports []string
215 ForceLibrary bool
216 CmdlineFiles bool
217 CmdlinePkg bool
218 CmdlinePkgLiteral bool
219 Local bool
220 LocalPrefix string
221 ExeName string
222 FuzzInstrument bool
223 CoverMode string
224 CoverVars map[string]*CoverVar
225 OmitDebug bool
226 GobinSubdir bool
227 BuildInfo string
228 TestmainGo *[]byte
229 Embed map[string][]string
230 OrigImportPath string
231
232 Asmflags []string
233 Gcflags []string
234 Ldflags []string
235 Gccgoflags []string
236 }
237
238
239
240
241
242
243 type NoGoError struct {
244 Package *Package
245 }
246
247 func (e *NoGoError) Error() string {
248 if len(e.Package.IgnoredGoFiles) > 0 {
249
250 return "build constraints exclude all Go files in " + e.Package.Dir
251 }
252 if len(e.Package.TestGoFiles)+len(e.Package.XTestGoFiles) > 0 {
253
254
255
256 return "no non-test Go files in " + e.Package.Dir
257 }
258 return "no Go files in " + e.Package.Dir
259 }
260
261
262
263
264
265
266
267
268 func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportStack, importPos []token.Position) {
269 matchErr, isMatchErr := err.(*search.MatchError)
270 if isMatchErr && matchErr.Match.Pattern() == path {
271 if matchErr.Match.IsLiteral() {
272
273
274
275
276 err = matchErr.Err
277 }
278 }
279
280
281
282 var nogoErr *build.NoGoError
283 if errors.As(err, &nogoErr) {
284 if p.Dir == "" && nogoErr.Dir != "" {
285 p.Dir = nogoErr.Dir
286 }
287 err = &NoGoError{Package: p}
288 }
289
290
291
292
293 var pos string
294 var isScanErr bool
295 if scanErr, ok := err.(scanner.ErrorList); ok && len(scanErr) > 0 {
296 isScanErr = true
297
298 scanPos := scanErr[0].Pos
299 scanPos.Filename = base.ShortPath(scanPos.Filename)
300 pos = scanPos.String()
301 err = errors.New(scanErr[0].Msg)
302 }
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319 if !isMatchErr && (nogoErr != nil || isScanErr) {
320 stk.Push(path)
321 defer stk.Pop()
322 }
323
324 p.Error = &PackageError{
325 ImportStack: stk.Copy(),
326 Pos: pos,
327 Err: err,
328 }
329
330 if path != stk.Top() {
331 p.Error.setPos(importPos)
332 }
333 }
334
335
336
337
338
339
340
341
342
343
344
345 func (p *Package) Resolve(imports []string) []string {
346 if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
347 panic("internal error: p.Resolve(p.Imports) called")
348 }
349 seen := make(map[string]bool)
350 var all []string
351 for _, path := range imports {
352 path = ResolveImportPath(p, path)
353 if !seen[path] {
354 seen[path] = true
355 all = append(all, path)
356 }
357 }
358 sort.Strings(all)
359 return all
360 }
361
362
363 type CoverVar struct {
364 File string
365 Var string
366 }
367
368 func (p *Package) copyBuild(opts PackageOpts, pp *build.Package) {
369 p.Internal.Build = pp
370
371 if pp.PkgTargetRoot != "" && cfg.BuildPkgdir != "" {
372 old := pp.PkgTargetRoot
373 pp.PkgRoot = cfg.BuildPkgdir
374 pp.PkgTargetRoot = cfg.BuildPkgdir
375 pp.PkgObj = filepath.Join(cfg.BuildPkgdir, strings.TrimPrefix(pp.PkgObj, old))
376 }
377
378 p.Dir = pp.Dir
379 p.ImportPath = pp.ImportPath
380 p.ImportComment = pp.ImportComment
381 p.Name = pp.Name
382 p.Doc = pp.Doc
383 p.Root = pp.Root
384 p.ConflictDir = pp.ConflictDir
385 p.BinaryOnly = pp.BinaryOnly
386
387
388 p.Goroot = pp.Goroot
389 p.Standard = p.Goroot && p.ImportPath != "" && search.IsStandardImportPath(p.ImportPath)
390 p.GoFiles = pp.GoFiles
391 p.CgoFiles = pp.CgoFiles
392 p.IgnoredGoFiles = pp.IgnoredGoFiles
393 p.InvalidGoFiles = pp.InvalidGoFiles
394 p.IgnoredOtherFiles = pp.IgnoredOtherFiles
395 p.CFiles = pp.CFiles
396 p.CXXFiles = pp.CXXFiles
397 p.MFiles = pp.MFiles
398 p.HFiles = pp.HFiles
399 p.FFiles = pp.FFiles
400 p.SFiles = pp.SFiles
401 p.SwigFiles = pp.SwigFiles
402 p.SwigCXXFiles = pp.SwigCXXFiles
403 p.SysoFiles = pp.SysoFiles
404 p.CgoCFLAGS = pp.CgoCFLAGS
405 p.CgoCPPFLAGS = pp.CgoCPPFLAGS
406 p.CgoCXXFLAGS = pp.CgoCXXFLAGS
407 p.CgoFFLAGS = pp.CgoFFLAGS
408 p.CgoLDFLAGS = pp.CgoLDFLAGS
409 p.CgoPkgConfig = pp.CgoPkgConfig
410
411 p.Imports = make([]string, len(pp.Imports))
412 copy(p.Imports, pp.Imports)
413 p.Internal.RawImports = pp.Imports
414 p.TestGoFiles = pp.TestGoFiles
415 p.TestImports = pp.TestImports
416 p.XTestGoFiles = pp.XTestGoFiles
417 p.XTestImports = pp.XTestImports
418 if opts.IgnoreImports {
419 p.Imports = nil
420 p.Internal.RawImports = nil
421 p.TestImports = nil
422 p.XTestImports = nil
423 }
424 p.EmbedPatterns = pp.EmbedPatterns
425 p.TestEmbedPatterns = pp.TestEmbedPatterns
426 p.XTestEmbedPatterns = pp.XTestEmbedPatterns
427 p.Internal.OrigImportPath = pp.ImportPath
428 }
429
430
431 type PackageError struct {
432 ImportStack []string
433 Pos string
434 Err error
435 IsImportCycle bool
436 Hard bool
437 alwaysPrintStack bool
438 }
439
440 func (p *PackageError) Error() string {
441
442
443
444 if p.Pos != "" && (len(p.ImportStack) == 0 || !p.alwaysPrintStack) {
445
446
447 return p.Pos + ": " + p.Err.Error()
448 }
449
450
451
452
453
454
455
456 if len(p.ImportStack) == 0 {
457 return p.Err.Error()
458 }
459 var optpos string
460 if p.Pos != "" {
461 optpos = "\n\t" + p.Pos
462 }
463 return "package " + strings.Join(p.ImportStack, "\n\timports ") + optpos + ": " + p.Err.Error()
464 }
465
466 func (p *PackageError) Unwrap() error { return p.Err }
467
468
469
470 func (p *PackageError) MarshalJSON() ([]byte, error) {
471 perr := struct {
472 ImportStack []string
473 Pos string
474 Err string
475 }{p.ImportStack, p.Pos, p.Err.Error()}
476 return json.Marshal(perr)
477 }
478
479 func (p *PackageError) setPos(posList []token.Position) {
480 if len(posList) == 0 {
481 return
482 }
483 pos := posList[0]
484 pos.Filename = base.ShortPath(pos.Filename)
485 p.Pos = pos.String()
486 }
487
488
489
490
491
492
493
494
495
496 type ImportPathError interface {
497 error
498 ImportPath() string
499 }
500
501 var (
502 _ ImportPathError = (*importError)(nil)
503 _ ImportPathError = (*mainPackageError)(nil)
504 _ ImportPathError = (*modload.ImportMissingError)(nil)
505 _ ImportPathError = (*modload.ImportMissingSumError)(nil)
506 _ ImportPathError = (*modload.DirectImportFromImplicitDependencyError)(nil)
507 )
508
509 type importError struct {
510 importPath string
511 err error
512 }
513
514 func ImportErrorf(path, format string, args ...any) ImportPathError {
515 err := &importError{importPath: path, err: fmt.Errorf(format, args...)}
516 if errStr := err.Error(); !strings.Contains(errStr, path) {
517 panic(fmt.Sprintf("path %q not in error %q", path, errStr))
518 }
519 return err
520 }
521
522 func (e *importError) Error() string {
523 return e.err.Error()
524 }
525
526 func (e *importError) Unwrap() error {
527
528
529 return errors.Unwrap(e.err)
530 }
531
532 func (e *importError) ImportPath() string {
533 return e.importPath
534 }
535
536
537
538
539 type ImportStack []string
540
541 func (s *ImportStack) Push(p string) {
542 *s = append(*s, p)
543 }
544
545 func (s *ImportStack) Pop() {
546 *s = (*s)[0 : len(*s)-1]
547 }
548
549 func (s *ImportStack) Copy() []string {
550 return append([]string{}, *s...)
551 }
552
553 func (s *ImportStack) Top() string {
554 if len(*s) == 0 {
555 return ""
556 }
557 return (*s)[len(*s)-1]
558 }
559
560
561
562
563 func (sp *ImportStack) shorterThan(t []string) bool {
564 s := *sp
565 if len(s) != len(t) {
566 return len(s) < len(t)
567 }
568
569 for i := range s {
570 if s[i] != t[i] {
571 return s[i] < t[i]
572 }
573 }
574 return false
575 }
576
577
578
579
580 var packageCache = map[string]*Package{}
581
582
583
584
585 func ClearPackageCache() {
586 for name := range packageCache {
587 delete(packageCache, name)
588 }
589 resolvedImportCache.Clear()
590 packageDataCache.Clear()
591 }
592
593
594
595
596
597 func ClearPackageCachePartial(args []string) {
598 shouldDelete := make(map[string]bool)
599 for _, arg := range args {
600 shouldDelete[arg] = true
601 if p := packageCache[arg]; p != nil {
602 delete(packageCache, arg)
603 }
604 }
605 resolvedImportCache.DeleteIf(func(key any) bool {
606 return shouldDelete[key.(importSpec).path]
607 })
608 packageDataCache.DeleteIf(func(key any) bool {
609 return shouldDelete[key.(string)]
610 })
611 }
612
613
614
615
616
617 func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package {
618 p := packageCache[arg]
619 if p != nil {
620 delete(packageCache, arg)
621 resolvedImportCache.DeleteIf(func(key any) bool {
622 return key.(importSpec).path == p.ImportPath
623 })
624 packageDataCache.Delete(p.ImportPath)
625 }
626 return LoadImport(context.TODO(), PackageOpts{}, arg, base.Cwd(), nil, stk, nil, 0)
627 }
628
629
630
631
632
633
634
635
636 func dirToImportPath(dir string) string {
637 return pathpkg.Join("_", strings.Map(makeImportValid, filepath.ToSlash(dir)))
638 }
639
640 func makeImportValid(r rune) rune {
641
642 const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
643 if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
644 return '_'
645 }
646 return r
647 }
648
649
650 const (
651
652
653
654
655
656
657
658
659
660 ResolveImport = 1 << iota
661
662
663
664 ResolveModule
665
666
667
668 GetTestDeps
669 )
670
671
672
673
674
675
676
677
678 func LoadImport(ctx context.Context, opts PackageOpts, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
679 return loadImport(ctx, opts, nil, path, srcDir, parent, stk, importPos, mode)
680 }
681
682 func loadImport(ctx context.Context, opts PackageOpts, pre *preload, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
683 if path == "" {
684 panic("LoadImport called with empty package path")
685 }
686
687 var parentPath, parentRoot string
688 parentIsStd := false
689 if parent != nil {
690 parentPath = parent.ImportPath
691 parentRoot = parent.Root
692 parentIsStd = parent.Standard
693 }
694 bp, loaded, err := loadPackageData(ctx, path, parentPath, srcDir, parentRoot, parentIsStd, mode)
695 if loaded && pre != nil && !opts.IgnoreImports {
696 pre.preloadImports(ctx, opts, bp.Imports, bp)
697 }
698 if bp == nil {
699 p := &Package{
700 PackagePublic: PackagePublic{
701 ImportPath: path,
702 Incomplete: true,
703 },
704 }
705 if importErr, ok := err.(ImportPathError); !ok || importErr.ImportPath() != path {
706
707
708
709
710
711
712
713 stk.Push(path)
714 defer stk.Pop()
715 }
716 p.setLoadPackageDataError(err, path, stk, nil)
717 return p
718 }
719
720 importPath := bp.ImportPath
721 p := packageCache[importPath]
722 if p != nil {
723 stk.Push(path)
724 p = reusePackage(p, stk)
725 stk.Pop()
726 } else {
727 p = new(Package)
728 p.Internal.Local = build.IsLocalImport(path)
729 p.ImportPath = importPath
730 packageCache[importPath] = p
731
732
733
734
735 p.load(ctx, opts, path, stk, importPos, bp, err)
736
737 if !cfg.ModulesEnabled && path != cleanImport(path) {
738 p.Error = &PackageError{
739 ImportStack: stk.Copy(),
740 Err: ImportErrorf(path, "non-canonical import path %q: should be %q", path, pathpkg.Clean(path)),
741 }
742 p.Incomplete = true
743 p.Error.setPos(importPos)
744 }
745 }
746
747
748 if perr := disallowInternal(ctx, srcDir, parent, parentPath, p, stk); perr != p {
749 perr.Error.setPos(importPos)
750 return perr
751 }
752 if mode&ResolveImport != 0 {
753 if perr := disallowVendor(srcDir, path, parentPath, p, stk); perr != p {
754 perr.Error.setPos(importPos)
755 return perr
756 }
757 }
758
759 if p.Name == "main" && parent != nil && parent.Dir != p.Dir {
760 perr := *p
761 perr.Error = &PackageError{
762 ImportStack: stk.Copy(),
763 Err: ImportErrorf(path, "import %q is a program, not an importable package", path),
764 }
765 perr.Error.setPos(importPos)
766 return &perr
767 }
768
769 if p.Internal.Local && parent != nil && !parent.Internal.Local {
770 perr := *p
771 var err error
772 if path == "." {
773 err = ImportErrorf(path, "%s: cannot import current directory", path)
774 } else {
775 err = ImportErrorf(path, "local import %q in non-local package", path)
776 }
777 perr.Error = &PackageError{
778 ImportStack: stk.Copy(),
779 Err: err,
780 }
781 perr.Error.setPos(importPos)
782 return &perr
783 }
784
785 return p
786 }
787
788
789
790
791
792
793
794
795
796
797 func loadPackageData(ctx context.Context, path, parentPath, parentDir, parentRoot string, parentIsStd bool, mode int) (bp *build.Package, loaded bool, err error) {
798 if path == "" {
799 panic("loadPackageData called with empty package path")
800 }
801
802 if strings.HasPrefix(path, "mod/") {
803
804
805
806
807
808 return nil, false, fmt.Errorf("disallowed import path %q", path)
809 }
810
811 if strings.Contains(path, "@") {
812 return nil, false, errors.New("can only use path@version syntax with 'go get' and 'go install' in module-aware mode")
813 }
814
815
816
817
818
819
820
821
822
823
824
825 importKey := importSpec{
826 path: path,
827 parentPath: parentPath,
828 parentDir: parentDir,
829 parentRoot: parentRoot,
830 parentIsStd: parentIsStd,
831 mode: mode,
832 }
833 r := resolvedImportCache.Do(importKey, func() any {
834 var r resolvedImport
835 if cfg.ModulesEnabled {
836 r.dir, r.path, r.err = modload.Lookup(parentPath, parentIsStd, path)
837 } else if build.IsLocalImport(path) {
838 r.dir = filepath.Join(parentDir, path)
839 r.path = dirToImportPath(r.dir)
840 } else if mode&ResolveImport != 0 {
841
842
843
844
845 r.path = resolveImportPath(path, parentPath, parentDir, parentRoot, parentIsStd)
846 } else if mode&ResolveModule != 0 {
847 r.path = moduleImportPath(path, parentPath, parentDir, parentRoot)
848 }
849 if r.path == "" {
850 r.path = path
851 }
852 return r
853 }).(resolvedImport)
854
855
856
857
858
859
860 data := packageDataCache.Do(r.path, func() any {
861 loaded = true
862 var data packageData
863 if r.dir != "" {
864 var buildMode build.ImportMode
865 if !cfg.ModulesEnabled {
866 buildMode = build.ImportComment
867 }
868 data.p, data.err = cfg.BuildContext.ImportDir(r.dir, buildMode)
869 if cfg.ModulesEnabled {
870
871
872 if info := modload.PackageModuleInfo(ctx, path); info != nil {
873 data.p.Root = info.Dir
874 }
875 }
876 if r.err != nil {
877 if data.err != nil {
878
879
880
881
882 } else if errors.Is(r.err, imports.ErrNoGo) {
883
884
885
886
887
888
889
890
891
892
893 } else {
894 data.err = r.err
895 }
896 }
897 } else if r.err != nil {
898 data.p = new(build.Package)
899 data.err = r.err
900 } else if cfg.ModulesEnabled && path != "unsafe" {
901 data.p = new(build.Package)
902 data.err = fmt.Errorf("unknown import path %q: internal error: module loader did not resolve import", r.path)
903 } else {
904 buildMode := build.ImportComment
905 if mode&ResolveImport == 0 || r.path != path {
906
907 buildMode |= build.IgnoreVendor
908 }
909 data.p, data.err = cfg.BuildContext.Import(r.path, parentDir, buildMode)
910 }
911 data.p.ImportPath = r.path
912
913
914
915 if !data.p.Goroot {
916 if cfg.GOBIN != "" {
917 data.p.BinDir = cfg.GOBIN
918 } else if cfg.ModulesEnabled {
919 data.p.BinDir = modload.BinDir()
920 }
921 }
922
923 if !cfg.ModulesEnabled && data.err == nil &&
924 data.p.ImportComment != "" && data.p.ImportComment != path &&
925 !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
926 data.err = fmt.Errorf("code in directory %s expects import %q", data.p.Dir, data.p.ImportComment)
927 }
928 return data
929 }).(packageData)
930
931 return data.p, loaded, data.err
932 }
933
934
935
936 type importSpec struct {
937 path string
938 parentPath, parentDir, parentRoot string
939 parentIsStd bool
940 mode int
941 }
942
943
944
945
946 type resolvedImport struct {
947 path, dir string
948 err error
949 }
950
951
952
953 type packageData struct {
954 p *build.Package
955 err error
956 }
957
958
959
960 var resolvedImportCache par.Cache
961
962
963
964 var packageDataCache par.Cache
965
966
967
968
969
970
971
972
973
974
975
976
977
978 var preloadWorkerCount = runtime.GOMAXPROCS(0)
979
980
981
982
983
984
985
986
987
988
989 type preload struct {
990 cancel chan struct{}
991 sema chan struct{}
992 }
993
994
995
996 func newPreload() *preload {
997 pre := &preload{
998 cancel: make(chan struct{}),
999 sema: make(chan struct{}, preloadWorkerCount),
1000 }
1001 return pre
1002 }
1003
1004
1005
1006
1007 func (pre *preload) preloadMatches(ctx context.Context, opts PackageOpts, matches []*search.Match) {
1008 for _, m := range matches {
1009 for _, pkg := range m.Pkgs {
1010 select {
1011 case <-pre.cancel:
1012 return
1013 case pre.sema <- struct{}{}:
1014 go func(pkg string) {
1015 mode := 0
1016 bp, loaded, err := loadPackageData(ctx, pkg, "", base.Cwd(), "", false, mode)
1017 <-pre.sema
1018 if bp != nil && loaded && err == nil && !opts.IgnoreImports {
1019 pre.preloadImports(ctx, opts, bp.Imports, bp)
1020 }
1021 }(pkg)
1022 }
1023 }
1024 }
1025 }
1026
1027
1028
1029
1030 func (pre *preload) preloadImports(ctx context.Context, opts PackageOpts, imports []string, parent *build.Package) {
1031 parentIsStd := parent.Goroot && parent.ImportPath != "" && search.IsStandardImportPath(parent.ImportPath)
1032 for _, path := range imports {
1033 if path == "C" || path == "unsafe" {
1034 continue
1035 }
1036 select {
1037 case <-pre.cancel:
1038 return
1039 case pre.sema <- struct{}{}:
1040 go func(path string) {
1041 bp, loaded, err := loadPackageData(ctx, path, parent.ImportPath, parent.Dir, parent.Root, parentIsStd, ResolveImport)
1042 <-pre.sema
1043 if bp != nil && loaded && err == nil && !opts.IgnoreImports {
1044 pre.preloadImports(ctx, opts, bp.Imports, bp)
1045 }
1046 }(path)
1047 }
1048 }
1049 }
1050
1051
1052
1053
1054 func (pre *preload) flush() {
1055
1056
1057 if v := recover(); v != nil {
1058 panic(v)
1059 }
1060
1061 close(pre.cancel)
1062 for i := 0; i < preloadWorkerCount; i++ {
1063 pre.sema <- struct{}{}
1064 }
1065 }
1066
1067 func cleanImport(path string) string {
1068 orig := path
1069 path = pathpkg.Clean(path)
1070 if strings.HasPrefix(orig, "./") && path != ".." && !strings.HasPrefix(path, "../") {
1071 path = "./" + path
1072 }
1073 return path
1074 }
1075
1076 var isDirCache par.Cache
1077
1078 func isDir(path string) bool {
1079 return isDirCache.Do(path, func() any {
1080 fi, err := fsys.Stat(path)
1081 return err == nil && fi.IsDir()
1082 }).(bool)
1083 }
1084
1085
1086
1087
1088
1089
1090 func ResolveImportPath(parent *Package, path string) (found string) {
1091 var parentPath, parentDir, parentRoot string
1092 parentIsStd := false
1093 if parent != nil {
1094 parentPath = parent.ImportPath
1095 parentDir = parent.Dir
1096 parentRoot = parent.Root
1097 parentIsStd = parent.Standard
1098 }
1099 return resolveImportPath(path, parentPath, parentDir, parentRoot, parentIsStd)
1100 }
1101
1102 func resolveImportPath(path, parentPath, parentDir, parentRoot string, parentIsStd bool) (found string) {
1103 if cfg.ModulesEnabled {
1104 if _, p, e := modload.Lookup(parentPath, parentIsStd, path); e == nil {
1105 return p
1106 }
1107 return path
1108 }
1109 found = vendoredImportPath(path, parentPath, parentDir, parentRoot)
1110 if found != path {
1111 return found
1112 }
1113 return moduleImportPath(path, parentPath, parentDir, parentRoot)
1114 }
1115
1116
1117
1118 func dirAndRoot(path string, dir, root string) (string, string) {
1119 origDir, origRoot := dir, root
1120 dir = filepath.Clean(dir)
1121 root = filepath.Join(root, "src")
1122 if !str.HasFilePathPrefix(dir, root) || path != "command-line-arguments" && filepath.Join(root, path) != dir {
1123
1124 dir = expandPath(dir)
1125 root = expandPath(root)
1126 }
1127
1128 if !str.HasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator || path != "command-line-arguments" && !build.IsLocalImport(path) && filepath.Join(root, path) != dir {
1129 debug.PrintStack()
1130 base.Fatalf("unexpected directory layout:\n"+
1131 " import path: %s\n"+
1132 " root: %s\n"+
1133 " dir: %s\n"+
1134 " expand root: %s\n"+
1135 " expand dir: %s\n"+
1136 " separator: %s",
1137 path,
1138 filepath.Join(origRoot, "src"),
1139 filepath.Clean(origDir),
1140 origRoot,
1141 origDir,
1142 string(filepath.Separator))
1143 }
1144
1145 return dir, root
1146 }
1147
1148
1149
1150
1151
1152 func vendoredImportPath(path, parentPath, parentDir, parentRoot string) (found string) {
1153 if parentRoot == "" {
1154 return path
1155 }
1156
1157 dir, root := dirAndRoot(parentPath, parentDir, parentRoot)
1158
1159 vpath := "vendor/" + path
1160 for i := len(dir); i >= len(root); i-- {
1161 if i < len(dir) && dir[i] != filepath.Separator {
1162 continue
1163 }
1164
1165
1166
1167
1168 if !isDir(filepath.Join(dir[:i], "vendor")) {
1169 continue
1170 }
1171 targ := filepath.Join(dir[:i], vpath)
1172 if isDir(targ) && hasGoFiles(targ) {
1173 importPath := parentPath
1174 if importPath == "command-line-arguments" {
1175
1176
1177 importPath = dir[len(root)+1:]
1178 }
1179
1180
1181
1182
1183
1184
1185
1186
1187 chopped := len(dir) - i
1188 if chopped == len(importPath)+1 {
1189
1190
1191
1192
1193 return vpath
1194 }
1195 return importPath[:len(importPath)-chopped] + "/" + vpath
1196 }
1197 }
1198 return path
1199 }
1200
1201 var (
1202 modulePrefix = []byte("\nmodule ")
1203 goModPathCache par.Cache
1204 )
1205
1206
1207 func goModPath(dir string) (path string) {
1208 return goModPathCache.Do(dir, func() any {
1209 data, err := os.ReadFile(filepath.Join(dir, "go.mod"))
1210 if err != nil {
1211 return ""
1212 }
1213 var i int
1214 if bytes.HasPrefix(data, modulePrefix[1:]) {
1215 i = 0
1216 } else {
1217 i = bytes.Index(data, modulePrefix)
1218 if i < 0 {
1219 return ""
1220 }
1221 i++
1222 }
1223 line := data[i:]
1224
1225
1226 if j := bytes.IndexByte(line, '\n'); j >= 0 {
1227 line = line[:j]
1228 }
1229 if line[len(line)-1] == '\r' {
1230 line = line[:len(line)-1]
1231 }
1232 line = line[len("module "):]
1233
1234
1235 path = strings.TrimSpace(string(line))
1236 if path != "" && path[0] == '"' {
1237 s, err := strconv.Unquote(path)
1238 if err != nil {
1239 return ""
1240 }
1241 path = s
1242 }
1243 return path
1244 }).(string)
1245 }
1246
1247
1248
1249 func findVersionElement(path string) (i, j int) {
1250 j = len(path)
1251 for i = len(path) - 1; i >= 0; i-- {
1252 if path[i] == '/' {
1253 if isVersionElement(path[i+1 : j]) {
1254 return i, j
1255 }
1256 j = i
1257 }
1258 }
1259 return -1, -1
1260 }
1261
1262
1263
1264 func isVersionElement(s string) bool {
1265 if len(s) < 2 || s[0] != 'v' || s[1] == '0' || s[1] == '1' && len(s) == 2 {
1266 return false
1267 }
1268 for i := 1; i < len(s); i++ {
1269 if s[i] < '0' || '9' < s[i] {
1270 return false
1271 }
1272 }
1273 return true
1274 }
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284 func moduleImportPath(path, parentPath, parentDir, parentRoot string) (found string) {
1285 if parentRoot == "" {
1286 return path
1287 }
1288
1289
1290
1291
1292
1293 if i, _ := findVersionElement(path); i < 0 {
1294 return path
1295 }
1296
1297 dir, root := dirAndRoot(parentPath, parentDir, parentRoot)
1298
1299
1300 for i := len(dir); i >= len(root); i-- {
1301 if i < len(dir) && dir[i] != filepath.Separator {
1302 continue
1303 }
1304 if goModPath(dir[:i]) != "" {
1305 goto HaveGoMod
1306 }
1307 }
1308
1309
1310 return path
1311
1312 HaveGoMod:
1313
1314
1315
1316
1317
1318 if bp, _ := cfg.BuildContext.Import(path, "", build.IgnoreVendor); bp.Dir != "" {
1319 return path
1320 }
1321
1322
1323
1324
1325
1326
1327 limit := len(path)
1328 for limit > 0 {
1329 i, j := findVersionElement(path[:limit])
1330 if i < 0 {
1331 return path
1332 }
1333 if bp, _ := cfg.BuildContext.Import(path[:i], "", build.IgnoreVendor); bp.Dir != "" {
1334 if mpath := goModPath(bp.Dir); mpath != "" {
1335
1336
1337
1338 if mpath == path[:j] {
1339 return path[:i] + path[j:]
1340 }
1341
1342
1343
1344
1345 return path
1346 }
1347 }
1348 limit = i
1349 }
1350 return path
1351 }
1352
1353
1354
1355
1356
1357 func hasGoFiles(dir string) bool {
1358 files, _ := os.ReadDir(dir)
1359 for _, f := range files {
1360 if !f.IsDir() && strings.HasSuffix(f.Name(), ".go") {
1361 return true
1362 }
1363 }
1364 return false
1365 }
1366
1367
1368
1369
1370 func reusePackage(p *Package, stk *ImportStack) *Package {
1371
1372
1373
1374 if p.Internal.Imports == nil {
1375 if p.Error == nil {
1376 p.Error = &PackageError{
1377 ImportStack: stk.Copy(),
1378 Err: errors.New("import cycle not allowed"),
1379 IsImportCycle: true,
1380 }
1381 } else if !p.Error.IsImportCycle {
1382
1383
1384
1385 p.Error.IsImportCycle = true
1386 }
1387 p.Incomplete = true
1388 }
1389
1390
1391 if p.Error != nil && !p.Error.IsImportCycle && stk.shorterThan(p.Error.ImportStack) {
1392 p.Error.ImportStack = stk.Copy()
1393 }
1394 return p
1395 }
1396
1397
1398
1399
1400
1401 func disallowInternal(ctx context.Context, srcDir string, importer *Package, importerPath string, p *Package, stk *ImportStack) *Package {
1402
1403
1404
1405
1406
1407
1408 if p.Error != nil {
1409 return p
1410 }
1411
1412
1413
1414
1415
1416 if str.HasPathPrefix(p.ImportPath, "testing/internal") && importerPath == "testmain" {
1417 return p
1418 }
1419
1420
1421 if cfg.BuildContext.Compiler == "gccgo" && p.Standard {
1422 return p
1423 }
1424
1425
1426
1427
1428 if p.Standard && strings.HasPrefix(importerPath, "bootstrap/") {
1429 return p
1430 }
1431
1432
1433
1434
1435 if importerPath == "" {
1436 return p
1437 }
1438
1439
1440 i, ok := findInternal(p.ImportPath)
1441 if !ok {
1442 return p
1443 }
1444
1445
1446
1447 if i > 0 {
1448 i--
1449 }
1450
1451 if p.Module == nil {
1452 parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)]
1453
1454 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1455 return p
1456 }
1457
1458
1459 srcDir = expandPath(srcDir)
1460 parent = expandPath(parent)
1461 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1462 return p
1463 }
1464 } else {
1465
1466
1467 if importer.Internal.CmdlineFiles {
1468
1469
1470
1471
1472
1473 importerPath, _ = modload.MainModules.DirImportPath(ctx, importer.Dir)
1474 }
1475 parentOfInternal := p.ImportPath[:i]
1476 if str.HasPathPrefix(importerPath, parentOfInternal) {
1477 return p
1478 }
1479 }
1480
1481
1482 perr := *p
1483 perr.Error = &PackageError{
1484 alwaysPrintStack: true,
1485 ImportStack: stk.Copy(),
1486 Err: ImportErrorf(p.ImportPath, "use of internal package "+p.ImportPath+" not allowed"),
1487 }
1488 perr.Incomplete = true
1489 return &perr
1490 }
1491
1492
1493
1494
1495 func findInternal(path string) (index int, ok bool) {
1496
1497
1498
1499
1500 switch {
1501 case strings.HasSuffix(path, "/internal"):
1502 return len(path) - len("internal"), true
1503 case strings.Contains(path, "/internal/"):
1504 return strings.LastIndex(path, "/internal/") + 1, true
1505 case path == "internal", strings.HasPrefix(path, "internal/"):
1506 return 0, true
1507 }
1508 return 0, false
1509 }
1510
1511
1512
1513
1514 func disallowVendor(srcDir string, path string, importerPath string, p *Package, stk *ImportStack) *Package {
1515
1516
1517
1518 if importerPath == "" {
1519 return p
1520 }
1521
1522 if perr := disallowVendorVisibility(srcDir, p, importerPath, stk); perr != p {
1523 return perr
1524 }
1525
1526
1527 if i, ok := FindVendor(path); ok {
1528 perr := *p
1529 perr.Error = &PackageError{
1530 ImportStack: stk.Copy(),
1531 Err: ImportErrorf(path, "%s must be imported as %s", path, path[i+len("vendor/"):]),
1532 }
1533 perr.Incomplete = true
1534 return &perr
1535 }
1536
1537 return p
1538 }
1539
1540
1541
1542
1543
1544
1545 func disallowVendorVisibility(srcDir string, p *Package, importerPath string, stk *ImportStack) *Package {
1546
1547
1548
1549
1550 if importerPath == "" {
1551 return p
1552 }
1553
1554
1555 i, ok := FindVendor(p.ImportPath)
1556 if !ok {
1557 return p
1558 }
1559
1560
1561
1562 if i > 0 {
1563 i--
1564 }
1565 truncateTo := i + len(p.Dir) - len(p.ImportPath)
1566 if truncateTo < 0 || len(p.Dir) < truncateTo {
1567 return p
1568 }
1569 parent := p.Dir[:truncateTo]
1570 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1571 return p
1572 }
1573
1574
1575 srcDir = expandPath(srcDir)
1576 parent = expandPath(parent)
1577 if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) {
1578 return p
1579 }
1580
1581
1582 perr := *p
1583 perr.Error = &PackageError{
1584 ImportStack: stk.Copy(),
1585 Err: errors.New("use of vendored package not allowed"),
1586 }
1587 perr.Incomplete = true
1588 return &perr
1589 }
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599 func FindVendor(path string) (index int, ok bool) {
1600
1601
1602
1603 switch {
1604 case strings.Contains(path, "/vendor/"):
1605 return strings.LastIndex(path, "/vendor/") + 1, true
1606 case strings.HasPrefix(path, "vendor/"):
1607 return 0, true
1608 }
1609 return 0, false
1610 }
1611
1612 type TargetDir int
1613
1614 const (
1615 ToTool TargetDir = iota
1616 ToBin
1617 StalePath
1618 )
1619
1620
1621 func InstallTargetDir(p *Package) TargetDir {
1622 if strings.HasPrefix(p.ImportPath, "code.google.com/p/go.tools/cmd/") {
1623 return StalePath
1624 }
1625 if p.Goroot && strings.HasPrefix(p.ImportPath, "cmd/") && p.Name == "main" {
1626 switch p.ImportPath {
1627 case "cmd/go", "cmd/gofmt":
1628 return ToBin
1629 }
1630 return ToTool
1631 }
1632 return ToBin
1633 }
1634
1635 var cgoExclude = map[string]bool{
1636 "runtime/cgo": true,
1637 }
1638
1639 var cgoSyscallExclude = map[string]bool{
1640 "runtime/cgo": true,
1641 "runtime/race": true,
1642 "runtime/msan": true,
1643 "runtime/asan": true,
1644 }
1645
1646 var foldPath = make(map[string]string)
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656 func (p *Package) exeFromImportPath() string {
1657 _, elem := pathpkg.Split(p.ImportPath)
1658 if cfg.ModulesEnabled {
1659
1660
1661 if elem != p.ImportPath && isVersionElement(elem) {
1662 _, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
1663 }
1664 }
1665 return elem
1666 }
1667
1668
1669
1670
1671
1672 func (p *Package) exeFromFiles() string {
1673 var src string
1674 if len(p.GoFiles) > 0 {
1675 src = p.GoFiles[0]
1676 } else if len(p.CgoFiles) > 0 {
1677 src = p.CgoFiles[0]
1678 } else {
1679 return ""
1680 }
1681 _, elem := filepath.Split(src)
1682 return elem[:len(elem)-len(".go")]
1683 }
1684
1685
1686 func (p *Package) DefaultExecName() string {
1687 if p.Internal.CmdlineFiles {
1688 return p.exeFromFiles()
1689 }
1690 return p.exeFromImportPath()
1691 }
1692
1693
1694
1695
1696 func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) {
1697 p.copyBuild(opts, bp)
1698
1699
1700
1701
1702 if p.Internal.Local && !cfg.ModulesEnabled {
1703 p.Internal.LocalPrefix = dirToImportPath(p.Dir)
1704 }
1705
1706
1707
1708
1709 setError := func(err error) {
1710 if p.Error == nil {
1711 p.Error = &PackageError{
1712 ImportStack: stk.Copy(),
1713 Err: err,
1714 }
1715
1716
1717
1718
1719
1720
1721
1722 if path != stk.Top() && len(importPos) > 0 {
1723 p.Error.setPos(importPos)
1724 }
1725 }
1726 }
1727
1728 if err != nil {
1729 p.Incomplete = true
1730 p.setLoadPackageDataError(err, path, stk, importPos)
1731 }
1732
1733 useBindir := p.Name == "main"
1734 if !p.Standard {
1735 switch cfg.BuildBuildmode {
1736 case "c-archive", "c-shared", "plugin":
1737 useBindir = false
1738 }
1739 }
1740
1741 if useBindir {
1742
1743 if InstallTargetDir(p) == StalePath {
1744
1745
1746 newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
1747 e := ImportErrorf(p.ImportPath, "the %v command has moved; use %v instead.", p.ImportPath, newPath)
1748 setError(e)
1749 return
1750 }
1751 elem := p.DefaultExecName()
1752 full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
1753 if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
1754
1755 elem = full
1756 }
1757 if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled {
1758 p.Internal.Build.BinDir = modload.BinDir()
1759 }
1760 if p.Internal.Build.BinDir != "" {
1761
1762 p.Target = filepath.Join(p.Internal.Build.BinDir, elem)
1763 if !p.Goroot && strings.Contains(elem, "/") && cfg.GOBIN != "" {
1764
1765 p.Target = ""
1766 p.Internal.GobinSubdir = true
1767 }
1768 }
1769 if InstallTargetDir(p) == ToTool {
1770
1771
1772 if cfg.BuildToolchainName == "gccgo" {
1773 p.Target = filepath.Join(base.ToolDir, elem)
1774 } else {
1775 p.Target = filepath.Join(cfg.GOROOTpkg, "tool", full)
1776 }
1777 }
1778 if p.Target != "" && cfg.BuildContext.GOOS == "windows" {
1779 p.Target += ".exe"
1780 }
1781 } else if p.Internal.Local {
1782
1783
1784 p.Target = ""
1785 } else {
1786 p.Target = p.Internal.Build.PkgObj
1787 if cfg.BuildLinkshared && p.Target != "" {
1788
1789
1790
1791 shlibnamefile := p.Target[:len(p.Target)-2] + ".shlibname"
1792 shlib, err := os.ReadFile(shlibnamefile)
1793 if err != nil && !os.IsNotExist(err) {
1794 base.Fatalf("reading shlibname: %v", err)
1795 }
1796 if err == nil {
1797 libname := strings.TrimSpace(string(shlib))
1798 if cfg.BuildContext.Compiler == "gccgo" {
1799 p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, "shlibs", libname)
1800 } else {
1801 p.Shlib = filepath.Join(p.Internal.Build.PkgTargetRoot, libname)
1802 }
1803 }
1804 }
1805 }
1806
1807
1808
1809 importPaths := p.Imports
1810 addImport := func(path string, forCompiler bool) {
1811 for _, p := range importPaths {
1812 if path == p {
1813 return
1814 }
1815 }
1816 importPaths = append(importPaths, path)
1817 if forCompiler {
1818 p.Internal.CompiledImports = append(p.Internal.CompiledImports, path)
1819 }
1820 }
1821
1822 if !opts.IgnoreImports {
1823
1824
1825 if p.UsesCgo() {
1826 addImport("unsafe", true)
1827 }
1828 if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" {
1829 addImport("runtime/cgo", true)
1830 }
1831 if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
1832 addImport("syscall", true)
1833 }
1834
1835
1836 if p.UsesSwig() {
1837 addImport("unsafe", true)
1838 if cfg.BuildContext.Compiler != "gccgo" {
1839 addImport("runtime/cgo", true)
1840 }
1841 addImport("syscall", true)
1842 addImport("sync", true)
1843
1844
1845
1846 }
1847
1848
1849 if p.Name == "main" && !p.Internal.ForceLibrary {
1850 for _, dep := range LinkerDeps(p) {
1851 addImport(dep, false)
1852 }
1853 }
1854 }
1855
1856
1857 fold := str.ToFold(p.ImportPath)
1858 if other := foldPath[fold]; other == "" {
1859 foldPath[fold] = p.ImportPath
1860 } else if other != p.ImportPath {
1861 setError(ImportErrorf(p.ImportPath, "case-insensitive import collision: %q and %q", p.ImportPath, other))
1862 return
1863 }
1864
1865 if !SafeArg(p.ImportPath) {
1866 setError(ImportErrorf(p.ImportPath, "invalid import path %q", p.ImportPath))
1867 return
1868 }
1869
1870
1871
1872
1873 stk.Push(path)
1874 defer stk.Pop()
1875
1876 pkgPath := p.ImportPath
1877 if p.Internal.CmdlineFiles {
1878 pkgPath = "command-line-arguments"
1879 }
1880 if cfg.ModulesEnabled {
1881 p.Module = modload.PackageModuleInfo(ctx, pkgPath)
1882 }
1883
1884 p.EmbedFiles, p.Internal.Embed, err = resolveEmbed(p.Dir, p.EmbedPatterns)
1885 if err != nil {
1886 p.Incomplete = true
1887 setError(err)
1888 embedErr := err.(*EmbedError)
1889 p.Error.setPos(p.Internal.Build.EmbedPatternPos[embedErr.Pattern])
1890 }
1891
1892
1893
1894
1895
1896 inputs := p.AllFiles()
1897 f1, f2 := str.FoldDup(inputs)
1898 if f1 != "" {
1899 setError(fmt.Errorf("case-insensitive file name collision: %q and %q", f1, f2))
1900 return
1901 }
1902
1903
1904
1905
1906
1907
1908
1909
1910 for _, file := range inputs {
1911 if !SafeArg(file) || strings.HasPrefix(file, "_cgo_") {
1912 setError(fmt.Errorf("invalid input file name %q", file))
1913 return
1914 }
1915 }
1916 if name := pathpkg.Base(p.ImportPath); !SafeArg(name) {
1917 setError(fmt.Errorf("invalid input directory name %q", name))
1918 return
1919 }
1920
1921
1922 imports := make([]*Package, 0, len(p.Imports))
1923 for i, path := range importPaths {
1924 if path == "C" {
1925 continue
1926 }
1927 p1 := LoadImport(ctx, opts, path, p.Dir, p, stk, p.Internal.Build.ImportPos[path], ResolveImport)
1928
1929 path = p1.ImportPath
1930 importPaths[i] = path
1931 if i < len(p.Imports) {
1932 p.Imports[i] = path
1933 }
1934
1935 imports = append(imports, p1)
1936 if p1.Incomplete {
1937 p.Incomplete = true
1938 }
1939 }
1940 p.Internal.Imports = imports
1941 p.collectDeps()
1942 if p.Error == nil && p.Name == "main" && !p.Internal.ForceLibrary && len(p.DepsErrors) == 0 {
1943
1944
1945
1946
1947 p.setBuildInfo(opts.LoadVCS)
1948 }
1949
1950
1951 if p.Standard && (p.ImportPath == "unsafe" || cfg.BuildContext.Compiler == "gccgo") {
1952 p.Target = ""
1953 }
1954
1955
1956
1957 if !cfg.BuildContext.CgoEnabled {
1958 p.CFiles = nil
1959 p.CXXFiles = nil
1960 p.MFiles = nil
1961 p.SwigFiles = nil
1962 p.SwigCXXFiles = nil
1963
1964
1965
1966
1967 }
1968
1969
1970 if len(p.CFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() && cfg.BuildContext.Compiler == "gc" {
1971 setError(fmt.Errorf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")))
1972 return
1973 }
1974
1975
1976
1977 if len(p.CXXFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
1978 setError(fmt.Errorf("C++ source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CXXFiles, " ")))
1979 return
1980 }
1981 if len(p.MFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
1982 setError(fmt.Errorf("Objective-C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.MFiles, " ")))
1983 return
1984 }
1985 if len(p.FFiles) > 0 && !p.UsesCgo() && !p.UsesSwig() {
1986 setError(fmt.Errorf("Fortran source files not allowed when not using cgo or SWIG: %s", strings.Join(p.FFiles, " ")))
1987 return
1988 }
1989 }
1990
1991
1992 type EmbedError struct {
1993 Pattern string
1994 Err error
1995 }
1996
1997 func (e *EmbedError) Error() string {
1998 return fmt.Sprintf("pattern %s: %v", e.Pattern, e.Err)
1999 }
2000
2001 func (e *EmbedError) Unwrap() error {
2002 return e.Err
2003 }
2004
2005
2006
2007
2008
2009
2010 func ResolveEmbed(dir string, patterns []string) ([]string, error) {
2011 files, _, err := resolveEmbed(dir, patterns)
2012 return files, err
2013 }
2014
2015
2016
2017
2018
2019 func resolveEmbed(pkgdir string, patterns []string) (files []string, pmap map[string][]string, err error) {
2020 var pattern string
2021 defer func() {
2022 if err != nil {
2023 err = &EmbedError{
2024 Pattern: pattern,
2025 Err: err,
2026 }
2027 }
2028 }()
2029
2030
2031 pmap = make(map[string][]string)
2032 have := make(map[string]int)
2033 dirOK := make(map[string]bool)
2034 pid := 0
2035 for _, pattern = range patterns {
2036 pid++
2037
2038 glob := pattern
2039 all := strings.HasPrefix(pattern, "all:")
2040 if all {
2041 glob = pattern[len("all:"):]
2042 }
2043
2044 if _, err := path.Match(glob, ""); err != nil || !validEmbedPattern(glob) {
2045 return nil, nil, fmt.Errorf("invalid pattern syntax")
2046 }
2047
2048
2049 match, err := fsys.Glob(pkgdir + string(filepath.Separator) + filepath.FromSlash(glob))
2050 if err != nil {
2051 return nil, nil, err
2052 }
2053
2054
2055
2056
2057
2058 var list []string
2059 for _, file := range match {
2060 rel := filepath.ToSlash(file[len(pkgdir)+1:])
2061
2062 what := "file"
2063 info, err := fsys.Lstat(file)
2064 if err != nil {
2065 return nil, nil, err
2066 }
2067 if info.IsDir() {
2068 what = "directory"
2069 }
2070
2071
2072
2073 for dir := file; len(dir) > len(pkgdir)+1 && !dirOK[dir]; dir = filepath.Dir(dir) {
2074 if _, err := fsys.Stat(filepath.Join(dir, "go.mod")); err == nil {
2075 return nil, nil, fmt.Errorf("cannot embed %s %s: in different module", what, rel)
2076 }
2077 if dir != file {
2078 if info, err := fsys.Lstat(dir); err == nil && !info.IsDir() {
2079 return nil, nil, fmt.Errorf("cannot embed %s %s: in non-directory %s", what, rel, dir[len(pkgdir)+1:])
2080 }
2081 }
2082 dirOK[dir] = true
2083 if elem := filepath.Base(dir); isBadEmbedName(elem) {
2084 if dir == file {
2085 return nil, nil, fmt.Errorf("cannot embed %s %s: invalid name %s", what, rel, elem)
2086 } else {
2087 return nil, nil, fmt.Errorf("cannot embed %s %s: in invalid directory %s", what, rel, elem)
2088 }
2089 }
2090 }
2091
2092 switch {
2093 default:
2094 return nil, nil, fmt.Errorf("cannot embed irregular file %s", rel)
2095
2096 case info.Mode().IsRegular():
2097 if have[rel] != pid {
2098 have[rel] = pid
2099 list = append(list, rel)
2100 }
2101
2102 case info.IsDir():
2103
2104
2105 count := 0
2106 err := fsys.Walk(file, func(path string, info os.FileInfo, err error) error {
2107 if err != nil {
2108 return err
2109 }
2110 rel := filepath.ToSlash(path[len(pkgdir)+1:])
2111 name := info.Name()
2112 if path != file && (isBadEmbedName(name) || ((name[0] == '.' || name[0] == '_') && !all)) {
2113
2114
2115
2116 if info.IsDir() {
2117 return fs.SkipDir
2118 }
2119 return nil
2120 }
2121 if info.IsDir() {
2122 if _, err := fsys.Stat(filepath.Join(path, "go.mod")); err == nil {
2123 return filepath.SkipDir
2124 }
2125 return nil
2126 }
2127 if !info.Mode().IsRegular() {
2128 return nil
2129 }
2130 count++
2131 if have[rel] != pid {
2132 have[rel] = pid
2133 list = append(list, rel)
2134 }
2135 return nil
2136 })
2137 if err != nil {
2138 return nil, nil, err
2139 }
2140 if count == 0 {
2141 return nil, nil, fmt.Errorf("cannot embed directory %s: contains no embeddable files", rel)
2142 }
2143 }
2144 }
2145
2146 if len(list) == 0 {
2147 return nil, nil, fmt.Errorf("no matching files found")
2148 }
2149 sort.Strings(list)
2150 pmap[pattern] = list
2151 }
2152
2153 for file := range have {
2154 files = append(files, file)
2155 }
2156 sort.Strings(files)
2157 return files, pmap, nil
2158 }
2159
2160 func validEmbedPattern(pattern string) bool {
2161 return pattern != "." && fs.ValidPath(pattern)
2162 }
2163
2164
2165
2166
2167 func isBadEmbedName(name string) bool {
2168 if err := module.CheckFilePath(name); err != nil {
2169 return true
2170 }
2171 switch name {
2172
2173 case "":
2174 return true
2175
2176 case ".bzr", ".hg", ".git", ".svn":
2177 return true
2178 }
2179 return false
2180 }
2181
2182
2183
2184
2185
2186
2187 func (p *Package) collectDeps() {
2188 deps := make(map[string]*Package)
2189 var q []*Package
2190 q = append(q, p.Internal.Imports...)
2191 for i := 0; i < len(q); i++ {
2192 p1 := q[i]
2193 path := p1.ImportPath
2194
2195
2196
2197 p0 := deps[path]
2198 if p0 == nil || p1.Error != nil && (p0.Error == nil || len(p0.Error.ImportStack) > len(p1.Error.ImportStack)) {
2199 deps[path] = p1
2200 for _, p2 := range p1.Internal.Imports {
2201 if deps[p2.ImportPath] != p2 {
2202 q = append(q, p2)
2203 }
2204 }
2205 }
2206 }
2207
2208 p.Deps = make([]string, 0, len(deps))
2209 for dep := range deps {
2210 p.Deps = append(p.Deps, dep)
2211 }
2212 sort.Strings(p.Deps)
2213 for _, dep := range p.Deps {
2214 p1 := deps[dep]
2215 if p1 == nil {
2216 panic("impossible: missing entry in package cache for " + dep + " imported by " + p.ImportPath)
2217 }
2218 if p1.Error != nil {
2219 p.DepsErrors = append(p.DepsErrors, p1.Error)
2220 }
2221 }
2222 }
2223
2224
2225
2226 var vcsStatusCache par.Cache
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236 func (p *Package) setBuildInfo(includeVCS bool) {
2237
2238
2239
2240
2241
2242 setPkgErrorf := func(format string, args ...any) {
2243 if p.Error == nil {
2244 p.Error = &PackageError{Err: fmt.Errorf(format, args...)}
2245 }
2246 }
2247
2248 var debugModFromModinfo func(*modinfo.ModulePublic) *debug.Module
2249 debugModFromModinfo = func(mi *modinfo.ModulePublic) *debug.Module {
2250 version := mi.Version
2251 if version == "" {
2252 version = "(devel)"
2253 }
2254 dm := &debug.Module{
2255 Path: mi.Path,
2256 Version: version,
2257 }
2258 if mi.Replace != nil {
2259 dm.Replace = debugModFromModinfo(mi.Replace)
2260 } else if mi.Version != "" {
2261 dm.Sum = modfetch.Sum(module.Version{Path: mi.Path, Version: mi.Version})
2262 }
2263 return dm
2264 }
2265
2266 var main debug.Module
2267 if p.Module != nil {
2268 main = *debugModFromModinfo(p.Module)
2269 }
2270
2271 visited := make(map[*Package]bool)
2272 mdeps := make(map[module.Version]*debug.Module)
2273 var q []*Package
2274 q = append(q, p.Internal.Imports...)
2275 for len(q) > 0 {
2276 p1 := q[0]
2277 q = q[1:]
2278 if visited[p1] {
2279 continue
2280 }
2281 visited[p1] = true
2282 if p1.Module != nil {
2283 m := module.Version{Path: p1.Module.Path, Version: p1.Module.Version}
2284 if p1.Module.Path != main.Path && mdeps[m] == nil {
2285 mdeps[m] = debugModFromModinfo(p1.Module)
2286 }
2287 }
2288 q = append(q, p1.Internal.Imports...)
2289 }
2290 sortedMods := make([]module.Version, 0, len(mdeps))
2291 for mod := range mdeps {
2292 sortedMods = append(sortedMods, mod)
2293 }
2294 module.Sort(sortedMods)
2295 deps := make([]*debug.Module, len(sortedMods))
2296 for i, mod := range sortedMods {
2297 deps[i] = mdeps[mod]
2298 }
2299
2300 pkgPath := p.ImportPath
2301 if p.Internal.CmdlineFiles {
2302 pkgPath = "command-line-arguments"
2303 }
2304 info := &debug.BuildInfo{
2305 Path: pkgPath,
2306 Main: main,
2307 Deps: deps,
2308 }
2309 appendSetting := func(key, value string) {
2310 value = strings.ReplaceAll(value, "\n", " ")
2311 info.Settings = append(info.Settings, debug.BuildSetting{Key: key, Value: value})
2312 }
2313
2314
2315
2316
2317 if !p.Standard {
2318 if cfg.BuildASan {
2319 appendSetting("-asan", "true")
2320 }
2321 if BuildAsmflags.present {
2322 appendSetting("-asmflags", BuildAsmflags.String())
2323 }
2324 appendSetting("-compiler", cfg.BuildContext.Compiler)
2325 if BuildGccgoflags.present && cfg.BuildContext.Compiler == "gccgo" {
2326 appendSetting("-gccgoflags", BuildGccgoflags.String())
2327 }
2328 if BuildGcflags.present && cfg.BuildContext.Compiler == "gc" {
2329 appendSetting("-gcflags", BuildGcflags.String())
2330 }
2331 if BuildLdflags.present {
2332 appendSetting("-ldflags", BuildLdflags.String())
2333 }
2334 if cfg.BuildMSan {
2335 appendSetting("-msan", "true")
2336 }
2337 if cfg.BuildRace {
2338 appendSetting("-race", "true")
2339 }
2340 if tags := cfg.BuildContext.BuildTags; len(tags) > 0 {
2341 appendSetting("-tags", strings.Join(tags, ","))
2342 }
2343 cgo := "0"
2344 if cfg.BuildContext.CgoEnabled {
2345 cgo = "1"
2346 }
2347 appendSetting("CGO_ENABLED", cgo)
2348 if cfg.BuildContext.CgoEnabled {
2349 for _, name := range []string{"CGO_CFLAGS", "CGO_CPPFLAGS", "CGO_CXXFLAGS", "CGO_LDFLAGS"} {
2350 appendSetting(name, cfg.Getenv(name))
2351 }
2352 }
2353 appendSetting("GOARCH", cfg.BuildContext.GOARCH)
2354 if cfg.GOEXPERIMENT != "" {
2355 appendSetting("GOEXPERIMENT", cfg.GOEXPERIMENT)
2356 }
2357 appendSetting("GOOS", cfg.BuildContext.GOOS)
2358 if key, val := cfg.GetArchEnv(); key != "" && val != "" {
2359 appendSetting(key, val)
2360 }
2361 }
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371 setVCSError := func(err error) {
2372 setPkgErrorf("error obtaining VCS status: %v\n\tUse -buildvcs=false to disable VCS stamping.", err)
2373 }
2374
2375 var repoDir string
2376 var vcsCmd *vcs.Cmd
2377 var err error
2378 const allowNesting = true
2379 if includeVCS && cfg.BuildBuildvcs != "false" && p.Module != nil && p.Module.Version == "" && !p.Standard && !p.IsTestOnly() {
2380 repoDir, vcsCmd, err = vcs.FromDir(base.Cwd(), "", allowNesting)
2381 if err != nil && !errors.Is(err, os.ErrNotExist) {
2382 setVCSError(err)
2383 return
2384 }
2385 if !str.HasFilePathPrefix(p.Module.Dir, repoDir) &&
2386 !str.HasFilePathPrefix(repoDir, p.Module.Dir) {
2387
2388
2389
2390
2391 goto omitVCS
2392 }
2393 if cfg.BuildBuildvcs == "auto" && vcsCmd != nil && vcsCmd.Cmd != "" {
2394 if _, err := exec.LookPath(vcsCmd.Cmd); err != nil {
2395
2396
2397 goto omitVCS
2398 }
2399 }
2400 }
2401 if repoDir != "" && vcsCmd.Status != nil {
2402
2403
2404
2405
2406 pkgRepoDir, _, err := vcs.FromDir(p.Dir, "", allowNesting)
2407 if err != nil {
2408 setVCSError(err)
2409 return
2410 }
2411 if pkgRepoDir != repoDir {
2412 if cfg.BuildBuildvcs != "auto" {
2413 setVCSError(fmt.Errorf("main package is in repository %q but current directory is in repository %q", pkgRepoDir, repoDir))
2414 return
2415 }
2416 goto omitVCS
2417 }
2418 modRepoDir, _, err := vcs.FromDir(p.Module.Dir, "", allowNesting)
2419 if err != nil {
2420 setVCSError(err)
2421 return
2422 }
2423 if modRepoDir != repoDir {
2424 if cfg.BuildBuildvcs != "auto" {
2425 setVCSError(fmt.Errorf("main module is in repository %q but current directory is in repository %q", modRepoDir, repoDir))
2426 return
2427 }
2428 goto omitVCS
2429 }
2430
2431 type vcsStatusError struct {
2432 Status vcs.Status
2433 Err error
2434 }
2435 cached := vcsStatusCache.Do(repoDir, func() any {
2436 st, err := vcsCmd.Status(vcsCmd, repoDir)
2437 return vcsStatusError{st, err}
2438 }).(vcsStatusError)
2439 if err := cached.Err; err != nil {
2440 setVCSError(err)
2441 return
2442 }
2443 st := cached.Status
2444
2445 appendSetting("vcs", vcsCmd.Cmd)
2446 if st.Revision != "" {
2447 appendSetting("vcs.revision", st.Revision)
2448 }
2449 if !st.CommitTime.IsZero() {
2450 stamp := st.CommitTime.UTC().Format(time.RFC3339Nano)
2451 appendSetting("vcs.time", stamp)
2452 }
2453 appendSetting("vcs.modified", strconv.FormatBool(st.Uncommitted))
2454 }
2455 omitVCS:
2456
2457 p.Internal.BuildInfo = info.String()
2458 }
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469 func SafeArg(name string) bool {
2470 if name == "" {
2471 return false
2472 }
2473 c := name[0]
2474 return '0' <= c && c <= '9' || 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '.' || c == '_' || c == '/' || c >= utf8.RuneSelf
2475 }
2476
2477
2478 func LinkerDeps(p *Package) []string {
2479
2480 deps := []string{"runtime"}
2481
2482
2483 if externalLinkingForced(p) && cfg.BuildContext.Compiler != "gccgo" {
2484 deps = append(deps, "runtime/cgo")
2485 }
2486
2487 if cfg.Goarch == "arm" {
2488 deps = append(deps, "math")
2489 }
2490
2491 if cfg.BuildRace {
2492 deps = append(deps, "runtime/race")
2493 }
2494
2495 if cfg.BuildMSan {
2496 deps = append(deps, "runtime/msan")
2497 }
2498
2499 if cfg.BuildASan {
2500 deps = append(deps, "runtime/asan")
2501 }
2502
2503 return deps
2504 }
2505
2506
2507
2508 func externalLinkingForced(p *Package) bool {
2509 if !cfg.BuildContext.CgoEnabled {
2510 return false
2511 }
2512
2513
2514 switch cfg.BuildContext.GOOS {
2515 case "android":
2516 if cfg.BuildContext.GOARCH != "arm64" {
2517 return true
2518 }
2519 case "ios":
2520 return true
2521 }
2522
2523
2524
2525
2526
2527
2528
2529
2530 pieCgo := cfg.BuildBuildmode == "pie" && !sys.InternalLinkPIESupported(cfg.BuildContext.GOOS, cfg.BuildContext.GOARCH)
2531 linkmodeExternal := false
2532 if p != nil {
2533 ldflags := BuildLdflags.For(p)
2534 for i := len(ldflags) - 1; i >= 0; i-- {
2535 a := ldflags[i]
2536 if a == "-linkmode=external" ||
2537 a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "external" {
2538 linkmodeExternal = true
2539 break
2540 } else if a == "-linkmode=internal" ||
2541 a == "-linkmode" && i+1 < len(ldflags) && ldflags[i+1] == "internal" {
2542 break
2543 }
2544 }
2545 }
2546
2547 return cfg.BuildBuildmode == "c-shared" || cfg.BuildBuildmode == "plugin" || pieCgo || cfg.BuildLinkshared || linkmodeExternal
2548 }
2549
2550
2551
2552
2553 func (p *Package) mkAbs(list []string) []string {
2554 for i, f := range list {
2555 list[i] = filepath.Join(p.Dir, f)
2556 }
2557 sort.Strings(list)
2558 return list
2559 }
2560
2561
2562
2563 func (p *Package) InternalGoFiles() []string {
2564 return p.mkAbs(str.StringList(p.GoFiles, p.CgoFiles, p.TestGoFiles))
2565 }
2566
2567
2568
2569 func (p *Package) InternalXGoFiles() []string {
2570 return p.mkAbs(p.XTestGoFiles)
2571 }
2572
2573
2574
2575
2576 func (p *Package) InternalAllGoFiles() []string {
2577 return p.mkAbs(str.StringList(p.IgnoredGoFiles, p.GoFiles, p.CgoFiles, p.TestGoFiles, p.XTestGoFiles))
2578 }
2579
2580
2581 func (p *Package) UsesSwig() bool {
2582 return len(p.SwigFiles) > 0 || len(p.SwigCXXFiles) > 0
2583 }
2584
2585
2586 func (p *Package) UsesCgo() bool {
2587 return len(p.CgoFiles) > 0
2588 }
2589
2590
2591
2592 func PackageList(roots []*Package) []*Package {
2593 seen := map[*Package]bool{}
2594 all := []*Package{}
2595 var walk func(*Package)
2596 walk = func(p *Package) {
2597 if seen[p] {
2598 return
2599 }
2600 seen[p] = true
2601 for _, p1 := range p.Internal.Imports {
2602 walk(p1)
2603 }
2604 all = append(all, p)
2605 }
2606 for _, root := range roots {
2607 walk(root)
2608 }
2609 return all
2610 }
2611
2612
2613
2614
2615 func TestPackageList(ctx context.Context, opts PackageOpts, roots []*Package) []*Package {
2616 seen := map[*Package]bool{}
2617 all := []*Package{}
2618 var walk func(*Package)
2619 walk = func(p *Package) {
2620 if seen[p] {
2621 return
2622 }
2623 seen[p] = true
2624 for _, p1 := range p.Internal.Imports {
2625 walk(p1)
2626 }
2627 all = append(all, p)
2628 }
2629 walkTest := func(root *Package, path string) {
2630 var stk ImportStack
2631 p1 := LoadImport(ctx, opts, path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport)
2632 if p1.Error == nil {
2633 walk(p1)
2634 }
2635 }
2636 for _, root := range roots {
2637 walk(root)
2638 for _, path := range root.TestImports {
2639 walkTest(root, path)
2640 }
2641 for _, path := range root.XTestImports {
2642 walkTest(root, path)
2643 }
2644 }
2645 return all
2646 }
2647
2648
2649
2650
2651
2652
2653 func LoadImportWithFlags(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package {
2654 p := LoadImport(context.TODO(), PackageOpts{}, path, srcDir, parent, stk, importPos, mode)
2655 setToolFlags(p)
2656 return p
2657 }
2658
2659
2660
2661 type PackageOpts struct {
2662
2663
2664
2665 IgnoreImports bool
2666
2667
2668
2669
2670
2671
2672
2673
2674 ModResolveTests bool
2675
2676
2677
2678
2679
2680
2681 MainOnly bool
2682
2683
2684 LoadVCS bool
2685 }
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695 func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string) []*Package {
2696 ctx, span := trace.StartSpan(ctx, "load.PackagesAndErrors")
2697 defer span.Done()
2698
2699 for _, p := range patterns {
2700
2701
2702
2703 if strings.HasSuffix(p, ".go") {
2704
2705
2706 if fi, err := fsys.Stat(p); err == nil && !fi.IsDir() {
2707 return []*Package{GoFilesPackage(ctx, opts, patterns)}
2708 }
2709 }
2710 }
2711
2712 var matches []*search.Match
2713 if modload.Init(); cfg.ModulesEnabled {
2714 modOpts := modload.PackageOpts{
2715 ResolveMissingImports: true,
2716 LoadTests: opts.ModResolveTests,
2717 SilencePackageErrors: true,
2718 }
2719 matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
2720 } else {
2721 noModRoots := []string{}
2722 matches = search.ImportPaths(patterns, noModRoots)
2723 }
2724
2725 var (
2726 pkgs []*Package
2727 stk ImportStack
2728 seenPkg = make(map[*Package]bool)
2729 )
2730
2731 pre := newPreload()
2732 defer pre.flush()
2733 pre.preloadMatches(ctx, opts, matches)
2734
2735 for _, m := range matches {
2736 for _, pkg := range m.Pkgs {
2737 if pkg == "" {
2738 panic(fmt.Sprintf("ImportPaths returned empty package for pattern %s", m.Pattern()))
2739 }
2740 p := loadImport(ctx, opts, pre, pkg, base.Cwd(), nil, &stk, nil, 0)
2741 p.Match = append(p.Match, m.Pattern())
2742 p.Internal.CmdlinePkg = true
2743 if m.IsLiteral() {
2744
2745
2746
2747 p.Internal.CmdlinePkgLiteral = true
2748 }
2749 if seenPkg[p] {
2750 continue
2751 }
2752 seenPkg[p] = true
2753 pkgs = append(pkgs, p)
2754 }
2755
2756 if len(m.Errs) > 0 {
2757
2758
2759
2760 p := new(Package)
2761 p.ImportPath = m.Pattern()
2762
2763 var stk ImportStack
2764 var importPos []token.Position
2765 p.setLoadPackageDataError(m.Errs[0], m.Pattern(), &stk, importPos)
2766 p.Incomplete = true
2767 p.Match = append(p.Match, m.Pattern())
2768 p.Internal.CmdlinePkg = true
2769 if m.IsLiteral() {
2770 p.Internal.CmdlinePkgLiteral = true
2771 }
2772 pkgs = append(pkgs, p)
2773 }
2774 }
2775
2776 if opts.MainOnly {
2777 pkgs = mainPackagesOnly(pkgs, matches)
2778 }
2779
2780
2781
2782
2783
2784 setToolFlags(pkgs...)
2785
2786 return pkgs
2787 }
2788
2789
2790
2791 func CheckPackageErrors(pkgs []*Package) {
2792 printed := map[*PackageError]bool{}
2793 for _, pkg := range pkgs {
2794 if pkg.Error != nil {
2795 base.Errorf("%v", pkg.Error)
2796 printed[pkg.Error] = true
2797 }
2798 for _, err := range pkg.DepsErrors {
2799
2800
2801
2802
2803 if !printed[err] {
2804 printed[err] = true
2805 base.Errorf("%v", err)
2806 }
2807 }
2808 }
2809 base.ExitIfErrors()
2810
2811
2812
2813
2814
2815
2816 seen := map[string]bool{}
2817 reported := map[string]bool{}
2818 for _, pkg := range PackageList(pkgs) {
2819 if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
2820 reported[pkg.ImportPath] = true
2821 base.Errorf("internal error: duplicate loads of %s", pkg.ImportPath)
2822 }
2823 seen[pkg.ImportPath] = true
2824 }
2825 base.ExitIfErrors()
2826 }
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839 func mainPackagesOnly(pkgs []*Package, matches []*search.Match) []*Package {
2840 treatAsMain := map[string]bool{}
2841 for _, m := range matches {
2842 if m.IsLiteral() {
2843 for _, path := range m.Pkgs {
2844 treatAsMain[path] = true
2845 }
2846 }
2847 }
2848
2849 var mains []*Package
2850 for _, pkg := range pkgs {
2851 if pkg.Name == "main" {
2852 treatAsMain[pkg.ImportPath] = true
2853 mains = append(mains, pkg)
2854 continue
2855 }
2856
2857 if len(pkg.InvalidGoFiles) > 0 {
2858
2859
2860
2861 treatAsMain[pkg.ImportPath] = true
2862 }
2863 if treatAsMain[pkg.ImportPath] {
2864 if pkg.Error == nil {
2865 pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
2866 }
2867 mains = append(mains, pkg)
2868 }
2869 }
2870
2871 for _, m := range matches {
2872 if m.IsLiteral() || len(m.Pkgs) == 0 {
2873 continue
2874 }
2875 foundMain := false
2876 for _, path := range m.Pkgs {
2877 if treatAsMain[path] {
2878 foundMain = true
2879 break
2880 }
2881 }
2882 if !foundMain {
2883 fmt.Fprintf(os.Stderr, "go: warning: %q matched only non-main packages\n", m.Pattern())
2884 }
2885 }
2886
2887 return mains
2888 }
2889
2890 type mainPackageError struct {
2891 importPath string
2892 }
2893
2894 func (e *mainPackageError) Error() string {
2895 return fmt.Sprintf("package %s is not a main package", e.importPath)
2896 }
2897
2898 func (e *mainPackageError) ImportPath() string {
2899 return e.importPath
2900 }
2901
2902 func setToolFlags(pkgs ...*Package) {
2903 for _, p := range PackageList(pkgs) {
2904 p.Internal.Asmflags = BuildAsmflags.For(p)
2905 p.Internal.Gcflags = BuildGcflags.For(p)
2906 p.Internal.Ldflags = BuildLdflags.For(p)
2907 p.Internal.Gccgoflags = BuildGccgoflags.For(p)
2908 }
2909 }
2910
2911
2912
2913
2914 func GoFilesPackage(ctx context.Context, opts PackageOpts, gofiles []string) *Package {
2915 modload.Init()
2916
2917 for _, f := range gofiles {
2918 if !strings.HasSuffix(f, ".go") {
2919 pkg := new(Package)
2920 pkg.Internal.Local = true
2921 pkg.Internal.CmdlineFiles = true
2922 pkg.Name = f
2923 pkg.Error = &PackageError{
2924 Err: fmt.Errorf("named files must be .go files: %s", pkg.Name),
2925 }
2926 return pkg
2927 }
2928 }
2929
2930 var stk ImportStack
2931 ctxt := cfg.BuildContext
2932 ctxt.UseAllFiles = true
2933
2934
2935
2936
2937
2938 var dirent []fs.FileInfo
2939 var dir string
2940 for _, file := range gofiles {
2941 fi, err := fsys.Stat(file)
2942 if err != nil {
2943 base.Fatalf("%s", err)
2944 }
2945 if fi.IsDir() {
2946 base.Fatalf("%s is a directory, should be a Go file", file)
2947 }
2948 dir1 := filepath.Dir(file)
2949 if dir == "" {
2950 dir = dir1
2951 } else if dir != dir1 {
2952 base.Fatalf("named files must all be in one directory; have %s and %s", dir, dir1)
2953 }
2954 dirent = append(dirent, fi)
2955 }
2956 ctxt.ReadDir = func(string) ([]fs.FileInfo, error) { return dirent, nil }
2957
2958 if cfg.ModulesEnabled {
2959 modload.ImportFromFiles(ctx, gofiles)
2960 }
2961
2962 var err error
2963 if dir == "" {
2964 dir = base.Cwd()
2965 }
2966 dir, err = filepath.Abs(dir)
2967 if err != nil {
2968 base.Fatalf("%s", err)
2969 }
2970
2971 bp, err := ctxt.ImportDir(dir, 0)
2972 pkg := new(Package)
2973 pkg.Internal.Local = true
2974 pkg.Internal.CmdlineFiles = true
2975 pkg.load(ctx, opts, "command-line-arguments", &stk, nil, bp, err)
2976 if !cfg.ModulesEnabled {
2977 pkg.Internal.LocalPrefix = dirToImportPath(dir)
2978 }
2979 pkg.ImportPath = "command-line-arguments"
2980 pkg.Target = ""
2981 pkg.Match = gofiles
2982
2983 if pkg.Name == "main" {
2984 exe := pkg.DefaultExecName() + cfg.ExeSuffix
2985
2986 if cfg.GOBIN != "" {
2987 pkg.Target = filepath.Join(cfg.GOBIN, exe)
2988 } else if cfg.ModulesEnabled {
2989 pkg.Target = filepath.Join(modload.BinDir(), exe)
2990 }
2991 }
2992
2993 if opts.MainOnly && pkg.Name != "main" && pkg.Error == nil {
2994 pkg.Error = &PackageError{Err: &mainPackageError{importPath: pkg.ImportPath}}
2995 }
2996 setToolFlags(pkg)
2997
2998 return pkg
2999 }
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016 func PackagesAndErrorsOutsideModule(ctx context.Context, opts PackageOpts, args []string) ([]*Package, error) {
3017 if !modload.ForceUseModules {
3018 panic("modload.ForceUseModules must be true")
3019 }
3020 if modload.RootMode != modload.NoRoot {
3021 panic("modload.RootMode must be NoRoot")
3022 }
3023
3024
3025 var version string
3026 for _, arg := range args {
3027 if i := strings.Index(arg, "@"); i >= 0 {
3028 version = arg[i+1:]
3029 if version == "" {
3030 return nil, fmt.Errorf("%s: version must not be empty", arg)
3031 }
3032 break
3033 }
3034 }
3035 patterns := make([]string, len(args))
3036 for i, arg := range args {
3037 if !strings.HasSuffix(arg, "@"+version) {
3038 return nil, fmt.Errorf("%s: all arguments must have the same version (@%s)", arg, version)
3039 }
3040 p := arg[:len(arg)-len(version)-1]
3041 switch {
3042 case build.IsLocalImport(p):
3043 return nil, fmt.Errorf("%s: argument must be a package path, not a relative path", arg)
3044 case filepath.IsAbs(p):
3045 return nil, fmt.Errorf("%s: argument must be a package path, not an absolute path", arg)
3046 case search.IsMetaPackage(p):
3047 return nil, fmt.Errorf("%s: argument must be a package path, not a meta-package", arg)
3048 case path.Clean(p) != p:
3049 return nil, fmt.Errorf("%s: argument must be a clean package path", arg)
3050 case !strings.Contains(p, "...") && search.IsStandardImportPath(p) && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, p):
3051 return nil, fmt.Errorf("%s: argument must not be a package in the standard library", arg)
3052 default:
3053 patterns[i] = p
3054 }
3055 }
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065 allowed := modload.CheckAllowed
3066 if modload.IsRevisionQuery(version) {
3067
3068 allowed = nil
3069 }
3070 noneSelected := func(path string) (version string) { return "none" }
3071 qrs, err := modload.QueryPackages(ctx, patterns[0], version, noneSelected, allowed)
3072 if err != nil {
3073 return nil, fmt.Errorf("%s: %w", args[0], err)
3074 }
3075 rootMod := qrs[0].Mod
3076 data, err := modfetch.GoMod(rootMod.Path, rootMod.Version)
3077 if err != nil {
3078 return nil, fmt.Errorf("%s: %w", args[0], err)
3079 }
3080 f, err := modfile.Parse("go.mod", data, nil)
3081 if err != nil {
3082 return nil, fmt.Errorf("%s (in %s): %w", args[0], rootMod, err)
3083 }
3084 directiveFmt := "%s (in %s):\n" +
3085 "\tThe go.mod file for the module providing named packages contains one or\n" +
3086 "\tmore %s directives. It must not contain directives that would cause\n" +
3087 "\tit to be interpreted differently than if it were the main module."
3088 if len(f.Replace) > 0 {
3089 return nil, fmt.Errorf(directiveFmt, args[0], rootMod, "replace")
3090 }
3091 if len(f.Exclude) > 0 {
3092 return nil, fmt.Errorf(directiveFmt, args[0], rootMod, "exclude")
3093 }
3094
3095
3096
3097
3098 if _, err := modload.EditBuildList(ctx, nil, []module.Version{rootMod}); err != nil {
3099 return nil, fmt.Errorf("%s: %w", args[0], err)
3100 }
3101
3102
3103 pkgs := PackagesAndErrors(ctx, opts, patterns)
3104
3105
3106 for _, pkg := range pkgs {
3107 var pkgErr error
3108 if pkg.Module == nil {
3109
3110
3111 pkgErr = fmt.Errorf("package %s not provided by module %s", pkg.ImportPath, rootMod)
3112 } else if pkg.Module.Path != rootMod.Path || pkg.Module.Version != rootMod.Version {
3113 pkgErr = fmt.Errorf("package %s provided by module %s@%s\n\tAll packages must be provided by the same module (%s).", pkg.ImportPath, pkg.Module.Path, pkg.Module.Version, rootMod)
3114 }
3115 if pkgErr != nil && pkg.Error == nil {
3116 pkg.Error = &PackageError{Err: pkgErr}
3117 }
3118 }
3119
3120 matchers := make([]func(string) bool, len(patterns))
3121 for i, p := range patterns {
3122 if strings.Contains(p, "...") {
3123 matchers[i] = search.MatchPattern(p)
3124 }
3125 }
3126 return pkgs, nil
3127 }
3128
View as plain text