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