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 pkg.flags.has(pkgInAll) && !pkg.isTest() {
2013 all = append(all, pkg.path)
2014 }
2015 }
2016 sort.Strings(all)
2017 return all
2018 }
2019
2020
2021
2022
2023
2024 func (ld *loader) checkMultiplePaths() {
2025 mods := ld.requirements.rootModules
2026 if cached := ld.requirements.graph.Load(); cached != nil {
2027 if mg := cached.mg; mg != nil {
2028 mods = mg.BuildList()
2029 }
2030 }
2031
2032 firstPath := map[module.Version]string{}
2033 for _, mod := range mods {
2034 src := resolveReplacement(mod)
2035 if prev, ok := firstPath[src]; !ok {
2036 firstPath[src] = mod.Path
2037 } else if prev != mod.Path {
2038 ld.error(fmt.Errorf("%s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path))
2039 }
2040 }
2041 }
2042
2043
2044
2045 func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements, compatVersion string) {
2046 goVersion := rs.GoVersion()
2047 suggestUpgrade := false
2048 suggestEFlag := false
2049 suggestFixes := func() {
2050 if ld.AllowErrors {
2051
2052
2053 return
2054 }
2055
2056
2057
2058
2059
2060 fmt.Fprintln(os.Stderr)
2061
2062 goFlag := ""
2063 if goVersion != MainModules.GoVersion() {
2064 goFlag = " -go=" + goVersion
2065 }
2066
2067 compatFlag := ""
2068 if compatVersion != gover.Prev(goVersion) {
2069 compatFlag = " -compat=" + compatVersion
2070 }
2071 if suggestUpgrade {
2072 eDesc := ""
2073 eFlag := ""
2074 if suggestEFlag {
2075 eDesc = ", leaving some packages unresolved"
2076 eFlag = " -e"
2077 }
2078 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)
2079 } else if suggestEFlag {
2080
2081
2082
2083
2084 fmt.Fprintf(os.Stderr, "To proceed despite packages unresolved in go %s:\n\tgo mod tidy -e%s%s\n", compatVersion, goFlag, compatFlag)
2085 }
2086
2087 fmt.Fprintf(os.Stderr, "If reproducibility with go %s is not needed:\n\tgo mod tidy%s -compat=%s\n", compatVersion, goFlag, goVersion)
2088
2089 fmt.Fprintf(os.Stderr, "For information about 'go mod tidy' compatibility, see:\n\thttps://go.dev/ref/mod#graph-pruning\n")
2090 }
2091
2092 mg, err := rs.Graph(ctx)
2093 if err != nil {
2094 ld.error(fmt.Errorf("error loading go %s module graph: %w", compatVersion, err))
2095 ld.switchIfErrors(ctx)
2096 suggestFixes()
2097 ld.exitIfErrors(ctx)
2098 return
2099 }
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115 type mismatch struct {
2116 mod module.Version
2117 err error
2118 }
2119 mismatchMu := make(chan map[*loadPkg]mismatch, 1)
2120 mismatchMu <- map[*loadPkg]mismatch{}
2121 for _, pkg := range ld.pkgs {
2122 if pkg.mod.Path == "" && pkg.err == nil {
2123
2124
2125 continue
2126 }
2127
2128 pkg := pkg
2129 ld.work.Add(func() {
2130 mod, _, _, _, err := importFromModules(ctx, pkg.path, rs, mg, ld.skipImportModFiles)
2131 if mod != pkg.mod {
2132 mismatches := <-mismatchMu
2133 mismatches[pkg] = mismatch{mod: mod, err: err}
2134 mismatchMu <- mismatches
2135 }
2136 })
2137 }
2138 <-ld.work.Idle()
2139
2140 mismatches := <-mismatchMu
2141 if len(mismatches) == 0 {
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153 for _, m := range ld.requirements.rootModules {
2154 if v := mg.Selected(m.Path); v != m.Version {
2155 fmt.Fprintln(os.Stderr)
2156 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)
2157 }
2158 }
2159 return
2160 }
2161
2162
2163
2164 for _, pkg := range ld.pkgs {
2165 mismatch, ok := mismatches[pkg]
2166 if !ok {
2167 continue
2168 }
2169
2170 if pkg.isTest() {
2171
2172
2173 if _, ok := mismatches[pkg.testOf]; !ok {
2174 base.Fatalf("go: internal error: mismatch recorded for test %s, but not its non-test package", pkg.path)
2175 }
2176 continue
2177 }
2178
2179 switch {
2180 case mismatch.err != nil:
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192 if missing := (*ImportMissingError)(nil); errors.As(mismatch.err, &missing) {
2193 selected := module.Version{
2194 Path: pkg.mod.Path,
2195 Version: mg.Selected(pkg.mod.Path),
2196 }
2197 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))
2198 } else {
2199 if ambiguous := (*AmbiguousImportError)(nil); errors.As(mismatch.err, &ambiguous) {
2200
2201 }
2202 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))
2203 }
2204
2205 suggestEFlag = true
2206
2207
2208
2209
2210
2211
2212
2213
2214 if !suggestUpgrade {
2215 for _, m := range ld.requirements.rootModules {
2216 if v := mg.Selected(m.Path); v != m.Version {
2217 suggestUpgrade = true
2218 break
2219 }
2220 }
2221 }
2222
2223 case pkg.err != nil:
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239 suggestUpgrade = true
2240 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))
2241
2242 case pkg.mod != mismatch.mod:
2243
2244
2245
2246
2247 suggestUpgrade = true
2248 ld.error(fmt.Errorf("%s loaded from %v,\n\tbut go %s would select %v\n", pkg.stackText(), pkg.mod, compatVersion, mismatch.mod.Version))
2249
2250 default:
2251 base.Fatalf("go: internal error: mismatch recorded for package %s, but no differences found", pkg.path)
2252 }
2253 }
2254
2255 ld.switchIfErrors(ctx)
2256 suggestFixes()
2257 ld.exitIfErrors(ctx)
2258 }
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272 func scanDir(modroot string, dir string, tags map[string]bool) (imports_, testImports []string, err error) {
2273 if ip, mierr := modindex.GetPackage(modroot, dir); mierr == nil {
2274 imports_, testImports, err = ip.ScanDir(tags)
2275 goto Happy
2276 } else if !errors.Is(mierr, modindex.ErrNotIndexed) {
2277 return nil, nil, mierr
2278 }
2279
2280 imports_, testImports, err = imports.ScanDir(dir, tags)
2281 Happy:
2282
2283 filter := func(x []string) []string {
2284 w := 0
2285 for _, pkg := range x {
2286 if pkg != "C" && pkg != "appengine" && !strings.HasPrefix(pkg, "appengine/") &&
2287 pkg != "appengine_internal" && !strings.HasPrefix(pkg, "appengine_internal/") {
2288 x[w] = pkg
2289 w++
2290 }
2291 }
2292 return x[:w]
2293 }
2294
2295 return filter(imports_), filter(testImports), err
2296 }
2297
2298
2299
2300
2301
2302
2303
2304
2305 func (ld *loader) buildStacks() {
2306 if len(ld.pkgs) > 0 {
2307 panic("buildStacks")
2308 }
2309 for _, pkg := range ld.roots {
2310 pkg.stack = pkg
2311 ld.pkgs = append(ld.pkgs, pkg)
2312 }
2313 for i := 0; i < len(ld.pkgs); i++ {
2314 pkg := ld.pkgs[i]
2315 for _, next := range pkg.imports {
2316 if next.stack == nil {
2317 next.stack = pkg
2318 ld.pkgs = append(ld.pkgs, next)
2319 }
2320 }
2321 if next := pkg.test; next != nil && next.stack == nil {
2322 next.stack = pkg
2323 ld.pkgs = append(ld.pkgs, next)
2324 }
2325 }
2326 for _, pkg := range ld.roots {
2327 pkg.stack = nil
2328 }
2329 }
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339 func (pkg *loadPkg) stackText() string {
2340 var stack []*loadPkg
2341 for p := pkg; p != nil; p = p.stack {
2342 stack = append(stack, p)
2343 }
2344
2345 var buf strings.Builder
2346 for i := len(stack) - 1; i >= 0; i-- {
2347 p := stack[i]
2348 fmt.Fprint(&buf, p.path)
2349 if p.testOf != nil {
2350 fmt.Fprint(&buf, ".test")
2351 }
2352 if i > 0 {
2353 if stack[i-1].testOf == p {
2354 fmt.Fprint(&buf, " tested by\n\t")
2355 } else {
2356 fmt.Fprint(&buf, " imports\n\t")
2357 }
2358 }
2359 }
2360 return buf.String()
2361 }
2362
2363
2364
2365 func (pkg *loadPkg) why() string {
2366 var buf strings.Builder
2367 var stack []*loadPkg
2368 for p := pkg; p != nil; p = p.stack {
2369 stack = append(stack, p)
2370 }
2371
2372 for i := len(stack) - 1; i >= 0; i-- {
2373 p := stack[i]
2374 if p.testOf != nil {
2375 fmt.Fprintf(&buf, "%s.test\n", p.testOf.path)
2376 } else {
2377 fmt.Fprintf(&buf, "%s\n", p.path)
2378 }
2379 }
2380 return buf.String()
2381 }
2382
2383
2384
2385
2386
2387
2388 func Why(path string) string {
2389 pkg, ok := loaded.pkgCache.Get(path)
2390 if !ok {
2391 return ""
2392 }
2393 return pkg.why()
2394 }
2395
2396
2397
2398
2399 func WhyDepth(path string) int {
2400 n := 0
2401 pkg, _ := loaded.pkgCache.Get(path)
2402 for p := pkg; p != nil; p = p.stack {
2403 n++
2404 }
2405 return n
2406 }
2407
View as plain text