1
2
3
4
5 package modload
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 import (
98 "context"
99 "errors"
100 "fmt"
101 "go/build"
102 "internal/diff"
103 "io/fs"
104 "maps"
105 "os"
106 pathpkg "path"
107 "path/filepath"
108 "runtime"
109 "slices"
110 "sort"
111 "strings"
112 "sync"
113 "sync/atomic"
114
115 "cmd/go/internal/base"
116 "cmd/go/internal/cfg"
117 "cmd/go/internal/fips140"
118 "cmd/go/internal/fsys"
119 "cmd/go/internal/gover"
120 "cmd/go/internal/imports"
121 "cmd/go/internal/modfetch"
122 "cmd/go/internal/modindex"
123 "cmd/go/internal/mvs"
124 "cmd/go/internal/search"
125 "cmd/go/internal/str"
126 "cmd/internal/par"
127
128 "golang.org/x/mod/module"
129 )
130
131
132 type PackageOpts struct {
133
134
135
136
137
138
139 TidyGoVersion string
140
141
142
143
144 Tags map[string]bool
145
146
147
148
149 Tidy bool
150
151
152
153
154 TidyDiff bool
155
156
157
158
159
160
161 TidyCompatibleVersion string
162
163
164
165
166 VendorModulesInGOROOTSrc bool
167
168
169
170
171
172
173 ResolveMissingImports bool
174
175
176
177
178 AssumeRootsImported bool
179
180
181
182
183
184
185
186
187 AllowPackage func(ctx context.Context, path string, mod module.Version) error
188
189
190
191
192 LoadTests bool
193
194
195
196
197
198
199 UseVendorAll bool
200
201
202
203 AllowErrors bool
204
205
206
207
208
209
210
211
212
213
214 SilencePackageErrors bool
215
216
217
218
219
220 SilenceMissingStdImports bool
221
222
223
224
225
226
227
228
229 SilenceNoGoErrors bool
230
231
232
233 SilenceUnmatchedWarnings bool
234
235
236 MainModule module.Version
237
238
239
240 Switcher gover.Switcher
241 }
242
243
244
245 func LoadPackages(ld *Loader, ctx context.Context, opts PackageOpts, patterns ...string) (matches []*search.Match, loadedPackages []string) {
246 if opts.Tags == nil {
247 opts.Tags = imports.Tags()
248 }
249
250 patterns = search.CleanPatterns(patterns)
251 matches = make([]*search.Match, 0, len(patterns))
252 allPatternIsRoot := false
253 for _, pattern := range patterns {
254 matches = append(matches, search.NewMatch(pattern))
255 if pattern == "all" {
256 allPatternIsRoot = true
257 }
258 }
259
260 updateMatches := func(rs *Requirements, pld *packageLoader) {
261 for _, m := range matches {
262 switch {
263 case m.IsLocal():
264
265 if m.Dirs == nil {
266 matchModRoots := ld.modRoots
267 if opts.MainModule != (module.Version{}) {
268 matchModRoots = []string{ld.MainModules.ModRoot(opts.MainModule)}
269 }
270 matchLocalDirs(ld, ctx, matchModRoots, m, rs)
271 }
272
273
274
275
276
277
278
279 m.Pkgs = m.Pkgs[:0]
280 for _, dir := range m.Dirs {
281 var (
282 pkg string
283 err error
284 )
285 absDir := mkAbs(base.Cwd(), dir)
286 if m.IsLiteral() {
287 pkg, err = resolveLocalPackage(ld, ctx, absDir, rs)
288 } else {
289
290
291
292 pkg, err = localPackagePath(ld, ctx, absDir, rs)
293 }
294 if err != nil {
295 if !m.IsLiteral() && (err == errPkgIsBuiltin || err == errPkgIsGorootSrc) {
296 continue
297 }
298
299
300
301 if !ld.HasModRoot() {
302 die(ld)
303 }
304
305 if pld != nil {
306 m.AddError(err)
307 }
308 continue
309 }
310 m.Pkgs = append(m.Pkgs, pkg)
311 }
312
313 case m.IsLiteral():
314 m.Pkgs = []string{m.Pattern()}
315
316 case strings.Contains(m.Pattern(), "..."):
317 m.Errs = m.Errs[:0]
318 mg, err := rs.Graph(ld, ctx)
319 if err != nil {
320
321
322
323
324
325
326 m.Errs = append(m.Errs, err)
327 }
328 matchPackages(ld, ctx, m, opts.Tags, includeStd, mg.BuildList())
329
330 case m.Pattern() == "work":
331 matchModules := ld.MainModules.Versions()
332 if opts.MainModule != (module.Version{}) {
333 matchModules = []module.Version{opts.MainModule}
334 }
335 matchPackages(ld, ctx, m, opts.Tags, omitStd, matchModules)
336
337 case m.Pattern() == "all":
338 if pld == nil {
339
340
341 m.Errs = m.Errs[:0]
342 matchModules := ld.MainModules.Versions()
343 if opts.MainModule != (module.Version{}) {
344 matchModules = []module.Version{opts.MainModule}
345 }
346 matchPackages(ld, ctx, m, opts.Tags, omitStd, matchModules)
347 for tool := range ld.MainModules.Tools() {
348 m.Pkgs = append(m.Pkgs, tool)
349 }
350 } else {
351
352
353 m.Pkgs = pld.computePatternAll()
354 }
355
356 case m.Pattern() == "std" || m.Pattern() == "cmd":
357 if m.Pkgs == nil {
358 m.MatchPackages()
359 }
360
361 case m.Pattern() == "tool":
362 for tool := range ld.MainModules.Tools() {
363 m.Pkgs = append(m.Pkgs, tool)
364 }
365 default:
366 panic(fmt.Sprintf("internal error: modload missing case for pattern %s", m.Pattern()))
367 }
368 }
369 }
370
371 initialRS, err := loadModFile(ld, ctx, &opts)
372 if err != nil {
373 base.Fatal(err)
374 }
375
376 pld := loadFromRoots(ld, ctx, loaderParams{
377 PackageOpts: opts,
378 requirements: initialRS,
379
380 allPatternIsRoot: allPatternIsRoot,
381
382 listRoots: func(rs *Requirements) (roots []string) {
383 updateMatches(rs, nil)
384 for _, m := range matches {
385 roots = append(roots, m.Pkgs...)
386 }
387 return roots
388 },
389 })
390
391
392 updateMatches(pld.requirements, pld)
393
394
395
396 if !pld.SilencePackageErrors {
397 for _, match := range matches {
398 for _, err := range match.Errs {
399 pld.error(err)
400 }
401 }
402 }
403 pld.exitIfErrors(ctx)
404
405 if !opts.SilenceUnmatchedWarnings {
406 search.WarnUnmatched(matches)
407 }
408
409 if opts.Tidy {
410 if cfg.BuildV {
411 mg, _ := pld.requirements.Graph(ld, ctx)
412 for _, m := range initialRS.rootModules {
413 var unused bool
414 if pld.requirements.pruning == unpruned {
415
416
417
418 unused = mg.Selected(m.Path) == "none"
419 } else {
420
421
422
423 _, ok := pld.requirements.rootSelected(ld, m.Path)
424 unused = !ok
425 }
426 if unused {
427 fmt.Fprintf(os.Stderr, "unused %s\n", m.Path)
428 }
429 }
430 }
431
432 keep := keepSums(ld, ctx, pld, pld.requirements, loadedZipSumsOnly)
433 compatVersion := pld.TidyCompatibleVersion
434 goVersion := pld.requirements.GoVersion(ld)
435 if compatVersion == "" {
436 if gover.Compare(goVersion, gover.GoStrictVersion) < 0 {
437 compatVersion = gover.Prev(goVersion)
438 } else {
439
440
441 compatVersion = goVersion
442 }
443 }
444 if gover.Compare(compatVersion, goVersion) > 0 {
445
446
447
448 compatVersion = goVersion
449 }
450 if compatPruning := pruningForGoVersion(compatVersion); compatPruning != pld.requirements.pruning {
451 compatRS := newRequirements(ld, compatPruning, pld.requirements.rootModules, pld.requirements.direct)
452 pld.checkTidyCompatibility(ld, ctx, compatRS, compatVersion)
453
454 for m := range keepSums(ld, ctx, pld, compatRS, loadedZipSumsOnly) {
455 keep[m] = true
456 }
457 }
458
459 if opts.TidyDiff {
460 cfg.BuildMod = "readonly"
461 ld.pkgLoader = pld
462 ld.requirements = ld.pkgLoader.requirements
463 currentGoMod, updatedGoMod, _, err := UpdateGoModFromReqs(ld, ctx, WriteOpts{})
464 if err != nil {
465 base.Fatal(err)
466 }
467 goModDiff := diff.Diff("current/go.mod", currentGoMod, "tidy/go.mod", updatedGoMod)
468
469 ld.Fetcher().TrimGoSum(keep)
470
471
472 if gover.Compare(compatVersion, "1.16") > 0 {
473 keep = keepSums(ld, ctx, ld.pkgLoader, ld.requirements, addBuildListZipSums)
474 }
475 currentGoSum, tidyGoSum := ld.fetcher.TidyGoSum(keep)
476 goSumDiff := diff.Diff("current/go.sum", currentGoSum, "tidy/go.sum", tidyGoSum)
477
478 if len(goModDiff) > 0 {
479 fmt.Println(string(goModDiff))
480 base.SetExitStatus(1)
481 }
482 if len(goSumDiff) > 0 {
483 fmt.Println(string(goSumDiff))
484 base.SetExitStatus(1)
485 }
486 base.Exit()
487 }
488
489 if !ExplicitWriteGoMod {
490 ld.Fetcher().TrimGoSum(keep)
491
492
493
494
495
496
497 if err := ld.Fetcher().WriteGoSum(ctx, keep, mustHaveCompleteRequirements(ld)); err != nil {
498 base.Fatal(err)
499 }
500 }
501 }
502
503 if opts.TidyDiff && !opts.Tidy {
504 panic("TidyDiff is set but Tidy is not.")
505 }
506
507
508
509
510
511 ld.pkgLoader = pld
512 ld.requirements = ld.pkgLoader.requirements
513
514 for _, pkg := range pld.pkgs {
515 if !pkg.isTest() {
516 loadedPackages = append(loadedPackages, pkg.path)
517 }
518 }
519 sort.Strings(loadedPackages)
520
521 if !ExplicitWriteGoMod && opts.ResolveMissingImports {
522 if err := commitRequirements(ld, ctx, WriteOpts{}); err != nil {
523 base.Fatal(err)
524 }
525 }
526
527 return matches, loadedPackages
528 }
529
530
531
532 func matchLocalDirs(ld *Loader, ctx context.Context, modRoots []string, m *search.Match, rs *Requirements) {
533 if !m.IsLocal() {
534 panic(fmt.Sprintf("internal error: resolveLocalDirs on non-local pattern %s", m.Pattern()))
535 }
536
537 if i := strings.Index(m.Pattern(), "..."); i >= 0 {
538
539
540
541
542
543 dir := filepath.Dir(filepath.Clean(m.Pattern()[:i+3]))
544 absDir := mkAbs(base.Cwd(), dir)
545
546 modRoot := findModuleRoot(absDir)
547 if !slices.Contains(modRoots, modRoot) && search.InDir(absDir, cfg.GOROOTsrc) == "" && pathInModuleCache(ld, ctx, absDir, rs) == "" {
548 m.Dirs = []string{}
549 scope := "main module or its selected dependencies"
550 if ld.inWorkspaceMode() {
551 scope = "modules listed in go.work or their selected dependencies"
552 }
553 m.AddError(fmt.Errorf("directory prefix %s does not contain %s", base.ShortPath(absDir), scope))
554 return
555 }
556 }
557
558 m.MatchDirs(modRoots)
559 }
560
561
562 func resolveLocalPackage(ld *Loader, ctx context.Context, absDir string, rs *Requirements) (string, error) {
563 bp, err := cfg.BuildContext.ImportDir(absDir, 0)
564 if err != nil && (bp == nil || len(bp.IgnoredGoFiles) == 0) {
565
566
567
568
569
570
571
572 if _, err := fsys.Stat(absDir); err != nil {
573 if os.IsNotExist(err) {
574
575
576 return "", &fs.PathError{Op: "stat", Path: absDir, Err: errDirectoryNotFound}
577 }
578 return "", err
579 }
580 if _, noGo := err.(*build.NoGoError); noGo {
581
582
583
584
585
586
587
588
589 return "", err
590 }
591 }
592
593 return localPackagePath(ld, ctx, absDir, rs)
594 }
595
596 func mkAbs(wd, path string) string {
597 if filepath.IsAbs(path) {
598 return filepath.Clean(path)
599 }
600 return filepath.Join(wd, path)
601 }
602
603
604
605 func localPackagePath(ld *Loader, ctx context.Context, absDir string, rs *Requirements) (string, error) {
606 for _, mod := range ld.MainModules.Versions() {
607 modRoot := ld.MainModules.ModRoot(mod)
608 if modRoot != "" && absDir == modRoot {
609 if absDir == cfg.GOROOTsrc {
610 return "", errPkgIsGorootSrc
611 }
612 return ld.MainModules.PathPrefix(mod), nil
613 }
614 }
615
616
617
618
619 var pkgNotFoundErr error
620 pkgNotFoundLongestPrefix := ""
621 for _, mainModule := range ld.MainModules.Versions() {
622 modRoot := ld.MainModules.ModRoot(mainModule)
623 if modRoot != "" && str.HasFilePathPrefix(absDir, modRoot) && !strings.Contains(absDir[len(modRoot):], "@") {
624 suffix := filepath.ToSlash(str.TrimFilePathPrefix(absDir, modRoot))
625 if pkg, found := strings.CutPrefix(suffix, "vendor/"); found {
626 if cfg.BuildMod != "vendor" {
627 return "", fmt.Errorf("without -mod=vendor, directory %s has no package path", absDir)
628 }
629
630 readVendorList(VendorDir(ld))
631 if _, ok := vendorPkgModule[pkg]; !ok {
632 return "", fmt.Errorf("directory %s is not a package listed in vendor/modules.txt", absDir)
633 }
634 return pkg, nil
635 }
636
637 mainModulePrefix := ld.MainModules.PathPrefix(mainModule)
638 if mainModulePrefix == "" {
639 pkg := suffix
640 if pkg == "builtin" {
641
642
643
644 return "", errPkgIsBuiltin
645 }
646 return pkg, nil
647 }
648
649 pkg := pathpkg.Join(mainModulePrefix, suffix)
650 if _, ok, err := dirInModule(pkg, mainModulePrefix, modRoot, true); err != nil {
651 return "", err
652 } else if !ok {
653
654
655
656
657 if len(mainModulePrefix) > len(pkgNotFoundLongestPrefix) {
658 pkgNotFoundLongestPrefix = mainModulePrefix
659 pkgNotFoundErr = &PackageNotInModuleError{MainModules: []module.Version{mainModule}, Pattern: pkg}
660 }
661 continue
662 }
663 return pkg, nil
664 }
665 }
666 if pkgNotFoundErr != nil {
667 return "", pkgNotFoundErr
668 }
669
670 if sub := search.InDir(absDir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") {
671 pkg := filepath.ToSlash(sub)
672 if pkg == "builtin" {
673 return "", errPkgIsBuiltin
674 }
675 return pkg, nil
676 }
677
678 pkg := pathInModuleCache(ld, ctx, absDir, rs)
679 if pkg == "" {
680 dirstr := fmt.Sprintf("directory %s", base.ShortPath(absDir))
681 if dirstr == "directory ." {
682 dirstr = "current directory"
683 }
684 if ld.inWorkspaceMode() {
685 if mr := findModuleRoot(absDir); mr != "" {
686 return "", fmt.Errorf("%s is contained in a module that is not one of the workspace modules listed in go.work. You can add the module to the workspace using:\n\tgo work use %s", dirstr, base.ShortPath(mr))
687 }
688 return "", fmt.Errorf("%s outside modules listed in go.work or their selected dependencies", dirstr)
689 }
690 return "", fmt.Errorf("%s outside main module or its selected dependencies", dirstr)
691 }
692 return pkg, nil
693 }
694
695 var (
696 errDirectoryNotFound = errors.New("directory not found")
697 errPkgIsGorootSrc = errors.New("GOROOT/src is not an importable package")
698 errPkgIsBuiltin = errors.New(`"builtin" is a pseudo-package, not an importable package`)
699 )
700
701
702
703 func pathInModuleCache(ld *Loader, ctx context.Context, dir string, rs *Requirements) string {
704 tryMod := func(m module.Version) (string, bool) {
705 if gover.IsToolchain(m.Path) {
706 return "", false
707 }
708 var root string
709 var err error
710 if repl := Replacement(ld, m); repl.Path != "" && repl.Version == "" {
711 root = repl.Path
712 if !filepath.IsAbs(root) {
713 root = filepath.Join(replaceRelativeTo(ld), root)
714 }
715 } else if repl.Path != "" {
716 root, err = modfetch.DownloadDir(ctx, repl)
717 } else {
718 root, err = modfetch.DownloadDir(ctx, m)
719 }
720 if err != nil {
721 return "", false
722 }
723
724 sub := search.InDir(dir, root)
725 if sub == "" {
726 return "", false
727 }
728 sub = filepath.ToSlash(sub)
729 if strings.Contains(sub, "/vendor/") || strings.HasPrefix(sub, "vendor/") || strings.Contains(sub, "@") {
730 return "", false
731 }
732
733 return pathpkg.Join(m.Path, filepath.ToSlash(sub)), true
734 }
735
736 if rs.pruning == pruned {
737 for _, m := range rs.rootModules {
738 if v, _ := rs.rootSelected(ld, m.Path); v != m.Version {
739 continue
740 }
741 if importPath, ok := tryMod(m); ok {
742
743
744 return importPath
745 }
746 }
747 }
748
749
750
751
752
753
754
755
756
757 mg, _ := rs.Graph(ld, ctx)
758 var importPath string
759 for _, m := range mg.BuildList() {
760 var found bool
761 importPath, found = tryMod(m)
762 if found {
763 break
764 }
765 }
766 return importPath
767 }
768
769
770
771
772
773
774
775
776 func ImportFromFiles(ld *Loader, ctx context.Context, gofiles []string) {
777 rs := LoadModFile(ld, ctx)
778
779 tags := imports.Tags()
780 imports, testImports, err := imports.ScanFiles(gofiles, tags)
781 if err != nil {
782 base.Fatal(err)
783 }
784
785 ld.pkgLoader = loadFromRoots(ld, ctx, loaderParams{
786 PackageOpts: PackageOpts{
787 Tags: tags,
788 ResolveMissingImports: true,
789 SilencePackageErrors: true,
790 },
791 requirements: rs,
792 listRoots: func(*Requirements) (roots []string) {
793 roots = append(roots, imports...)
794 roots = append(roots, testImports...)
795 return roots
796 },
797 })
798 ld.requirements = ld.pkgLoader.requirements
799
800 if !ExplicitWriteGoMod {
801 if err := commitRequirements(ld, ctx, WriteOpts{}); err != nil {
802 base.Fatal(err)
803 }
804 }
805 }
806
807
808
809 func (mms *MainModuleSet) DirImportPath(ld *Loader, ctx context.Context, dir string) (path string, m module.Version) {
810 if !ld.HasModRoot() {
811 return ".", module.Version{}
812 }
813 LoadModFile(ld, ctx)
814
815 if !filepath.IsAbs(dir) {
816 dir = filepath.Join(base.Cwd(), dir)
817 } else {
818 dir = filepath.Clean(dir)
819 }
820
821 var longestPrefix string
822 var longestPrefixPath string
823 var longestPrefixVersion module.Version
824 for _, v := range mms.Versions() {
825 modRoot := mms.ModRoot(v)
826 if dir == modRoot {
827 return mms.PathPrefix(v), v
828 }
829 if str.HasFilePathPrefix(dir, modRoot) {
830 pathPrefix := ld.MainModules.PathPrefix(v)
831 if pathPrefix > longestPrefix {
832 longestPrefix = pathPrefix
833 longestPrefixVersion = v
834 suffix := filepath.ToSlash(str.TrimFilePathPrefix(dir, modRoot))
835 if strings.HasPrefix(suffix, "vendor/") {
836 longestPrefixPath = suffix[len("vendor/"):]
837 continue
838 }
839 longestPrefixPath = pathpkg.Join(mms.PathPrefix(v), suffix)
840 }
841 }
842 }
843 if len(longestPrefix) > 0 {
844 return longestPrefixPath, longestPrefixVersion
845 }
846
847 return ".", module.Version{}
848 }
849
850
851 func (ld *Loader) PackageModule(path string) module.Version {
852 pkg, ok := ld.pkgLoader.pkgCache.Get(path)
853 if !ok {
854 return module.Version{}
855 }
856 return pkg.mod
857 }
858
859
860
861
862
863 func Lookup(ld *Loader, parentPath string, parentIsStd bool, path string) (dir, realPath string, err error) {
864 if path == "" {
865 panic("Lookup called with empty package path")
866 }
867
868 if parentIsStd {
869 path = ld.pkgLoader.stdVendor(ld, parentPath, path)
870 }
871 pkg, ok := ld.pkgLoader.pkgCache.Get(path)
872 if !ok {
873
874
875
876
877
878
879
880
881 dir := findStandardImportPath(path)
882 if dir != "" {
883 return dir, path, nil
884 }
885 return "", "", errMissing
886 }
887 return pkg.dir, pkg.path, pkg.err
888 }
889
890
891
892
893
894 type packageLoader struct {
895 loaderParams
896
897
898
899
900
901 allClosesOverTests bool
902
903
904
905 skipImportModFiles bool
906
907 work *par.Queue
908
909
910 roots []*loadPkg
911 pkgCache *par.Cache[string, *loadPkg]
912 pkgs []*loadPkg
913 }
914
915
916
917 type loaderParams struct {
918 PackageOpts
919 requirements *Requirements
920
921 allPatternIsRoot bool
922
923 listRoots func(rs *Requirements) []string
924 }
925
926 func (pld *packageLoader) reset() {
927 select {
928 case <-pld.work.Idle():
929 default:
930 panic("loader.reset when not idle")
931 }
932
933 pld.roots = nil
934 pld.pkgCache = new(par.Cache[string, *loadPkg])
935 pld.pkgs = nil
936 }
937
938
939
940 func (pld *packageLoader) error(err error) {
941 if pld.AllowErrors {
942 fmt.Fprintf(os.Stderr, "go: %v\n", err)
943 } else if pld.Switcher != nil {
944 pld.Switcher.Error(err)
945 } else {
946 base.Error(err)
947 }
948 }
949
950
951 func (pld *packageLoader) switchIfErrors(ctx context.Context) {
952 if pld.Switcher != nil {
953 pld.Switcher.Switch(ctx)
954 }
955 }
956
957
958
959 func (pld *packageLoader) exitIfErrors(ctx context.Context) {
960 pld.switchIfErrors(ctx)
961 base.ExitIfErrors()
962 }
963
964
965
966
967 func (pld *packageLoader) goVersion(ld *Loader) string {
968 if pld.TidyGoVersion != "" {
969 return pld.TidyGoVersion
970 }
971 return pld.requirements.GoVersion(ld)
972 }
973
974
975 type loadPkg struct {
976
977 path string
978 testOf *loadPkg
979
980
981 flags atomicLoadPkgFlags
982
983
984 mod module.Version
985 dir string
986 err error
987 imports []*loadPkg
988 testImports []string
989 inStd bool
990 altMods []module.Version
991
992
993 testOnce sync.Once
994 test *loadPkg
995
996
997 stack *loadPkg
998 }
999
1000
1001 type loadPkgFlags int8
1002
1003 const (
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014 pkgInAll loadPkgFlags = 1 << iota
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 pkgIsRoot
1026
1027
1028
1029
1030 pkgFromRoot
1031
1032
1033
1034 pkgImportsLoaded
1035 )
1036
1037
1038 func (f loadPkgFlags) has(cond loadPkgFlags) bool {
1039 return f&cond == cond
1040 }
1041
1042
1043
1044 type atomicLoadPkgFlags struct {
1045 bits atomic.Int32
1046 }
1047
1048
1049
1050
1051
1052 func (af *atomicLoadPkgFlags) update(flags loadPkgFlags) (old loadPkgFlags) {
1053 for {
1054 old := af.bits.Load()
1055 new := old | int32(flags)
1056 if new == old || af.bits.CompareAndSwap(old, new) {
1057 return loadPkgFlags(old)
1058 }
1059 }
1060 }
1061
1062
1063 func (af *atomicLoadPkgFlags) has(cond loadPkgFlags) bool {
1064 return loadPkgFlags(af.bits.Load())&cond == cond
1065 }
1066
1067
1068 func (pkg *loadPkg) isTest() bool {
1069 return pkg.testOf != nil
1070 }
1071
1072
1073
1074 func (pkg *loadPkg) fromExternalModule(ld *Loader) bool {
1075 if pkg.mod.Path == "" {
1076 return false
1077 }
1078 return !ld.MainModules.Contains(pkg.mod.Path)
1079 }
1080
1081 var errMissing = errors.New("cannot find package")
1082
1083
1084
1085
1086
1087
1088
1089 func loadFromRoots(ld *Loader, ctx context.Context, params loaderParams) *packageLoader {
1090 pld := &packageLoader{
1091 loaderParams: params,
1092 work: par.NewQueue(runtime.GOMAXPROCS(0)),
1093 }
1094
1095 if pld.requirements.pruning == unpruned {
1096
1097
1098
1099
1100
1101
1102
1103
1104 var err error
1105 pld.requirements, _, err = expandGraph(ld, ctx, pld.requirements)
1106 if err != nil {
1107 pld.error(err)
1108 }
1109 }
1110 pld.exitIfErrors(ctx)
1111
1112 updateGoVersion := func() {
1113 goVersion := pld.goVersion(ld)
1114
1115 if pld.requirements.pruning != workspace {
1116 var err error
1117 pld.requirements, err = convertPruning(ld, ctx, pld.requirements, pruningForGoVersion(goVersion))
1118 if err != nil {
1119 pld.error(err)
1120 pld.exitIfErrors(ctx)
1121 }
1122 }
1123
1124
1125
1126
1127 pld.skipImportModFiles = pld.Tidy && gover.Compare(goVersion, gover.TidyGoModSumVersion) < 0
1128
1129
1130
1131 pld.allClosesOverTests = gover.Compare(goVersion, gover.NarrowAllVersion) < 0 && !pld.UseVendorAll
1132 }
1133
1134 for {
1135 pld.reset()
1136 updateGoVersion()
1137
1138
1139
1140
1141
1142 rootPkgs := pld.listRoots(pld.requirements)
1143
1144 if pld.requirements.pruning == pruned && cfg.BuildMod == "mod" {
1145
1146
1147
1148
1149
1150
1151 changedBuildList := pld.preloadRootModules(ld, ctx, rootPkgs)
1152 if changedBuildList {
1153
1154
1155
1156
1157
1158 continue
1159 }
1160 }
1161
1162 inRoots := map[*loadPkg]bool{}
1163 for _, path := range rootPkgs {
1164 root := pld.pkg(ld, ctx, path, pkgIsRoot)
1165 if !inRoots[root] {
1166 pld.roots = append(pld.roots, root)
1167 inRoots[root] = true
1168 }
1169 }
1170
1171
1172
1173
1174
1175
1176 <-pld.work.Idle()
1177
1178 pld.buildStacks()
1179
1180 changed, err := pld.updateRequirements(ld, ctx)
1181 if err != nil {
1182 pld.error(err)
1183 break
1184 }
1185 if changed {
1186
1187
1188
1189
1190
1191 continue
1192 }
1193
1194 if !pld.ResolveMissingImports || (!ld.HasModRoot() && !ld.allowMissingModuleImports) {
1195
1196 break
1197 }
1198
1199 modAddedBy, err := pld.resolveMissingImports(ld, ctx)
1200 if err != nil {
1201 pld.error(err)
1202 break
1203 }
1204 if len(modAddedBy) == 0 {
1205
1206
1207 break
1208 }
1209
1210 toAdd := make([]module.Version, 0, len(modAddedBy))
1211 for m := range modAddedBy {
1212 toAdd = append(toAdd, m)
1213 }
1214 gover.ModSort(toAdd)
1215
1216
1217
1218
1219
1220
1221 var noPkgs []*loadPkg
1222
1223
1224
1225 direct := pld.requirements.direct
1226 rs, err := updateRoots(ld, ctx, direct, pld.requirements, noPkgs, toAdd, pld.AssumeRootsImported)
1227 if err != nil {
1228
1229
1230
1231 if err, ok := err.(*mvs.BuildListError); ok {
1232 if pkg := modAddedBy[err.Module()]; pkg != nil {
1233 pld.error(fmt.Errorf("%s: %w", pkg.stackText(), err.Err))
1234 break
1235 }
1236 }
1237 pld.error(err)
1238 break
1239 }
1240 if slices.Equal(rs.rootModules, pld.requirements.rootModules) {
1241
1242
1243
1244
1245 panic(fmt.Sprintf("internal error: adding %v to module graph had no effect on root requirements (%v)", toAdd, rs.rootModules))
1246 }
1247 pld.requirements = rs
1248 }
1249 pld.exitIfErrors(ctx)
1250
1251
1252
1253 if pld.Tidy {
1254 rs, err := tidyRoots(ld, ctx, pld.requirements, pld.pkgs)
1255 if err != nil {
1256 pld.error(err)
1257 } else {
1258 if pld.TidyGoVersion != "" {
1259
1260
1261
1262 tidy := overrideRoots(ld, ctx, rs, []module.Version{{Path: "go", Version: pld.TidyGoVersion}})
1263 mg, err := tidy.Graph(ld, ctx)
1264 if err != nil {
1265 pld.error(err)
1266 }
1267 if v := mg.Selected("go"); v == pld.TidyGoVersion {
1268 rs = tidy
1269 } else {
1270 conflict := Conflict{
1271 Path: mg.g.FindPath(func(m module.Version) bool {
1272 return m.Path == "go" && m.Version == v
1273 })[1:],
1274 Constraint: module.Version{Path: "go", Version: pld.TidyGoVersion},
1275 }
1276 msg := conflict.Summary()
1277 if cfg.BuildV {
1278 msg = conflict.String()
1279 }
1280 pld.error(errors.New(msg))
1281 }
1282 }
1283
1284 if pld.requirements.pruning == pruned {
1285
1286
1287
1288
1289
1290
1291 for _, m := range rs.rootModules {
1292 if m.Path == "go" && pld.TidyGoVersion != "" {
1293 continue
1294 }
1295 if v, ok := pld.requirements.rootSelected(ld, m.Path); !ok || v != m.Version {
1296 pld.error(fmt.Errorf("internal error: a requirement on %v is needed but was not added during package loading (selected %s)", m, v))
1297 }
1298 }
1299 }
1300
1301 pld.requirements = rs
1302 }
1303
1304 pld.exitIfErrors(ctx)
1305 }
1306
1307
1308 for _, pkg := range pld.pkgs {
1309 if pkg.err == nil {
1310 continue
1311 }
1312
1313
1314 if sumErr, ok := errors.AsType[*ImportMissingSumError](pkg.err); ok {
1315 if importer := pkg.stack; importer != nil {
1316 sumErr.importer = importer.path
1317 sumErr.importerVersion = importer.mod.Version
1318 sumErr.importerIsTest = importer.testOf != nil
1319 }
1320 }
1321
1322 if stdErr, ok := errors.AsType[*ImportMissingError](pkg.err); ok && stdErr.isStd {
1323
1324
1325 if importer := pkg.stack; importer != nil {
1326 if v, ok := rawGoVersion.Load(importer.mod); ok && gover.Compare(gover.Local(), v.(string)) < 0 {
1327 stdErr.importerGoVersion = v.(string)
1328 }
1329 }
1330 if pld.SilenceMissingStdImports {
1331 continue
1332 }
1333 }
1334 if pld.SilencePackageErrors {
1335 continue
1336 }
1337 if pld.SilenceNoGoErrors && errors.Is(pkg.err, imports.ErrNoGo) {
1338 continue
1339 }
1340
1341 pld.error(fmt.Errorf("%s: %w", pkg.stackText(), pkg.err))
1342 }
1343
1344 pld.checkMultiplePaths(ld)
1345 return pld
1346 }
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367 func (pld *packageLoader) updateRequirements(ld *Loader, ctx context.Context) (changed bool, err error) {
1368 rs := pld.requirements
1369
1370
1371
1372 var direct map[string]bool
1373
1374
1375
1376
1377
1378 loadedDirect := pld.allPatternIsRoot && maps.Equal(pld.Tags, imports.AnyTags())
1379 if loadedDirect {
1380 direct = make(map[string]bool)
1381 } else {
1382
1383
1384
1385 direct = make(map[string]bool, len(rs.direct))
1386 for mPath := range rs.direct {
1387 direct[mPath] = true
1388 }
1389 }
1390
1391 var maxTooNew *gover.TooNewError
1392 for _, pkg := range pld.pkgs {
1393 if pkg.err != nil {
1394 if tooNew, ok := errors.AsType[*gover.TooNewError](pkg.err); ok {
1395 if maxTooNew == nil || gover.Compare(tooNew.GoVersion, maxTooNew.GoVersion) > 0 {
1396 maxTooNew = tooNew
1397 }
1398 }
1399 }
1400 if pkg.mod.Version != "" || !ld.MainModules.Contains(pkg.mod.Path) {
1401 continue
1402 }
1403
1404 for _, dep := range pkg.imports {
1405 if !dep.fromExternalModule(ld) {
1406 continue
1407 }
1408
1409 if ld.inWorkspaceMode() {
1410
1411
1412
1413 if cfg.BuildMod == "vendor" {
1414
1415
1416
1417
1418
1419
1420 continue
1421 }
1422 if mg, err := rs.Graph(ld, ctx); err != nil {
1423 return false, err
1424 } else if _, ok := mg.RequiredBy(dep.mod); !ok {
1425
1426
1427 pkg.err = &DirectImportFromImplicitDependencyError{
1428 ImporterPath: pkg.path,
1429 ImportedPath: dep.path,
1430 Module: dep.mod,
1431 }
1432 }
1433 } else if pkg.err == nil && cfg.BuildMod != "mod" {
1434 if v, ok := rs.rootSelected(ld, dep.mod.Path); !ok || v != dep.mod.Version {
1435
1436
1437
1438
1439
1440
1441
1442
1443 pkg.err = &DirectImportFromImplicitDependencyError{
1444 ImporterPath: pkg.path,
1445 ImportedPath: dep.path,
1446 Module: dep.mod,
1447 }
1448
1449
1450 continue
1451 }
1452 }
1453
1454
1455
1456
1457 direct[dep.mod.Path] = true
1458 }
1459 }
1460 if maxTooNew != nil {
1461 return false, maxTooNew
1462 }
1463
1464 var addRoots []module.Version
1465 if pld.Tidy {
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500 tidy, err := tidyRoots(ld, ctx, rs, pld.pkgs)
1501 if err != nil {
1502 return false, err
1503 }
1504 addRoots = tidy.rootModules
1505 }
1506
1507 rs, err = updateRoots(ld, ctx, direct, rs, pld.pkgs, addRoots, pld.AssumeRootsImported)
1508 if err != nil {
1509
1510
1511 return false, err
1512 }
1513
1514 if rs.GoVersion(ld) != pld.requirements.GoVersion(ld) {
1515
1516
1517
1518
1519
1520 changed = true
1521 } else if rs != pld.requirements && !slices.Equal(rs.rootModules, pld.requirements.rootModules) {
1522
1523
1524
1525 mg, err := rs.Graph(ld, ctx)
1526 if err != nil {
1527 return false, err
1528 }
1529 for _, pkg := range pld.pkgs {
1530 if pkg.fromExternalModule(ld) && mg.Selected(pkg.mod.Path) != pkg.mod.Version {
1531 changed = true
1532 break
1533 }
1534 if pkg.err != nil {
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550 if _, _, _, _, err = importFromModules(ld, ctx, pkg.path, rs, nil, pld.skipImportModFiles); err == nil {
1551 changed = true
1552 break
1553 }
1554 }
1555 }
1556 }
1557
1558 pld.requirements = rs
1559 return changed, nil
1560 }
1561
1562
1563
1564
1565
1566
1567
1568 func (pld *packageLoader) resolveMissingImports(ld *Loader, ctx context.Context) (modAddedBy map[module.Version]*loadPkg, err error) {
1569 type pkgMod struct {
1570 pkg *loadPkg
1571 mod *module.Version
1572 }
1573 var pkgMods []pkgMod
1574 for _, pkg := range pld.pkgs {
1575 if pkg.err == nil {
1576 continue
1577 }
1578 if pkg.isTest() {
1579
1580
1581 continue
1582 }
1583 if _, ok := errors.AsType[*ImportMissingError](pkg.err); !ok {
1584
1585 continue
1586 }
1587
1588 pkg := pkg
1589 var mod module.Version
1590 pld.work.Add(func() {
1591 var err error
1592 mod, err = queryImport(ld, ctx, pkg.path, pld.requirements)
1593 if err != nil {
1594 if ime, ok := errors.AsType[*ImportMissingError](err); ok {
1595 for curstack := pkg.stack; curstack != nil; curstack = curstack.stack {
1596 if ld.MainModules.Contains(curstack.mod.Path) {
1597 ime.ImportingMainModule = curstack.mod
1598 ime.modRoot = ld.MainModules.ModRoot(ime.ImportingMainModule)
1599 break
1600 }
1601 }
1602 }
1603
1604
1605
1606
1607
1608 pkg.err = err
1609 }
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622 })
1623
1624 pkgMods = append(pkgMods, pkgMod{pkg: pkg, mod: &mod})
1625 }
1626 <-pld.work.Idle()
1627
1628 modAddedBy = map[module.Version]*loadPkg{}
1629
1630 var (
1631 maxTooNew *gover.TooNewError
1632 maxTooNewPkg *loadPkg
1633 )
1634 for _, pm := range pkgMods {
1635 if tooNew, ok := errors.AsType[*gover.TooNewError](pm.pkg.err); ok {
1636 if maxTooNew == nil || gover.Compare(tooNew.GoVersion, maxTooNew.GoVersion) > 0 {
1637 maxTooNew = tooNew
1638 maxTooNewPkg = pm.pkg
1639 }
1640 }
1641 }
1642 if maxTooNew != nil {
1643 fmt.Fprintf(os.Stderr, "go: toolchain upgrade needed to resolve %s\n", maxTooNewPkg.path)
1644 return nil, maxTooNew
1645 }
1646
1647 for _, pm := range pkgMods {
1648 pkg, mod := pm.pkg, *pm.mod
1649 if mod.Path == "" {
1650 continue
1651 }
1652
1653 fmt.Fprintf(os.Stderr, "go: found %s in %s %s\n", pkg.path, mod.Path, mod.Version)
1654 if modAddedBy[mod] == nil {
1655 modAddedBy[mod] = pkg
1656 }
1657 }
1658
1659 return modAddedBy, nil
1660 }
1661
1662
1663
1664
1665
1666
1667
1668
1669 func (pld *packageLoader) pkg(ld *Loader, ctx context.Context, path string, flags loadPkgFlags) *loadPkg {
1670 if flags.has(pkgImportsLoaded) {
1671 panic("internal error: (*packageLoader).pkg called with pkgImportsLoaded flag set")
1672 }
1673
1674 pkg := pld.pkgCache.Do(path, func() *loadPkg {
1675 pkg := &loadPkg{
1676 path: path,
1677 }
1678 pld.applyPkgFlags(ld, ctx, pkg, flags)
1679
1680 pld.work.Add(func() { pld.load(ld, ctx, pkg) })
1681 return pkg
1682 })
1683
1684 pld.applyPkgFlags(ld, ctx, pkg, flags)
1685 return pkg
1686 }
1687
1688
1689
1690
1691 func (pld *packageLoader) applyPkgFlags(ld *Loader, ctx context.Context, pkg *loadPkg, flags loadPkgFlags) {
1692 if flags == 0 {
1693 return
1694 }
1695
1696 if flags.has(pkgInAll) && pld.allPatternIsRoot && !pkg.isTest() {
1697
1698 flags |= pkgIsRoot
1699 }
1700 if flags.has(pkgIsRoot) {
1701 flags |= pkgFromRoot
1702 }
1703
1704 old := pkg.flags.update(flags)
1705 new := old | flags
1706 if new == old || !new.has(pkgImportsLoaded) {
1707
1708
1709
1710 return
1711 }
1712
1713 if !pkg.isTest() {
1714
1715
1716
1717 wantTest := false
1718 switch {
1719 case pld.allPatternIsRoot && ld.MainModules.Contains(pkg.mod.Path):
1720
1721
1722
1723
1724
1725 wantTest = true
1726
1727 case pld.allPatternIsRoot && pld.allClosesOverTests && new.has(pkgInAll):
1728
1729
1730
1731 wantTest = true
1732
1733 case pld.LoadTests && new.has(pkgIsRoot):
1734
1735 wantTest = true
1736 }
1737
1738 if wantTest {
1739 var testFlags loadPkgFlags
1740 if ld.MainModules.Contains(pkg.mod.Path) || (pld.allClosesOverTests && new.has(pkgInAll)) {
1741
1742
1743
1744 testFlags |= pkgInAll
1745 }
1746 pld.pkgTest(ld, ctx, pkg, testFlags)
1747 }
1748 }
1749
1750 if new.has(pkgInAll) && !old.has(pkgInAll|pkgImportsLoaded) {
1751
1752
1753 for _, dep := range pkg.imports {
1754 pld.applyPkgFlags(ld, ctx, dep, pkgInAll)
1755 }
1756 }
1757
1758 if new.has(pkgFromRoot) && !old.has(pkgFromRoot|pkgImportsLoaded) {
1759 for _, dep := range pkg.imports {
1760 pld.applyPkgFlags(ld, ctx, dep, pkgFromRoot)
1761 }
1762 }
1763 }
1764
1765
1766
1767
1768 func (pld *packageLoader) preloadRootModules(ld *Loader, ctx context.Context, rootPkgs []string) (changedBuildList bool) {
1769 needc := make(chan map[module.Version]bool, 1)
1770 needc <- map[module.Version]bool{}
1771 for _, path := range rootPkgs {
1772 path := path
1773 pld.work.Add(func() {
1774
1775
1776
1777
1778
1779 m, _, _, _, err := importFromModules(ld, ctx, path, pld.requirements, nil, pld.skipImportModFiles)
1780 if err != nil {
1781 if _, ok := errors.AsType[*ImportMissingError](err); ok && pld.ResolveMissingImports {
1782
1783
1784 m, err = queryImport(ld, ctx, path, pld.requirements)
1785 }
1786 if err != nil {
1787
1788
1789 return
1790 }
1791 }
1792 if m.Path == "" {
1793
1794 return
1795 }
1796
1797 v, ok := pld.requirements.rootSelected(ld, m.Path)
1798 if !ok || v != m.Version {
1799
1800
1801
1802
1803
1804
1805
1806 need := <-needc
1807 need[m] = true
1808 needc <- need
1809 }
1810 })
1811 }
1812 <-pld.work.Idle()
1813
1814 need := <-needc
1815 if len(need) == 0 {
1816 return false
1817 }
1818
1819 toAdd := make([]module.Version, 0, len(need))
1820 for m := range need {
1821 toAdd = append(toAdd, m)
1822 }
1823 gover.ModSort(toAdd)
1824
1825 rs, err := updateRoots(ld, ctx, pld.requirements.direct, pld.requirements, nil, toAdd, pld.AssumeRootsImported)
1826 if err != nil {
1827
1828
1829
1830 pld.error(err)
1831 pld.exitIfErrors(ctx)
1832 return false
1833 }
1834 if slices.Equal(rs.rootModules, pld.requirements.rootModules) {
1835
1836
1837
1838
1839 panic(fmt.Sprintf("internal error: adding %v to module graph had no effect on root requirements (%v)", toAdd, rs.rootModules))
1840 }
1841
1842 pld.requirements = rs
1843 return true
1844 }
1845
1846
1847 func (pld *packageLoader) load(ld *Loader, ctx context.Context, pkg *loadPkg) {
1848 var mg *ModuleGraph
1849 if pld.requirements.pruning == unpruned {
1850 var err error
1851 mg, err = pld.requirements.Graph(ld, ctx)
1852 if err != nil {
1853
1854
1855
1856
1857
1858
1859
1860
1861 mg = nil
1862 }
1863 }
1864
1865 var modroot string
1866 pkg.mod, modroot, pkg.dir, pkg.altMods, pkg.err = importFromModules(ld, ctx, pkg.path, pld.requirements, mg, pld.skipImportModFiles)
1867 if ld.MainModules.Tools()[pkg.path] {
1868
1869
1870
1871 pld.applyPkgFlags(ld, ctx, pkg, pkgInAll)
1872 }
1873 if pkg.dir == "" {
1874 return
1875 }
1876 if ld.MainModules.Contains(pkg.mod.Path) {
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886 pld.applyPkgFlags(ld, ctx, pkg, pkgInAll)
1887 }
1888 if pld.AllowPackage != nil {
1889 if err := pld.AllowPackage(ctx, pkg.path, pkg.mod); err != nil {
1890 pkg.err = err
1891 }
1892 }
1893
1894 pkg.inStd = (search.IsStandardImportPath(pkg.path) && search.InDir(pkg.dir, cfg.GOROOTsrc) != "")
1895
1896 var imports, testImports []string
1897
1898 if cfg.BuildContext.Compiler == "gccgo" && pkg.inStd {
1899
1900 } else {
1901 var err error
1902 imports, testImports, err = scanDir(modroot, pkg.dir, pld.Tags)
1903 if err != nil {
1904 pkg.err = err
1905 return
1906 }
1907 }
1908
1909 pkg.imports = make([]*loadPkg, 0, len(imports))
1910 var importFlags loadPkgFlags
1911 if pkg.flags.has(pkgInAll) {
1912 importFlags = pkgInAll
1913 }
1914 for _, path := range imports {
1915 if pkg.inStd {
1916
1917
1918 path = pld.stdVendor(ld, pkg.path, path)
1919 }
1920 pkg.imports = append(pkg.imports, pld.pkg(ld, ctx, path, importFlags))
1921 }
1922 pkg.testImports = testImports
1923
1924 pld.applyPkgFlags(ld, ctx, pkg, pkgImportsLoaded)
1925 }
1926
1927
1928
1929
1930
1931
1932 func (pld *packageLoader) pkgTest(ld *Loader, ctx context.Context, pkg *loadPkg, testFlags loadPkgFlags) *loadPkg {
1933 if pkg.isTest() {
1934 panic("pkgTest called on a test package")
1935 }
1936
1937 createdTest := false
1938 pkg.testOnce.Do(func() {
1939 pkg.test = &loadPkg{
1940 path: pkg.path,
1941 testOf: pkg,
1942 mod: pkg.mod,
1943 dir: pkg.dir,
1944 err: pkg.err,
1945 inStd: pkg.inStd,
1946 }
1947 pld.applyPkgFlags(ld, ctx, pkg.test, testFlags)
1948 createdTest = true
1949 })
1950
1951 test := pkg.test
1952 if createdTest {
1953 test.imports = make([]*loadPkg, 0, len(pkg.testImports))
1954 var importFlags loadPkgFlags
1955 if test.flags.has(pkgInAll) {
1956 importFlags = pkgInAll
1957 }
1958 for _, path := range pkg.testImports {
1959 if pkg.inStd {
1960 path = pld.stdVendor(ld, test.path, path)
1961 }
1962 test.imports = append(test.imports, pld.pkg(ld, ctx, path, importFlags))
1963 }
1964 pkg.testImports = nil
1965 pld.applyPkgFlags(ld, ctx, test, pkgImportsLoaded)
1966 } else {
1967 pld.applyPkgFlags(ld, ctx, test, testFlags)
1968 }
1969
1970 return test
1971 }
1972
1973
1974
1975 func (pld *packageLoader) stdVendor(ld *Loader, parentPath, path string) string {
1976 if p, _, ok := fips140.ResolveImport(path); ok {
1977 return p
1978 }
1979 if search.IsStandardImportPath(path) {
1980 return path
1981 }
1982
1983 if str.HasPathPrefix(parentPath, "cmd") {
1984 if !pld.VendorModulesInGOROOTSrc || !ld.MainModules.Contains("cmd") {
1985 vendorPath := pathpkg.Join("cmd", "vendor", path)
1986
1987 if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
1988 return vendorPath
1989 }
1990 }
1991 } else if !pld.VendorModulesInGOROOTSrc || !ld.MainModules.Contains("std") || str.HasPathPrefix(parentPath, "vendor") {
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004 vendorPath := pathpkg.Join("vendor", path)
2005 if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
2006 return vendorPath
2007 }
2008 }
2009
2010
2011 return path
2012 }
2013
2014
2015
2016 func (pld *packageLoader) computePatternAll() (all []string) {
2017 for _, pkg := range pld.pkgs {
2018 if module.CheckImportPath(pkg.path) != nil {
2019
2020
2021
2022
2023 continue
2024 }
2025 if pkg.flags.has(pkgInAll) && !pkg.isTest() {
2026 all = append(all, pkg.path)
2027 }
2028 }
2029 sort.Strings(all)
2030 return all
2031 }
2032
2033
2034
2035
2036
2037 func (pld *packageLoader) checkMultiplePaths(ld *Loader) {
2038 if cached := pld.requirements.graph.Load(); cached != nil {
2039 if mg := cached.mg; mg != nil {
2040
2041
2042
2043 mg.checkPathsOnce.Do(func() {
2044 checkMultiplePathsUncached(ld, pld, mg.BuildList())
2045 })
2046 return
2047 }
2048 }
2049 checkMultiplePathsUncached(ld, pld, pld.requirements.rootModules)
2050 }
2051
2052 func checkMultiplePathsUncached(ld *Loader, pld *packageLoader, mods []module.Version) {
2053 firstPath := map[module.Version]string{}
2054 for _, mod := range mods {
2055 src := resolveReplacement(ld, mod)
2056 if prev, ok := firstPath[src]; !ok {
2057 firstPath[src] = mod.Path
2058 } else if prev != mod.Path {
2059 pld.error(fmt.Errorf("%s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path))
2060 }
2061 }
2062 }
2063
2064
2065
2066 func (pld *packageLoader) checkTidyCompatibility(ld *Loader, ctx context.Context, rs *Requirements, compatVersion string) {
2067 goVersion := rs.GoVersion(ld)
2068 suggestUpgrade := false
2069 suggestEFlag := false
2070 suggestFixes := func() {
2071 if pld.AllowErrors {
2072
2073
2074 return
2075 }
2076
2077
2078
2079
2080
2081 fmt.Fprintln(os.Stderr)
2082
2083 goFlag := ""
2084 if goVersion != ld.MainModules.GoVersion(ld) {
2085 goFlag = " -go=" + goVersion
2086 }
2087
2088 compatFlag := ""
2089 if compatVersion != gover.Prev(goVersion) {
2090 compatFlag = " -compat=" + compatVersion
2091 }
2092 if suggestUpgrade {
2093 eDesc := ""
2094 eFlag := ""
2095 if suggestEFlag {
2096 eDesc = ", leaving some packages unresolved"
2097 eFlag = " -e"
2098 }
2099 fmt.Fprintf(os.Stderr, "To upgrade to the versions selected by go %s%s:\n\tgo mod tidy%s -go=%s && go mod tidy%s -go=%s%s\n", compatVersion, eDesc, eFlag, compatVersion, eFlag, goVersion, compatFlag)
2100 } else if suggestEFlag {
2101
2102
2103
2104
2105 fmt.Fprintf(os.Stderr, "To proceed despite packages unresolved in go %s:\n\tgo mod tidy -e%s%s\n", compatVersion, goFlag, compatFlag)
2106 }
2107
2108 fmt.Fprintf(os.Stderr, "If reproducibility with go %s is not needed:\n\tgo mod tidy%s -compat=%s\n", compatVersion, goFlag, goVersion)
2109
2110 fmt.Fprintf(os.Stderr, "For information about 'go mod tidy' compatibility, see:\n\thttps://go.dev/ref/mod#graph-pruning\n")
2111 }
2112
2113 mg, err := rs.Graph(ld, ctx)
2114 if err != nil {
2115 pld.error(fmt.Errorf("error loading go %s module graph: %w", compatVersion, err))
2116 pld.switchIfErrors(ctx)
2117 suggestFixes()
2118 pld.exitIfErrors(ctx)
2119 return
2120 }
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136 type mismatch struct {
2137 mod module.Version
2138 err error
2139 }
2140 mismatchMu := make(chan map[*loadPkg]mismatch, 1)
2141 mismatchMu <- map[*loadPkg]mismatch{}
2142 for _, pkg := range pld.pkgs {
2143 if pkg.mod.Path == "" && pkg.err == nil {
2144
2145
2146 continue
2147 }
2148
2149 pkg := pkg
2150 pld.work.Add(func() {
2151 mod, _, _, _, err := importFromModules(ld, ctx, pkg.path, rs, mg, pld.skipImportModFiles)
2152 if mod != pkg.mod {
2153 mismatches := <-mismatchMu
2154 mismatches[pkg] = mismatch{mod: mod, err: err}
2155 mismatchMu <- mismatches
2156 }
2157 })
2158 }
2159 <-pld.work.Idle()
2160
2161 mismatches := <-mismatchMu
2162 if len(mismatches) == 0 {
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174 for _, m := range pld.requirements.rootModules {
2175 if v := mg.Selected(m.Path); v != m.Version {
2176 fmt.Fprintln(os.Stderr)
2177 base.Fatalf("go: internal error: failed to diagnose selected-version mismatch for module %s: go %s selects %s, but go %s selects %s\n\tPlease report this at https://go.dev/issue.", m.Path, goVersion, m.Version, compatVersion, v)
2178 }
2179 }
2180 return
2181 }
2182
2183
2184
2185 for _, pkg := range pld.pkgs {
2186 mismatch, ok := mismatches[pkg]
2187 if !ok {
2188 continue
2189 }
2190
2191 if pkg.isTest() {
2192
2193
2194 if _, ok := mismatches[pkg.testOf]; !ok {
2195 base.Fatalf("go: internal error: mismatch recorded for test %s, but not its non-test package", pkg.path)
2196 }
2197 continue
2198 }
2199
2200 switch {
2201 case mismatch.err != nil:
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213 if _, ok := errors.AsType[*ImportMissingError](mismatch.err); ok {
2214 selected := module.Version{
2215 Path: pkg.mod.Path,
2216 Version: mg.Selected(pkg.mod.Path),
2217 }
2218 pld.error(fmt.Errorf("%s loaded from %v,\n\tbut go %s would fail to locate it in %s", pkg.stackText(), pkg.mod, compatVersion, selected))
2219 } else {
2220 if _, ok := errors.AsType[*AmbiguousImportError](mismatch.err); ok {
2221
2222 }
2223 pld.error(fmt.Errorf("%s loaded from %v,\n\tbut go %s would fail to locate it:\n\t%v", pkg.stackText(), pkg.mod, compatVersion, mismatch.err))
2224 }
2225
2226 suggestEFlag = true
2227
2228
2229
2230
2231
2232
2233
2234
2235 if !suggestUpgrade {
2236 for _, m := range pld.requirements.rootModules {
2237 if v := mg.Selected(m.Path); v != m.Version {
2238 suggestUpgrade = true
2239 break
2240 }
2241 }
2242 }
2243
2244 case pkg.err != nil:
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260 suggestUpgrade = true
2261 pld.error(fmt.Errorf("%s failed to load from any module,\n\tbut go %s would load it from %v", pkg.path, compatVersion, mismatch.mod))
2262
2263 case pkg.mod != mismatch.mod:
2264
2265
2266
2267
2268 suggestUpgrade = true
2269 pld.error(fmt.Errorf("%s loaded from %v,\n\tbut go %s would select %v\n", pkg.stackText(), pkg.mod, compatVersion, mismatch.mod.Version))
2270
2271 default:
2272 base.Fatalf("go: internal error: mismatch recorded for package %s, but no differences found", pkg.path)
2273 }
2274 }
2275
2276 pld.switchIfErrors(ctx)
2277 suggestFixes()
2278 pld.exitIfErrors(ctx)
2279 }
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293 func scanDir(modroot string, dir string, tags map[string]bool) (imports_, testImports []string, err error) {
2294 if ip, mierr := modindex.GetPackage(modroot, dir); mierr == nil {
2295 imports_, testImports, err = ip.ScanDir(tags)
2296 goto Happy
2297 } else if !errors.Is(mierr, modindex.ErrNotIndexed) {
2298 return nil, nil, mierr
2299 }
2300
2301 imports_, testImports, err = imports.ScanDir(dir, tags)
2302 Happy:
2303
2304 filter := func(x []string) []string {
2305 w := 0
2306 for _, pkg := range x {
2307 if pkg != "C" && pkg != "appengine" && !strings.HasPrefix(pkg, "appengine/") &&
2308 pkg != "appengine_internal" && !strings.HasPrefix(pkg, "appengine_internal/") {
2309 x[w] = pkg
2310 w++
2311 }
2312 }
2313 return x[:w]
2314 }
2315
2316 return filter(imports_), filter(testImports), err
2317 }
2318
2319
2320
2321
2322
2323
2324
2325
2326 func (pld *packageLoader) buildStacks() {
2327 if len(pld.pkgs) > 0 {
2328 panic("buildStacks")
2329 }
2330 for _, pkg := range pld.roots {
2331 pkg.stack = pkg
2332 pld.pkgs = append(pld.pkgs, pkg)
2333 }
2334 for i := 0; i < len(pld.pkgs); i++ {
2335 pkg := pld.pkgs[i]
2336 for _, next := range pkg.imports {
2337 if next.stack == nil {
2338 next.stack = pkg
2339 pld.pkgs = append(pld.pkgs, next)
2340 }
2341 }
2342 if next := pkg.test; next != nil && next.stack == nil {
2343 next.stack = pkg
2344 pld.pkgs = append(pld.pkgs, next)
2345 }
2346 }
2347 for _, pkg := range pld.roots {
2348 pkg.stack = nil
2349 }
2350 }
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360 func (pkg *loadPkg) stackText() string {
2361 var stack []*loadPkg
2362 for p := pkg; p != nil; p = p.stack {
2363 stack = append(stack, p)
2364 }
2365
2366 var buf strings.Builder
2367 for i := len(stack) - 1; i >= 0; i-- {
2368 p := stack[i]
2369 fmt.Fprint(&buf, p.path)
2370 if p.testOf != nil {
2371 fmt.Fprint(&buf, ".test")
2372 }
2373 if i > 0 {
2374 if stack[i-1].testOf == p {
2375 fmt.Fprint(&buf, " tested by\n\t")
2376 } else {
2377 fmt.Fprint(&buf, " imports\n\t")
2378 }
2379 }
2380 }
2381 return buf.String()
2382 }
2383
2384
2385
2386 func (pkg *loadPkg) why() string {
2387 var buf strings.Builder
2388 var stack []*loadPkg
2389 for p := pkg; p != nil; p = p.stack {
2390 stack = append(stack, p)
2391 }
2392
2393 for i := len(stack) - 1; i >= 0; i-- {
2394 p := stack[i]
2395 if p.testOf != nil {
2396 fmt.Fprintf(&buf, "%s.test\n", p.testOf.path)
2397 } else {
2398 fmt.Fprintf(&buf, "%s\n", p.path)
2399 }
2400 }
2401 return buf.String()
2402 }
2403
2404
2405
2406
2407
2408
2409 func (ld *Loader) Why(path string) string {
2410 pkg, ok := ld.pkgLoader.pkgCache.Get(path)
2411 if !ok {
2412 return ""
2413 }
2414 return pkg.why()
2415 }
2416
2417
2418
2419
2420 func (ld *Loader) WhyDepth(path string) int {
2421 n := 0
2422 pkg, _ := ld.pkgLoader.pkgCache.Get(path)
2423 for p := pkg; p != nil; p = p.stack {
2424 n++
2425 }
2426 return n
2427 }
2428
View as plain text