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