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