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