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