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