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