1
2
3
4
5
6 package modget
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import (
28 "context"
29 "errors"
30 "fmt"
31 "os"
32 "path/filepath"
33 "runtime"
34 "sort"
35 "strconv"
36 "strings"
37 "sync"
38
39 "cmd/go/internal/base"
40 "cmd/go/internal/cfg"
41 "cmd/go/internal/gover"
42 "cmd/go/internal/imports"
43 "cmd/go/internal/modfetch"
44 "cmd/go/internal/modload"
45 "cmd/go/internal/search"
46 "cmd/go/internal/toolchain"
47 "cmd/go/internal/work"
48 "cmd/internal/par"
49
50 "golang.org/x/mod/modfile"
51 "golang.org/x/mod/module"
52 )
53
54 var CmdGet = &base.Command{
55
56
57 UsageLine: "go get [-t] [-u] [-tool] [build flags] [packages]",
58 Short: "add dependencies to current module and install them",
59 Long: `
60 Get resolves its command-line arguments to packages at specific module versions,
61 updates go.mod to require those versions, and downloads source code into the
62 module cache.
63
64 To add a dependency for a package or upgrade it to its latest version:
65
66 go get example.com/pkg
67
68 To upgrade or downgrade a package to a specific version:
69
70 go get example.com/pkg@v1.2.3
71
72 To remove a dependency on a module and downgrade modules that require it:
73
74 go get example.com/mod@none
75
76 To upgrade the minimum required Go version to the latest released Go version:
77
78 go get go@latest
79
80 To upgrade the Go toolchain to the latest patch release of the current Go toolchain:
81
82 go get toolchain@patch
83
84 See https://go.dev/ref/mod#go-get for details.
85
86 In earlier versions of Go, 'go get' was used to build and install packages.
87 Now, 'go get' is dedicated to adjusting dependencies in go.mod. 'go install'
88 may be used to build and install commands instead. When a version is specified,
89 'go install' runs in module-aware mode and ignores the go.mod file in the
90 current directory. For example:
91
92 go install example.com/pkg@v1.2.3
93 go install example.com/pkg@latest
94
95 See 'go help install' or https://go.dev/ref/mod#go-install for details.
96
97 'go get' accepts the following flags.
98
99 The -t flag instructs get to consider modules needed to build tests of
100 packages specified on the command line.
101
102 The -u flag instructs get to update modules providing dependencies
103 of packages named on the command line to use newer minor or patch
104 releases when available.
105
106 The -u=patch flag (not -u patch) also instructs get to update dependencies,
107 but changes the default to select patch releases.
108
109 When the -t and -u flags are used together, get will update
110 test dependencies as well.
111
112 The -tool flag instructs go to add a matching tool line to go.mod for each
113 listed package. If -tool is used with @none, the line will be removed.
114 See 'go help tool' for more information.
115
116 The -x flag prints commands as they are executed. This is useful for
117 debugging version control commands when a module is downloaded directly
118 from a repository.
119
120 For more about build flags, see 'go help build'.
121
122 For more about modules, see https://go.dev/ref/mod.
123
124 For more about using 'go get' to update the minimum Go version and
125 suggested Go toolchain, see https://go.dev/doc/toolchain.
126
127 For more about specifying packages, see 'go help packages'.
128
129 See also: go build, go install, go clean, go mod.
130 `,
131 }
132
133 var HelpVCS = &base.Command{
134 UsageLine: "vcs",
135 Short: "controlling version control with GOVCS",
136 Long: `
137 The go command can run version control commands like git
138 to download imported code. This functionality is critical to the decentralized
139 Go package ecosystem, in which code can be imported from any server,
140 but it is also a potential security problem, if a malicious server finds a
141 way to cause the invoked version control command to run unintended code.
142
143 To balance the functionality and security concerns, the go command
144 by default will only use git and hg to download code from public servers.
145 But it will use any known version control system (fossil, git, hg, svn)
146 to download code from private servers, defined as those hosting packages
147 matching the GOPRIVATE variable (see 'go help private'). The rationale behind
148 allowing only Git and Mercurial is that these two systems have had the most
149 attention to issues of being run as clients of untrusted servers. In contrast,
150 Bazaar, Fossil, and Subversion have primarily been used in trusted,
151 authenticated environments and are not as well scrutinized as attack surfaces.
152
153 The version control command restrictions only apply when using direct version
154 control access to download code. When downloading modules from a proxy,
155 the go command uses the proxy protocol instead, which is always permitted.
156 By default, the go command uses the Go module mirror (proxy.golang.org)
157 for public packages and only falls back to version control for private
158 packages or when the mirror refuses to serve a public package (typically for
159 legal reasons). Therefore, clients can still access public code served from
160 Bazaar, Fossil, or Subversion repositories by default, because those downloads
161 use the Go module mirror, which takes on the security risk of running the
162 version control commands using a custom sandbox.
163
164 The GOVCS variable can be used to change the allowed version control systems
165 for specific packages (identified by a module or import path).
166 The GOVCS variable applies when building package in both module-aware mode
167 and GOPATH mode. When using modules, the patterns match against the module path.
168 When using GOPATH, the patterns match against the import path corresponding to
169 the root of the version control repository.
170
171 The general form of the GOVCS setting is a comma-separated list of
172 pattern:vcslist rules. The pattern is a glob pattern that must match
173 one or more leading elements of the module or import path. The vcslist
174 is a pipe-separated list of allowed version control commands, or "all"
175 to allow use of any known command, or "off" to disallow all commands.
176 Note that if a module matches a pattern with vcslist "off", it may still be
177 downloaded if the origin server uses the "mod" scheme, which instructs the
178 go command to download the module using the GOPROXY protocol.
179 The earliest matching pattern in the list applies, even if later patterns
180 might also match.
181
182 For example, consider:
183
184 GOVCS=github.com:git,evil.com:off,*:git|hg
185
186 With this setting, code with a module or import path beginning with
187 github.com/ can only use git; paths on evil.com cannot use any version
188 control command, and all other paths (* matches everything) can use
189 only git or hg.
190
191 The special patterns "public" and "private" match public and private
192 module or import paths. A path is private if it matches the GOPRIVATE
193 variable; otherwise it is public.
194
195 If no rules in the GOVCS variable match a particular module or import path,
196 the 'go get' command applies its default rule, which can now be summarized
197 in GOVCS notation as 'public:git|hg,private:all'.
198
199 To allow unfettered use of any version control system for any package, use:
200
201 GOVCS=*:all
202
203 To disable all use of version control, use:
204
205 GOVCS=*:off
206
207 The 'go env -w' command (see 'go help env') can be used to set the GOVCS
208 variable for future go command invocations.
209 `,
210 }
211
212 var (
213 getD dFlag
214 getF = CmdGet.Flag.Bool("f", false, "")
215 getFix = CmdGet.Flag.Bool("fix", false, "")
216 getM = CmdGet.Flag.Bool("m", false, "")
217 getT = CmdGet.Flag.Bool("t", false, "")
218 getU upgradeFlag
219 getTool = CmdGet.Flag.Bool("tool", false, "")
220 getInsecure = CmdGet.Flag.Bool("insecure", false, "")
221 )
222
223
224 type upgradeFlag struct {
225 rawVersion string
226 version string
227 }
228
229 func (*upgradeFlag) IsBoolFlag() bool { return true }
230
231 func (v *upgradeFlag) Set(s string) error {
232 if s == "false" {
233 v.version = ""
234 v.rawVersion = ""
235 } else if s == "true" {
236 v.version = "upgrade"
237 v.rawVersion = ""
238 } else {
239 v.version = s
240 v.rawVersion = s
241 }
242 return nil
243 }
244
245 func (v *upgradeFlag) String() string { return "" }
246
247
248
249
250 type dFlag struct {
251 value bool
252 set bool
253 }
254
255 func (v *dFlag) IsBoolFlag() bool { return true }
256
257 func (v *dFlag) Set(s string) error {
258 v.set = true
259 value, err := strconv.ParseBool(s)
260 if err != nil {
261 err = errors.New("parse error")
262 }
263 v.value = value
264 return err
265 }
266
267 func (b *dFlag) String() string { return "" }
268
269 func init() {
270 work.AddBuildFlags(CmdGet, work.OmitModFlag)
271 CmdGet.Run = runGet
272 CmdGet.Flag.Var(&getD, "d", "")
273 CmdGet.Flag.Var(&getU, "u", "")
274 }
275
276 func runGet(ctx context.Context, cmd *base.Command, args []string) {
277 moduleLoader := modload.NewLoader()
278 switch getU.version {
279 case "", "upgrade", "patch":
280
281 default:
282 base.Fatalf("go: unknown upgrade flag -u=%s", getU.rawVersion)
283 }
284 if getD.set {
285 if !getD.value {
286 base.Fatalf("go: -d flag may not be set to false")
287 }
288 fmt.Fprintf(os.Stderr, "go: -d flag is deprecated. -d=true is a no-op\n")
289 }
290 if *getF {
291 fmt.Fprintf(os.Stderr, "go: -f flag is a no-op\n")
292 }
293 if *getFix {
294 fmt.Fprintf(os.Stderr, "go: -fix flag is a no-op\n")
295 }
296 if *getM {
297 base.Fatalf("go: -m flag is no longer supported")
298 }
299 if *getInsecure {
300 base.Fatalf("go: -insecure flag is no longer supported; use GOINSECURE instead")
301 }
302
303 moduleLoader.ForceUseModules = true
304
305
306
307
308 modload.ExplicitWriteGoMod = true
309
310
311
312 moduleLoader.AllowMissingModuleImports()
313
314
315
316
317
318 modload.Init(moduleLoader)
319 if !moduleLoader.HasModRoot() {
320 base.Fatalf("go: go.mod file not found in current directory or any parent directory.\n" +
321 "\t'go get' is no longer supported outside a module.\n" +
322 "\tTo build and install a command, use 'go install' with a version,\n" +
323 "\tlike 'go install example.com/cmd@latest'\n" +
324 "\tFor more information, see https://go.dev/doc/go-get-install-deprecation\n" +
325 "\tor run 'go help get' or 'go help install'.")
326 }
327
328 dropToolchain, queries := parseArgs(moduleLoader, ctx, args)
329 opts := modload.WriteOpts{
330 DropToolchain: dropToolchain,
331 }
332 for _, q := range queries {
333 if q.pattern == "toolchain" {
334 opts.ExplicitToolchain = true
335 }
336 }
337
338 r := newResolver(moduleLoader, ctx, queries)
339 r.performLocalQueries(moduleLoader, ctx)
340 r.performPathQueries(moduleLoader, ctx)
341 r.performToolQueries(moduleLoader, ctx)
342 r.performWorkQueries(moduleLoader, ctx)
343
344 for {
345 r.performWildcardQueries(moduleLoader, ctx)
346 r.performPatternAllQueries(moduleLoader, ctx)
347
348 if changed := r.resolveQueries(moduleLoader, ctx, queries); changed {
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370 continue
371 }
372
373
374
375
376
377
378
379
380
381
382
383
384 upgrades := r.findAndUpgradeImports(moduleLoader, ctx, queries)
385 if changed := r.applyUpgrades(moduleLoader, ctx, upgrades); changed {
386 continue
387 }
388
389 r.findMissingWildcards(moduleLoader, ctx)
390 if changed := r.resolveQueries(moduleLoader, ctx, r.wildcardQueries); changed {
391 continue
392 }
393
394 break
395 }
396
397 r.checkWildcardVersions(moduleLoader, ctx)
398
399 var pkgPatterns []string
400 for _, q := range queries {
401 if q.matchesPackages {
402 pkgPatterns = append(pkgPatterns, q.pattern)
403 }
404 }
405
406 if *getTool {
407 updateTools(moduleLoader, ctx, r, queries, &opts)
408 }
409
410
411
412 r.checkPackageProblems(moduleLoader, ctx, pkgPatterns)
413
414
415 oldReqs := reqsFromGoMod(modload.ModFile(moduleLoader))
416
417 if err := modload.WriteGoMod(moduleLoader, ctx, opts); err != nil {
418
419
420
421
422
423 toolchain.SwitchOrFatal(moduleLoader, ctx, err)
424 }
425
426 newReqs := reqsFromGoMod(modload.ModFile(moduleLoader))
427 r.reportChanges(oldReqs, newReqs)
428
429 if gowork := moduleLoader.FindGoWork(base.Cwd()); gowork != "" {
430 wf, err := modload.ReadWorkFile(gowork)
431 if err == nil && modload.UpdateWorkGoVersion(wf, moduleLoader.MainModules.GoVersion(moduleLoader)) {
432 modload.WriteWorkFile(gowork, wf)
433 }
434 }
435 }
436
437 func updateTools(ld *modload.Loader, ctx context.Context, r *resolver, queries []*query, opts *modload.WriteOpts) {
438 pkgOpts := modload.PackageOpts{
439 VendorModulesInGOROOTSrc: true,
440 LoadTests: *getT,
441 ResolveMissingImports: false,
442 AllowErrors: true,
443 SilenceNoGoErrors: true,
444 }
445 patterns := []string{}
446 for _, q := range queries {
447 if search.IsMetaPackage(q.pattern) || q.pattern == "toolchain" {
448 base.Fatalf("go: go get -tool does not work with \"%s\".", q.pattern)
449 }
450 patterns = append(patterns, q.pattern)
451 }
452
453 matches, _ := modload.LoadPackages(ld, ctx, pkgOpts, patterns...)
454 for i, m := range matches {
455 if queries[i].version == "none" {
456 opts.DropTools = append(opts.DropTools, m.Pkgs...)
457 } else {
458 opts.AddTools = append(opts.AddTools, m.Pkgs...)
459 }
460 }
461
462 mg, err := modload.LoadModGraph(ld, ctx, "")
463 if err != nil {
464 toolchain.SwitchOrFatal(ld, ctx, err)
465 }
466 r.buildList = mg.BuildList()
467 r.buildListVersion = make(map[string]string, len(r.buildList))
468 for _, m := range r.buildList {
469 r.buildListVersion[m.Path] = m.Version
470 }
471 }
472
473
474
475
476
477 func parseArgs(ld *modload.Loader, ctx context.Context, rawArgs []string) (dropToolchain bool, queries []*query) {
478 defer base.ExitIfErrors()
479
480 for _, arg := range search.CleanPatterns(rawArgs) {
481 q, err := newQuery(ld, arg)
482 if err != nil {
483 base.Error(err)
484 continue
485 }
486
487 if q.version == "none" {
488 switch q.pattern {
489 case "go":
490 base.Errorf("go: cannot use go@none")
491 continue
492 case "toolchain":
493 dropToolchain = true
494 continue
495 }
496 }
497
498
499
500 if len(rawArgs) == 0 {
501 q.raw = ""
502 }
503
504
505
506
507 if strings.HasSuffix(q.raw, ".go") && q.rawVersion == "" {
508 if !strings.Contains(q.raw, "/") {
509 base.Errorf("go: %s: arguments must be package or module paths", q.raw)
510 continue
511 }
512 if fi, err := os.Stat(q.raw); err == nil && !fi.IsDir() {
513 base.Errorf("go: %s exists as a file, but 'go get' requires package arguments", q.raw)
514 continue
515 }
516 }
517
518 queries = append(queries, q)
519 }
520
521 return dropToolchain, queries
522 }
523
524 type resolver struct {
525 localQueries []*query
526 pathQueries []*query
527 wildcardQueries []*query
528 patternAllQueries []*query
529 workQueries []*query
530 toolQueries []*query
531
532
533
534 nonesByPath map[string]*query
535 wildcardNones []*query
536
537
538
539
540 resolvedVersion map[string]versionReason
541
542 buildList []module.Version
543 buildListVersion map[string]string
544
545 initialVersion map[string]string
546
547 missing []pathSet
548
549 work *par.Queue
550
551 matchInModuleCache par.ErrCache[matchInModuleKey, []string]
552
553
554
555 workspace *workspace
556 }
557
558 type versionReason struct {
559 version string
560 reason *query
561 }
562
563 type matchInModuleKey struct {
564 pattern string
565 m module.Version
566 }
567
568 func newResolver(ld *modload.Loader, ctx context.Context, queries []*query) *resolver {
569
570
571 mg, err := modload.LoadModGraph(ld, ctx, "")
572 if err != nil {
573 toolchain.SwitchOrFatal(ld, ctx, err)
574 }
575
576 buildList := mg.BuildList()
577 initialVersion := make(map[string]string, len(buildList))
578 for _, m := range buildList {
579 initialVersion[m.Path] = m.Version
580 }
581
582 r := &resolver{
583 work: par.NewQueue(runtime.GOMAXPROCS(0)),
584 resolvedVersion: map[string]versionReason{},
585 buildList: buildList,
586 buildListVersion: initialVersion,
587 initialVersion: initialVersion,
588 nonesByPath: map[string]*query{},
589 workspace: loadWorkspace(ld.FindGoWork(base.Cwd())),
590 }
591
592 for _, q := range queries {
593 if q.pattern == "all" {
594 r.patternAllQueries = append(r.patternAllQueries, q)
595 } else if q.pattern == "work" {
596 r.workQueries = append(r.workQueries, q)
597 } else if q.pattern == "tool" {
598 r.toolQueries = append(r.toolQueries, q)
599 } else if q.patternIsLocal {
600 r.localQueries = append(r.localQueries, q)
601 } else if q.isWildcard() {
602 r.wildcardQueries = append(r.wildcardQueries, q)
603 } else {
604 r.pathQueries = append(r.pathQueries, q)
605 }
606
607 if q.version == "none" {
608
609 if q.isWildcard() {
610 r.wildcardNones = append(r.wildcardNones, q)
611 } else {
612
613
614 r.nonesByPath[q.pattern] = q
615 }
616 }
617 }
618
619 return r
620 }
621
622
623
624 func (r *resolver) initialSelected(mPath string) (version string) {
625 v, ok := r.initialVersion[mPath]
626 if !ok {
627 return "none"
628 }
629 return v
630 }
631
632
633
634 func (r *resolver) selected(mPath string) (version string) {
635 v, ok := r.buildListVersion[mPath]
636 if !ok {
637 return "none"
638 }
639 return v
640 }
641
642
643
644 func (r *resolver) noneForPath(mPath string) (nq *query, found bool) {
645 if nq = r.nonesByPath[mPath]; nq != nil {
646 return nq, true
647 }
648 for _, nq := range r.wildcardNones {
649 if nq.matchesPath(mPath) {
650 return nq, true
651 }
652 }
653 return nil, false
654 }
655
656
657
658 func (r *resolver) queryModule(ld *modload.Loader, ctx context.Context, mPath, query string, selected func(string) string) (module.Version, error) {
659 current := r.initialSelected(mPath)
660 rev, err := modload.Query(ld, ctx, mPath, query, current, r.checkAllowedOr(ld, query, selected))
661 if err != nil {
662 return module.Version{}, err
663 }
664 return module.Version{Path: mPath, Version: rev.Version}, nil
665 }
666
667
668
669 func (r *resolver) queryPackages(ld *modload.Loader, ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, err error) {
670 results, err := modload.QueryPackages(ld, ctx, pattern, query, selected, r.checkAllowedOr(ld, query, selected))
671 if len(results) > 0 {
672 pkgMods = make([]module.Version, 0, len(results))
673 for _, qr := range results {
674 pkgMods = append(pkgMods, qr.Mod)
675 }
676 }
677 return pkgMods, err
678 }
679
680
681
682 func (r *resolver) queryPattern(ld *modload.Loader, ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, mod module.Version, err error) {
683 results, modOnly, err := modload.QueryPattern(ld, ctx, pattern, query, selected, r.checkAllowedOr(ld, query, selected))
684 if len(results) > 0 {
685 pkgMods = make([]module.Version, 0, len(results))
686 for _, qr := range results {
687 pkgMods = append(pkgMods, qr.Mod)
688 }
689 }
690 if modOnly != nil {
691 mod = modOnly.Mod
692 }
693 return pkgMods, mod, err
694 }
695
696
697
698 func (r *resolver) checkAllowedOr(s *modload.Loader, requested string, selected func(string) string) modload.AllowedFunc {
699 return func(ctx context.Context, m module.Version) error {
700 if m.Version == requested {
701 return s.CheckExclusions(ctx, m)
702 }
703 if (requested == "upgrade" || requested == "patch") && m.Version == selected(m.Path) {
704 return nil
705 }
706 return s.CheckAllowed(ctx, m)
707 }
708 }
709
710
711 func (r *resolver) matchInModule(ld *modload.Loader, ctx context.Context, pattern string, m module.Version) (packages []string, err error) {
712 return r.matchInModuleCache.Do(matchInModuleKey{pattern, m}, func() ([]string, error) {
713 match := modload.MatchInModule(ld, ctx, pattern, m, imports.AnyTags())
714 if len(match.Errs) > 0 {
715 return match.Pkgs, match.Errs[0]
716 }
717 return match.Pkgs, nil
718 })
719 }
720
721
722
723
724
725
726
727
728
729 func (r *resolver) queryNone(ld *modload.Loader, ctx context.Context, q *query) {
730 if search.IsMetaPackage(q.pattern) {
731 panic(fmt.Sprintf("internal error: queryNone called with pattern %q", q.pattern))
732 }
733
734 if !q.isWildcard() {
735 q.pathOnce(q.pattern, func() pathSet {
736 hasModRoot := ld.HasModRoot()
737 if hasModRoot && ld.MainModules.Contains(q.pattern) {
738 v := module.Version{Path: q.pattern}
739
740
741
742
743
744
745
746
747
748
749 return errSet(&modload.QueryMatchesMainModulesError{
750 MainModules: []module.Version{v},
751 Pattern: q.pattern,
752 Query: q.version,
753 PatternIsModule: ld.MainModules.Contains(q.pattern),
754 })
755 }
756
757 return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}}
758 })
759 }
760
761 for _, curM := range r.buildList {
762 if !q.matchesPath(curM.Path) {
763 continue
764 }
765 q.pathOnce(curM.Path, func() pathSet {
766 if ld.HasModRoot() && curM.Version == "" && ld.MainModules.Contains(curM.Path) {
767 return errSet(&modload.QueryMatchesMainModulesError{
768 MainModules: []module.Version{curM},
769 Pattern: q.pattern,
770 Query: q.version,
771 PatternIsModule: ld.MainModules.Contains(q.pattern),
772 })
773 }
774 return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}}
775 })
776 }
777 }
778
779 func (r *resolver) performLocalQueries(ld *modload.Loader, ctx context.Context) {
780 for _, q := range r.localQueries {
781 q.pathOnce(q.pattern, func() pathSet {
782 absDetail := ""
783 if !filepath.IsAbs(q.pattern) {
784 if absPath, err := filepath.Abs(q.pattern); err == nil {
785 absDetail = fmt.Sprintf(" (%s)", absPath)
786 }
787 }
788
789
790
791 pkgPattern, mainModule := ld.MainModules.DirImportPath(ld, ctx, q.pattern)
792 if pkgPattern == "." {
793 ld.MustHaveModRoot()
794 versions := ld.MainModules.Versions()
795 modRoots := make([]string, 0, len(versions))
796 for _, m := range versions {
797 modRoots = append(modRoots, ld.MainModules.ModRoot(m))
798 }
799 var plural string
800 if len(modRoots) != 1 {
801 plural = "s"
802 }
803 return errSet(fmt.Errorf("%s%s is not within module%s rooted at %s", q.pattern, absDetail, plural, strings.Join(modRoots, ", ")))
804 }
805
806 match := modload.MatchInModule(ld, ctx, pkgPattern, mainModule, imports.AnyTags())
807 if len(match.Errs) > 0 {
808 return pathSet{err: match.Errs[0]}
809 }
810
811 if len(match.Pkgs) == 0 {
812 if q.raw == "" || q.raw == "." {
813 return errSet(fmt.Errorf("no package to get in current directory"))
814 }
815 if !q.isWildcard() {
816 ld.MustHaveModRoot()
817 return errSet(fmt.Errorf("%s%s is not a package in module rooted at %s", q.pattern, absDetail, ld.MainModules.ModRoot(mainModule)))
818 }
819 search.WarnUnmatched([]*search.Match{match})
820 return pathSet{}
821 }
822
823 return pathSet{pkgMods: []module.Version{mainModule}}
824 })
825 }
826 }
827
828
829
830
831
832
833
834
835
836 func (r *resolver) performWildcardQueries(ld *modload.Loader, ctx context.Context) {
837 for _, q := range r.wildcardQueries {
838 q := q
839 r.work.Add(func() {
840 if q.version == "none" {
841 r.queryNone(ld, ctx, q)
842 } else {
843 r.queryWildcard(ld, ctx, q)
844 }
845 })
846 }
847 <-r.work.Idle()
848 }
849
850
851
852
853
854
855 func (r *resolver) queryWildcard(ld *modload.Loader, ctx context.Context, q *query) {
856
857
858
859
860
861
862 for _, curM := range r.buildList {
863 if !q.canMatchInModule(curM.Path) {
864 continue
865 }
866 q.pathOnce(curM.Path, func() pathSet {
867 if _, hit := r.noneForPath(curM.Path); hit {
868
869
870 return pathSet{}
871 }
872
873 if ld.MainModules.Contains(curM.Path) && !versionOkForMainModule(q.version) {
874 if q.matchesPath(curM.Path) {
875 return errSet(&modload.QueryMatchesMainModulesError{
876 MainModules: []module.Version{curM},
877 Pattern: q.pattern,
878 Query: q.version,
879 PatternIsModule: ld.MainModules.Contains(q.pattern),
880 })
881 }
882
883 packages, err := r.matchInModule(ld, ctx, q.pattern, curM)
884 if err != nil {
885 return errSet(err)
886 }
887 if len(packages) > 0 {
888 return errSet(&modload.QueryMatchesPackagesInMainModuleError{
889 Pattern: q.pattern,
890 Query: q.version,
891 Packages: packages,
892 })
893 }
894
895 return r.tryWildcard(ld, ctx, q, curM)
896 }
897
898 m, err := r.queryModule(ld, ctx, curM.Path, q.version, r.initialSelected)
899 if err != nil {
900 if !isNoSuchModuleVersion(err) {
901
902 return errSet(err)
903 }
904
905
906
907
908
909
910
911
912
913
914
915
916
917 return pathSet{}
918 }
919
920 return r.tryWildcard(ld, ctx, q, m)
921 })
922 }
923
924
925
926
927 }
928
929
930
931 func (r *resolver) tryWildcard(ld *modload.Loader, ctx context.Context, q *query, m module.Version) pathSet {
932 mMatches := q.matchesPath(m.Path)
933 packages, err := r.matchInModule(ld, ctx, q.pattern, m)
934 if err != nil {
935 return errSet(err)
936 }
937 if len(packages) > 0 {
938 return pathSet{pkgMods: []module.Version{m}}
939 }
940 if mMatches {
941 return pathSet{mod: m}
942 }
943 return pathSet{}
944 }
945
946
947
948 func (r *resolver) findMissingWildcards(ld *modload.Loader, ctx context.Context) {
949 for _, q := range r.wildcardQueries {
950 if q.version == "none" || q.matchesPackages {
951 continue
952 }
953 r.work.Add(func() {
954 q.pathOnce(q.pattern, func() pathSet {
955 pkgMods, mod, err := r.queryPattern(ld, ctx, q.pattern, q.version, r.initialSelected)
956 if err != nil {
957 if isNoSuchPackageVersion(err) && len(q.resolved) > 0 {
958
959
960
961 return pathSet{}
962 }
963 return errSet(err)
964 }
965
966 return pathSet{pkgMods: pkgMods, mod: mod}
967 })
968 })
969 }
970 <-r.work.Idle()
971 }
972
973
974
975
976 func (r *resolver) checkWildcardVersions(ld *modload.Loader, ctx context.Context) {
977 defer base.ExitIfErrors()
978
979 for _, q := range r.wildcardQueries {
980 for _, curM := range r.buildList {
981 if !q.canMatchInModule(curM.Path) {
982 continue
983 }
984 if !q.matchesPath(curM.Path) {
985 packages, err := r.matchInModule(ld, ctx, q.pattern, curM)
986 if len(packages) == 0 {
987 if err != nil {
988 reportError(q, err)
989 }
990 continue
991 }
992 }
993
994 rev, err := r.queryModule(ld, ctx, curM.Path, q.version, r.initialSelected)
995 if err != nil {
996 reportError(q, err)
997 continue
998 }
999 if rev.Version == curM.Version {
1000 continue
1001 }
1002
1003 if !q.matchesPath(curM.Path) {
1004 m := module.Version{Path: curM.Path, Version: rev.Version}
1005 packages, err := r.matchInModule(ld, ctx, q.pattern, m)
1006 if err != nil {
1007 reportError(q, err)
1008 continue
1009 }
1010 if len(packages) == 0 {
1011
1012
1013
1014 var version any = m
1015 if rev.Version != q.version {
1016 version = fmt.Sprintf("%s@%s (%s)", m.Path, q.version, m.Version)
1017 }
1018 reportError(q, fmt.Errorf("%v matches packages in %v but not %v: specify a different version for module %s", q, curM, version, m.Path))
1019 continue
1020 }
1021 }
1022
1023
1024
1025
1026
1027
1028 reportError(q, fmt.Errorf("internal error: selected %v instead of %v", curM, rev.Version))
1029 }
1030 }
1031 }
1032
1033
1034
1035
1036
1037
1038
1039 func (r *resolver) performPathQueries(ld *modload.Loader, ctx context.Context) {
1040 for _, q := range r.pathQueries {
1041 q := q
1042 r.work.Add(func() {
1043 if q.version == "none" {
1044 r.queryNone(ld, ctx, q)
1045 } else {
1046 r.queryPath(ld, ctx, q)
1047 }
1048 })
1049 }
1050 <-r.work.Idle()
1051 }
1052
1053
1054
1055
1056
1057 func (r *resolver) queryPath(ld *modload.Loader, ctx context.Context, q *query) {
1058 q.pathOnce(q.pattern, func() pathSet {
1059 if search.IsMetaPackage(q.pattern) || q.isWildcard() {
1060 panic(fmt.Sprintf("internal error: queryPath called with pattern %q", q.pattern))
1061 }
1062 if q.version == "none" {
1063 panic(`internal error: queryPath called with version "none"`)
1064 }
1065
1066 if search.IsStandardImportPath(q.pattern) {
1067 stdOnly := module.Version{}
1068 packages, _ := r.matchInModule(ld, ctx, q.pattern, stdOnly)
1069 if len(packages) > 0 {
1070 if q.rawVersion != "" {
1071 return errSet(fmt.Errorf("can't request explicit version %q of standard library package %s", q.version, q.pattern))
1072 }
1073
1074 q.matchesPackages = true
1075 return pathSet{}
1076 }
1077 }
1078
1079 pkgMods, mod, err := r.queryPattern(ld, ctx, q.pattern, q.version, r.initialSelected)
1080 if err != nil {
1081 return errSet(err)
1082 }
1083 return pathSet{pkgMods: pkgMods, mod: mod}
1084 })
1085 }
1086
1087
1088
1089 func (r *resolver) performToolQueries(ld *modload.Loader, ctx context.Context) {
1090 for _, q := range r.toolQueries {
1091 for tool := range ld.MainModules.Tools() {
1092 q.pathOnce(tool, func() pathSet {
1093 pkgMods, err := r.queryPackages(ld, ctx, tool, q.version, r.initialSelected)
1094 return pathSet{pkgMods: pkgMods, err: err}
1095 })
1096 }
1097 }
1098 }
1099
1100
1101
1102 func (r *resolver) performWorkQueries(ld *modload.Loader, ctx context.Context) {
1103 for _, q := range r.workQueries {
1104 q.pathOnce(q.pattern, func() pathSet {
1105
1106
1107
1108 if len(ld.MainModules.Versions()) != 1 {
1109 panic("internal error: number of main modules is not exactly one in resolution phase of go get")
1110 }
1111 mainModule := ld.MainModules.Versions()[0]
1112
1113
1114
1115
1116
1117 match := modload.MatchInModule(ld, ctx, q.pattern, mainModule, imports.AnyTags())
1118 if len(match.Errs) > 0 {
1119 return pathSet{err: match.Errs[0]}
1120 }
1121 if len(match.Pkgs) == 0 {
1122 search.WarnUnmatched([]*search.Match{match})
1123 return pathSet{}
1124 }
1125
1126 return pathSet{pkgMods: []module.Version{mainModule}}
1127 })
1128 }
1129 }
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139 func (r *resolver) performPatternAllQueries(ld *modload.Loader, ctx context.Context) {
1140 if len(r.patternAllQueries) == 0 {
1141 return
1142 }
1143
1144 findPackage := func(ctx context.Context, path string, m module.Version) (versionOk bool) {
1145 versionOk = true
1146 for _, q := range r.patternAllQueries {
1147 q.pathOnce(path, func() pathSet {
1148 pkgMods, err := r.queryPackages(ld, ctx, path, q.version, r.initialSelected)
1149 if len(pkgMods) != 1 || pkgMods[0] != m {
1150
1151
1152
1153
1154
1155 versionOk = false
1156 }
1157 return pathSet{pkgMods: pkgMods, err: err}
1158 })
1159 }
1160 return versionOk
1161 }
1162
1163 r.loadPackages(ld, ctx, []string{"all"}, findPackage)
1164
1165
1166
1167
1168
1169 for _, q := range r.patternAllQueries {
1170 sort.Slice(q.candidates, func(i, j int) bool {
1171 return q.candidates[i].path < q.candidates[j].path
1172 })
1173 }
1174 }
1175
1176
1177
1178
1179
1180
1181
1182
1183 func (r *resolver) findAndUpgradeImports(ld *modload.Loader, ctx context.Context, queries []*query) (upgrades []pathSet) {
1184 patterns := make([]string, 0, len(queries))
1185 for _, q := range queries {
1186 if q.matchesPackages {
1187 patterns = append(patterns, q.pattern)
1188 }
1189 }
1190 if len(patterns) == 0 {
1191 return nil
1192 }
1193
1194
1195
1196 var mu sync.Mutex
1197
1198 findPackage := func(ctx context.Context, path string, m module.Version) (versionOk bool) {
1199 version := "latest"
1200 if m.Path != "" {
1201 if getU.version == "" {
1202
1203 return true
1204 }
1205 if _, ok := r.resolvedVersion[m.Path]; ok {
1206
1207
1208 return true
1209 }
1210 version = getU.version
1211 }
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224 pkgMods, err := r.queryPackages(ld, ctx, path, version, r.selected)
1225 for _, u := range pkgMods {
1226 if u == m {
1227
1228
1229 return true
1230 }
1231 }
1232
1233 if err != nil {
1234 if isNoSuchPackageVersion(err) || (m.Path == "" && module.CheckPath(path) != nil) {
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245 return true
1246 }
1247 }
1248
1249 mu.Lock()
1250 upgrades = append(upgrades, pathSet{path: path, pkgMods: pkgMods, err: err})
1251 mu.Unlock()
1252 return false
1253 }
1254
1255 r.loadPackages(ld, ctx, patterns, findPackage)
1256
1257
1258
1259
1260
1261 sort.Slice(upgrades, func(i, j int) bool {
1262 return upgrades[i].path < upgrades[j].path
1263 })
1264 return upgrades
1265 }
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279 func (r *resolver) loadPackages(ld *modload.Loader, ctx context.Context, patterns []string, findPackage func(ctx context.Context, path string, m module.Version) (versionOk bool)) {
1280 opts := modload.PackageOpts{
1281 Tags: imports.AnyTags(),
1282 VendorModulesInGOROOTSrc: true,
1283 LoadTests: *getT,
1284 AssumeRootsImported: true,
1285 SilencePackageErrors: true,
1286 Switcher: toolchain.NewSwitcher(ld),
1287 }
1288
1289 opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error {
1290 if m.Path == "" || m.Version == "" {
1291
1292
1293 return nil
1294 }
1295 if ok := findPackage(ctx, path, m); !ok {
1296 return errVersionChange
1297 }
1298 return nil
1299 }
1300
1301 _, pkgs := modload.LoadPackages(ld, ctx, opts, patterns...)
1302 for _, pkgPath := range pkgs {
1303 const (
1304 parentPath = ""
1305 parentIsStd = false
1306 )
1307 _, _, err := modload.Lookup(ld, parentPath, parentIsStd, pkgPath)
1308 if err == nil {
1309 continue
1310 }
1311 if errors.Is(err, errVersionChange) {
1312
1313 continue
1314 }
1315 if r.workspace != nil && r.workspace.hasPackage(pkgPath) {
1316
1317 continue
1318 }
1319
1320 if _, ok := errors.AsType[*modload.ImportMissingError](err); !ok {
1321 if _, ok := errors.AsType[*modload.AmbiguousImportError](err); !ok {
1322
1323
1324
1325 continue
1326 }
1327 }
1328
1329 path := pkgPath
1330 r.work.Add(func() {
1331 findPackage(ctx, path, module.Version{})
1332 })
1333 }
1334 <-r.work.Idle()
1335 }
1336
1337
1338
1339 var errVersionChange = errors.New("version change needed")
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353 func (r *resolver) resolveQueries(ld *modload.Loader, ctx context.Context, queries []*query) (changed bool) {
1354 defer base.ExitIfErrors()
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366 resolved := 0
1367 for {
1368 prevResolved := resolved
1369
1370
1371
1372 sw := toolchain.NewSwitcher(ld)
1373 for _, q := range queries {
1374 for _, cs := range q.candidates {
1375 sw.Error(cs.err)
1376 }
1377 }
1378
1379
1380 if sw.NeedSwitch() {
1381 sw.Switch(ctx)
1382
1383
1384 base.Exit()
1385 }
1386
1387 for _, q := range queries {
1388 unresolved := q.candidates[:0]
1389
1390 for _, cs := range q.candidates {
1391 if cs.err != nil {
1392 reportError(q, cs.err)
1393 resolved++
1394 continue
1395 }
1396
1397 filtered, isPackage, m, unique := r.disambiguate(ld, cs)
1398 if !unique {
1399 unresolved = append(unresolved, filtered)
1400 continue
1401 }
1402
1403 if m.Path == "" {
1404
1405
1406 isPackage, m = r.chooseArbitrarily(cs)
1407 }
1408 if isPackage {
1409 q.matchesPackages = true
1410 }
1411 r.resolve(ld, q, m)
1412 resolved++
1413 }
1414
1415 q.candidates = unresolved
1416 }
1417
1418 base.ExitIfErrors()
1419 if resolved == prevResolved {
1420 break
1421 }
1422 }
1423
1424 if resolved > 0 {
1425 if changed = r.updateBuildList(ld, ctx, nil); changed {
1426
1427
1428
1429 return true
1430 }
1431 }
1432
1433
1434
1435
1436
1437
1438
1439
1440 resolvedArbitrarily := 0
1441 for _, q := range queries {
1442 for _, cs := range q.candidates {
1443 isPackage, m := r.chooseArbitrarily(cs)
1444 if isPackage {
1445 q.matchesPackages = true
1446 }
1447 r.resolve(ld, q, m)
1448 resolvedArbitrarily++
1449 }
1450 }
1451 if resolvedArbitrarily > 0 {
1452 changed = r.updateBuildList(ld, ctx, nil)
1453 }
1454 return changed
1455 }
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468 func (r *resolver) applyUpgrades(ld *modload.Loader, ctx context.Context, upgrades []pathSet) (changed bool) {
1469 defer base.ExitIfErrors()
1470 sw := toolchain.NewSwitcher(ld)
1471
1472
1473
1474
1475 var tentative []module.Version
1476 for _, cs := range upgrades {
1477 if cs.err != nil {
1478 sw.Error(cs.err)
1479 continue
1480 }
1481
1482 filtered, _, m, unique := r.disambiguate(ld, cs)
1483 if !unique {
1484 _, m = r.chooseArbitrarily(filtered)
1485 }
1486 if m.Path == "" {
1487
1488
1489 continue
1490 }
1491 tentative = append(tentative, m)
1492 }
1493
1494 sw.Switch(ctx)
1495 base.ExitIfErrors()
1496
1497 changed = r.updateBuildList(ld, ctx, tentative)
1498 return changed
1499 }
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511 func (r *resolver) disambiguate(s *modload.Loader, cs pathSet) (filtered pathSet, isPackage bool, m module.Version, unique bool) {
1512 if len(cs.pkgMods) == 0 && cs.mod.Path == "" {
1513 panic("internal error: resolveIfUnambiguous called with empty pathSet")
1514 }
1515
1516 for _, m := range cs.pkgMods {
1517 if _, ok := r.noneForPath(m.Path); ok {
1518
1519
1520 continue
1521 }
1522
1523 if s.MainModules.Contains(m.Path) {
1524 if m.Version == "" {
1525 return pathSet{}, true, m, true
1526 }
1527
1528 continue
1529 }
1530
1531 vr, ok := r.resolvedVersion[m.Path]
1532 if !ok {
1533
1534
1535 filtered.pkgMods = append(filtered.pkgMods, m)
1536 continue
1537 }
1538
1539 if vr.version != m.Version {
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550 continue
1551 }
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566 return pathSet{}, true, m, true
1567 }
1568
1569 if cs.mod.Path != "" {
1570 vr, ok := r.resolvedVersion[cs.mod.Path]
1571 if !ok || vr.version == cs.mod.Version {
1572 filtered.mod = cs.mod
1573 }
1574 }
1575
1576 if len(filtered.pkgMods) == 1 &&
1577 (filtered.mod.Path == "" || filtered.mod == filtered.pkgMods[0]) {
1578
1579
1580 return pathSet{}, true, filtered.pkgMods[0], true
1581 }
1582
1583 if len(filtered.pkgMods) == 0 {
1584
1585
1586
1587
1588 return pathSet{}, false, filtered.mod, true
1589 }
1590
1591
1592
1593 return filtered, false, module.Version{}, false
1594 }
1595
1596
1597
1598
1599
1600
1601
1602
1603 func (r *resolver) chooseArbitrarily(cs pathSet) (isPackage bool, m module.Version) {
1604
1605 for _, m := range cs.pkgMods {
1606 if r.initialSelected(m.Path) != "none" {
1607 return true, m
1608 }
1609 }
1610
1611
1612 if len(cs.pkgMods) > 0 {
1613 return true, cs.pkgMods[0]
1614 }
1615
1616 return false, cs.mod
1617 }
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628 func (r *resolver) checkPackageProblems(ld *modload.Loader, ctx context.Context, pkgPatterns []string) {
1629 defer base.ExitIfErrors()
1630
1631
1632
1633
1634
1635
1636
1637
1638 var exitWorkspace func()
1639 if r.workspace != nil && r.workspace.hasModule(ld.MainModules.Versions()[0].Path) {
1640 var err error
1641 exitWorkspace, err = modload.EnterWorkspace(ld, ctx)
1642 if err != nil {
1643
1644
1645
1646
1647
1648 toolchain.SwitchOrFatal(ld, ctx, err)
1649 }
1650 }
1651
1652
1653
1654
1655
1656 type modFlags int
1657 const (
1658 resolved modFlags = 1 << iota
1659 named
1660 hasPkg
1661 direct
1662 )
1663 relevantMods := make(map[module.Version]modFlags)
1664 for path, reason := range r.resolvedVersion {
1665 m := module.Version{Path: path, Version: reason.version}
1666 relevantMods[m] |= resolved
1667 }
1668
1669
1670 if len(pkgPatterns) > 0 {
1671
1672
1673 pkgOpts := modload.PackageOpts{
1674 VendorModulesInGOROOTSrc: true,
1675 LoadTests: *getT,
1676 ResolveMissingImports: false,
1677 AllowErrors: true,
1678 SilenceNoGoErrors: true,
1679 }
1680 matches, pkgs := modload.LoadPackages(ld, ctx, pkgOpts, pkgPatterns...)
1681 for _, m := range matches {
1682 if len(m.Errs) > 0 {
1683 base.SetExitStatus(1)
1684 break
1685 }
1686 }
1687 for _, pkg := range pkgs {
1688 if dir, _, err := modload.Lookup(ld, "", false, pkg); err != nil {
1689 if dir != "" && errors.Is(err, imports.ErrNoGo) {
1690
1691
1692
1693
1694
1695
1696
1697 continue
1698 }
1699
1700 base.SetExitStatus(1)
1701 if ambiguousErr, ok := errors.AsType[*modload.AmbiguousImportError](err); ok {
1702 for _, m := range ambiguousErr.Modules {
1703 relevantMods[m] |= hasPkg
1704 }
1705 }
1706 }
1707 if m := ld.PackageModule(pkg); m.Path != "" {
1708 relevantMods[m] |= hasPkg
1709 }
1710 }
1711 for _, match := range matches {
1712 for _, pkg := range match.Pkgs {
1713 m := ld.PackageModule(pkg)
1714 relevantMods[m] |= named
1715 }
1716 }
1717 }
1718
1719 reqs := modload.LoadModFile(ld, ctx)
1720 for m := range relevantMods {
1721 if reqs.IsDirect(m.Path) {
1722 relevantMods[m] |= direct
1723 }
1724 }
1725
1726
1727
1728
1729 type modMessage struct {
1730 m module.Version
1731 message string
1732 }
1733 retractions := make([]modMessage, 0, len(relevantMods))
1734 for m, flags := range relevantMods {
1735 if flags&(resolved|named|hasPkg) != 0 {
1736 retractions = append(retractions, modMessage{m: m})
1737 }
1738 }
1739 sort.Slice(retractions, func(i, j int) bool { return retractions[i].m.Path < retractions[j].m.Path })
1740 for i := range retractions {
1741 i := i
1742 r.work.Add(func() {
1743 err := ld.CheckRetractions(ctx, retractions[i].m)
1744 if _, ok := errors.AsType[*modload.ModuleRetractedError](err); ok {
1745 retractions[i].message = err.Error()
1746 }
1747 })
1748 }
1749
1750
1751
1752
1753
1754 deprecations := make([]modMessage, 0, len(relevantMods))
1755 for m, flags := range relevantMods {
1756 if flags&(resolved|named) != 0 || flags&(hasPkg|direct) == hasPkg|direct {
1757 deprecations = append(deprecations, modMessage{m: m})
1758 }
1759 }
1760 sort.Slice(deprecations, func(i, j int) bool { return deprecations[i].m.Path < deprecations[j].m.Path })
1761 for i := range deprecations {
1762 i := i
1763 r.work.Add(func() {
1764 deprecation, err := modload.CheckDeprecation(ld, ctx, deprecations[i].m)
1765 if err != nil || deprecation == "" {
1766 return
1767 }
1768 deprecations[i].message = modload.ShortMessage(deprecation, "")
1769 })
1770 }
1771
1772
1773
1774 if exitWorkspace != nil {
1775
1776
1777
1778 <-r.work.Idle()
1779 exitWorkspace()
1780 }
1781
1782
1783
1784
1785
1786
1787
1788
1789 sumErrs := make([]error, len(r.buildList))
1790 for i := range r.buildList {
1791 i := i
1792 m := r.buildList[i]
1793 mActual := m
1794 if mRepl := modload.Replacement(ld, m); mRepl.Path != "" {
1795 mActual = mRepl
1796 }
1797 old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]}
1798 if old.Version == "" {
1799 continue
1800 }
1801 oldActual := old
1802 if oldRepl := modload.Replacement(ld, old); oldRepl.Path != "" {
1803 oldActual = oldRepl
1804 }
1805 if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(ld.Fetcher(), oldActual) {
1806 continue
1807 }
1808 r.work.Add(func() {
1809 if _, err := ld.Fetcher().DownloadZip(ctx, mActual); err != nil {
1810 verb := "upgraded"
1811 if gover.ModCompare(m.Path, m.Version, old.Version) < 0 {
1812 verb = "downgraded"
1813 }
1814 replaced := ""
1815 if mActual != m {
1816 replaced = fmt.Sprintf(" (replaced by %s)", mActual)
1817 }
1818 err = fmt.Errorf("%s %s %s => %s%s: error finding sum for %s: %v", verb, m.Path, old.Version, m.Version, replaced, mActual, err)
1819 sumErrs[i] = err
1820 }
1821 })
1822 }
1823
1824 <-r.work.Idle()
1825
1826
1827
1828 for _, mm := range deprecations {
1829 if mm.message != "" {
1830 fmt.Fprintf(os.Stderr, "go: module %s is deprecated: %s\n", mm.m.Path, mm.message)
1831 }
1832 }
1833 var retractPath string
1834 for _, mm := range retractions {
1835 if mm.message != "" {
1836 fmt.Fprintf(os.Stderr, "go: warning: %v\n", mm.message)
1837 if retractPath == "" {
1838 retractPath = mm.m.Path
1839 } else {
1840 retractPath = "<module>"
1841 }
1842 }
1843 }
1844 if retractPath != "" {
1845 fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath)
1846 }
1847 for _, err := range sumErrs {
1848 if err != nil {
1849 base.Error(err)
1850 }
1851 }
1852 }
1853
1854
1855
1856
1857
1858
1859
1860
1861 func (r *resolver) reportChanges(oldReqs, newReqs []module.Version) {
1862 type change struct {
1863 path, old, new string
1864 }
1865 changes := make(map[string]change)
1866
1867
1868 for path, reason := range r.resolvedVersion {
1869 if gover.IsToolchain(path) {
1870 continue
1871 }
1872 old := r.initialVersion[path]
1873 new := reason.version
1874 if old != new && (old != "" || new != "none") {
1875 changes[path] = change{path, old, new}
1876 }
1877 }
1878
1879
1880 for _, req := range oldReqs {
1881 if gover.IsToolchain(req.Path) {
1882 continue
1883 }
1884 path := req.Path
1885 old := req.Version
1886 new := r.buildListVersion[path]
1887 if old != new {
1888 changes[path] = change{path, old, new}
1889 }
1890 }
1891 for _, req := range newReqs {
1892 if gover.IsToolchain(req.Path) {
1893 continue
1894 }
1895 path := req.Path
1896 old := r.initialVersion[path]
1897 new := req.Version
1898 if old != new {
1899 changes[path] = change{path, old, new}
1900 }
1901 }
1902
1903
1904 toolchainVersions := func(reqs []module.Version) (goV, toolchain string) {
1905 for _, req := range reqs {
1906 if req.Path == "go" {
1907 goV = req.Version
1908 }
1909 if req.Path == "toolchain" {
1910 toolchain = req.Version
1911 }
1912 }
1913 return
1914 }
1915 oldGo, oldToolchain := toolchainVersions(oldReqs)
1916 newGo, newToolchain := toolchainVersions(newReqs)
1917 if oldGo != newGo {
1918 changes["go"] = change{"go", oldGo, newGo}
1919 }
1920 if oldToolchain != newToolchain {
1921 changes["toolchain"] = change{"toolchain", oldToolchain, newToolchain}
1922 }
1923
1924 sortedChanges := make([]change, 0, len(changes))
1925 for _, c := range changes {
1926 sortedChanges = append(sortedChanges, c)
1927 }
1928 sort.Slice(sortedChanges, func(i, j int) bool {
1929 pi := sortedChanges[i].path
1930 pj := sortedChanges[j].path
1931 if pi == pj {
1932 return false
1933 }
1934
1935 switch {
1936 case pi == "go":
1937 return true
1938 case pj == "go":
1939 return false
1940 case pi == "toolchain":
1941 return true
1942 case pj == "toolchain":
1943 return false
1944 }
1945 return pi < pj
1946 })
1947
1948 for _, c := range sortedChanges {
1949 if c.old == "" {
1950 fmt.Fprintf(os.Stderr, "go: added %s %s\n", c.path, c.new)
1951 } else if c.new == "none" || c.new == "" {
1952 fmt.Fprintf(os.Stderr, "go: removed %s %s\n", c.path, c.old)
1953 } else if gover.ModCompare(c.path, c.new, c.old) > 0 {
1954 fmt.Fprintf(os.Stderr, "go: upgraded %s %s => %s\n", c.path, c.old, c.new)
1955 if c.path == "go" && gover.Compare(c.old, gover.ExplicitIndirectVersion) < 0 && gover.Compare(c.new, gover.ExplicitIndirectVersion) >= 0 {
1956 fmt.Fprintf(os.Stderr, "\tnote: expanded dependencies to upgrade to go %s or higher; run 'go mod tidy' to clean up\n", gover.ExplicitIndirectVersion)
1957 }
1958
1959 } else {
1960 fmt.Fprintf(os.Stderr, "go: downgraded %s %s => %s\n", c.path, c.old, c.new)
1961 }
1962 }
1963
1964
1965
1966
1967
1968 }
1969
1970
1971
1972
1973 func (r *resolver) resolve(s *modload.Loader, q *query, m module.Version) {
1974 if m.Path == "" {
1975 panic("internal error: resolving a module.Version with an empty path")
1976 }
1977
1978 if s.MainModules.Contains(m.Path) && m.Version != "" {
1979 reportError(q, &modload.QueryMatchesMainModulesError{
1980 MainModules: []module.Version{{Path: m.Path}},
1981 Pattern: q.pattern,
1982 Query: q.version,
1983 PatternIsModule: s.MainModules.Contains(q.pattern),
1984 })
1985 return
1986 }
1987
1988 vr, ok := r.resolvedVersion[m.Path]
1989 if ok && vr.version != m.Version {
1990 reportConflict(q, m, vr)
1991 return
1992 }
1993 r.resolvedVersion[m.Path] = versionReason{m.Version, q}
1994 q.resolved = append(q.resolved, m)
1995 }
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006 func (r *resolver) updateBuildList(ld *modload.Loader, ctx context.Context, additions []module.Version) (changed bool) {
2007 defer base.ExitIfErrors()
2008
2009 resolved := make([]module.Version, 0, len(r.resolvedVersion))
2010 for mPath, rv := range r.resolvedVersion {
2011 if !ld.MainModules.Contains(mPath) {
2012 resolved = append(resolved, module.Version{Path: mPath, Version: rv.version})
2013 }
2014 }
2015
2016 changed, err := modload.EditBuildList(ld, ctx, additions, resolved)
2017 if err != nil {
2018 if errors.Is(err, gover.ErrTooNew) {
2019 toolchain.SwitchOrFatal(ld, ctx, err)
2020 }
2021
2022 constraint, ok := errors.AsType[*modload.ConstraintError](err)
2023 if !ok {
2024 base.Fatal(err)
2025 }
2026
2027 if cfg.BuildV {
2028
2029 for _, c := range constraint.Conflicts {
2030 fmt.Fprintf(os.Stderr, "go: %v\n", c.String())
2031 }
2032 }
2033
2034
2035
2036
2037 reason := func(m module.Version) string {
2038 rv, ok := r.resolvedVersion[m.Path]
2039 if !ok {
2040 return fmt.Sprintf("(INTERNAL ERROR: no reason found for %v)", m)
2041 }
2042 return rv.reason.ResolvedString(module.Version{Path: m.Path, Version: rv.version})
2043 }
2044 for _, c := range constraint.Conflicts {
2045 adverb := ""
2046 if len(c.Path) > 2 {
2047 adverb = "indirectly "
2048 }
2049 firstReason := reason(c.Path[0])
2050 last := c.Path[len(c.Path)-1]
2051 if c.Err != nil {
2052 base.Errorf("go: %v %srequires %v: %v", firstReason, adverb, last, c.UnwrapModuleError())
2053 } else {
2054 base.Errorf("go: %v %srequires %v, not %v", firstReason, adverb, last, reason(c.Constraint))
2055 }
2056 }
2057 return false
2058 }
2059 if !changed {
2060 return false
2061 }
2062
2063 mg, err := modload.LoadModGraph(ld, ctx, "")
2064 if err != nil {
2065 toolchain.SwitchOrFatal(ld, ctx, err)
2066 }
2067
2068 r.buildList = mg.BuildList()
2069 r.buildListVersion = make(map[string]string, len(r.buildList))
2070 for _, m := range r.buildList {
2071 r.buildListVersion[m.Path] = m.Version
2072 }
2073 return true
2074 }
2075
2076 func reqsFromGoMod(f *modfile.File) []module.Version {
2077 reqs := make([]module.Version, len(f.Require), 2+len(f.Require))
2078 for i, r := range f.Require {
2079 reqs[i] = r.Mod
2080 }
2081 if f.Go != nil {
2082 reqs = append(reqs, module.Version{Path: "go", Version: f.Go.Version})
2083 }
2084 if f.Toolchain != nil {
2085 reqs = append(reqs, module.Version{Path: "toolchain", Version: f.Toolchain.Name})
2086 }
2087 return reqs
2088 }
2089
2090
2091
2092
2093 func isNoSuchModuleVersion(err error) bool {
2094 if errors.Is(err, os.ErrNotExist) {
2095 return true
2096 }
2097 _, ok := errors.AsType[*modload.NoMatchingVersionError](err)
2098 return ok
2099 }
2100
2101
2102
2103
2104
2105 func isNoSuchPackageVersion(err error) bool {
2106 if isNoSuchModuleVersion(err) {
2107 return true
2108 }
2109 _, ok := errors.AsType[*modload.PackageNotInModuleError](err)
2110 return ok
2111 }
2112
2113
2114
2115 type workspace struct {
2116 modules map[string]string
2117 }
2118
2119
2120
2121 func loadWorkspace(workFilePath string) *workspace {
2122 if workFilePath == "" {
2123
2124 return nil
2125 }
2126
2127 _, modRoots, err := modload.LoadWorkFile(workFilePath)
2128 if err != nil {
2129 return nil
2130 }
2131
2132 w := &workspace{modules: make(map[string]string)}
2133 for _, modRoot := range modRoots {
2134 modFile := filepath.Join(modRoot, "go.mod")
2135 _, f, err := modload.ReadModFile(modFile, nil)
2136 if err != nil {
2137 continue
2138 }
2139 w.modules[f.Module.Mod.Path] = modRoot
2140 }
2141
2142 return w
2143 }
2144
2145
2146
2147 func (w *workspace) hasPackage(pkgpath string) bool {
2148 for modPath, modroot := range w.modules {
2149 if modload.PkgIsInLocalModule(pkgpath, modPath, modroot) {
2150 return true
2151 }
2152 }
2153 return false
2154 }
2155
2156
2157
2158 func (w *workspace) hasModule(modPath string) bool {
2159 _, ok := w.modules[modPath]
2160 return ok
2161 }
2162
View as plain text