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