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