github.com/bir3/gocompiler@v0.9.2202/src/cmd/gocmd/internal/modget/get.go (about) 1 // Copyright 2018 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package modget implements the module-aware “go get” command. 6 package modget 7 8 // The arguments to 'go get' are patterns with optional version queries, with 9 // the version queries defaulting to "upgrade". 10 // 11 // The patterns are normally interpreted as package patterns. However, if a 12 // pattern cannot match a package, it is instead interpreted as a *module* 13 // pattern. For version queries such as "upgrade" and "patch" that depend on the 14 // selected version of a module (or of the module containing a package), 15 // whether a pattern denotes a package or module may change as updates are 16 // applied (see the example in mod_get_patchmod.txt). 17 // 18 // There are a few other ambiguous cases to resolve, too. A package can exist in 19 // two different modules at the same version: for example, the package 20 // example.com/foo might be found in module example.com and also in module 21 // example.com/foo, and those modules may have independent v0.1.0 tags — so the 22 // input 'example.com/foo@v0.1.0' could syntactically refer to the variant of 23 // the package loaded from either module! (See mod_get_ambiguous_pkg.txt.) 24 // If the argument is ambiguous, the user can often disambiguate by specifying 25 // explicit versions for *all* of the potential module paths involved. 26 27 import ( 28 "context" 29 "errors" 30 "fmt" 31 "os" 32 "path/filepath" 33 "runtime" 34 "sort" 35 "strings" 36 "sync" 37 38 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/base" 39 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/cfg" 40 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/gover" 41 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/imports" 42 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/modfetch" 43 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/modload" 44 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/par" 45 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/search" 46 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/toolchain" 47 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/work" 48 49 "github.com/bir3/gocompiler/src/xvendor/golang.org/x/mod/modfile" 50 "github.com/bir3/gocompiler/src/xvendor/golang.org/x/mod/module" 51 ) 52 53 var CmdGet = &base.Command{ 54 // Note: flags below are listed explicitly because they're the most common. 55 // Do not send CLs removing them because they're covered by [get flags]. 56 UsageLine: "go get [-t] [-u] [-v] [build flags] [packages]", 57 Short: "add dependencies to current module and install them", 58 Long: ` 59 Get resolves its command-line arguments to packages at specific module versions, 60 updates go.mod to require those versions, and downloads source code into the 61 module cache. 62 63 To add a dependency for a package or upgrade it to its latest version: 64 65 go get example.com/pkg 66 67 To upgrade or downgrade a package to a specific version: 68 69 go get example.com/pkg@v1.2.3 70 71 To remove a dependency on a module and downgrade modules that require it: 72 73 go get example.com/mod@none 74 75 To upgrade the minimum required Go version to the latest released Go version: 76 77 go get go@latest 78 79 To upgrade the Go toolchain to the latest patch release of the current Go toolchain: 80 81 go get toolchain@patch 82 83 See https://golang.org/ref/mod#go-get for details. 84 85 In earlier versions of Go, 'go get' was used to build and install packages. 86 Now, 'go get' is dedicated to adjusting dependencies in go.mod. 'go install' 87 may be used to build and install commands instead. When a version is specified, 88 'go install' runs in module-aware mode and ignores the go.mod file in the 89 current directory. For example: 90 91 go install example.com/pkg@v1.2.3 92 go install example.com/pkg@latest 93 94 See 'go help install' or https://golang.org/ref/mod#go-install for details. 95 96 'go get' accepts the following flags. 97 98 The -t flag instructs get to consider modules needed to build tests of 99 packages specified on the command line. 100 101 The -u flag instructs get to update modules providing dependencies 102 of packages named on the command line to use newer minor or patch 103 releases when available. 104 105 The -u=patch flag (not -u patch) also instructs get to update dependencies, 106 but changes the default to select patch releases. 107 108 When the -t and -u flags are used together, get will update 109 test dependencies as well. 110 111 The -x flag prints commands as they are executed. This is useful for 112 debugging version control commands when a module is downloaded directly 113 from a repository. 114 115 For more about modules, see https://golang.org/ref/mod. 116 117 For more about using 'go get' to update the minimum Go version and 118 suggested Go toolchain, see https://go.dev/doc/toolchain. 119 120 For more about specifying packages, see 'go help packages'. 121 122 This text describes the behavior of get using modules to manage source 123 code and dependencies. If instead the go command is running in GOPATH 124 mode, the details of get's flags and effects change, as does 'go help get'. 125 See 'go help gopath-get'. 126 127 See also: go build, go install, go clean, go mod. 128 `, 129 } 130 131 var HelpVCS = &base.Command{ 132 UsageLine: "vcs", 133 Short: "controlling version control with GOVCS", 134 Long: ` 135 The 'go get' command can run version control commands like git 136 to download imported code. This functionality is critical to the decentralized 137 Go package ecosystem, in which code can be imported from any server, 138 but it is also a potential security problem, if a malicious server finds a 139 way to cause the invoked version control command to run unintended code. 140 141 To balance the functionality and security concerns, the 'go get' command 142 by default will only use git and hg to download code from public servers. 143 But it will use any known version control system (bzr, fossil, git, hg, svn) 144 to download code from private servers, defined as those hosting packages 145 matching the GOPRIVATE variable (see 'go help private'). The rationale behind 146 allowing only Git and Mercurial is that these two systems have had the most 147 attention to issues of being run as clients of untrusted servers. In contrast, 148 Bazaar, Fossil, and Subversion have primarily been used in trusted, 149 authenticated environments and are not as well scrutinized as attack surfaces. 150 151 The version control command restrictions only apply when using direct version 152 control access to download code. When downloading modules from a proxy, 153 'go get' uses the proxy protocol instead, which is always permitted. 154 By default, the 'go get' command uses the Go module mirror (proxy.golang.org) 155 for public packages and only falls back to version control for private 156 packages or when the mirror refuses to serve a public package (typically for 157 legal reasons). Therefore, clients can still access public code served from 158 Bazaar, Fossil, or Subversion repositories by default, because those downloads 159 use the Go module mirror, which takes on the security risk of running the 160 version control commands using a custom sandbox. 161 162 The GOVCS variable can be used to change the allowed version control systems 163 for specific packages (identified by a module or import path). 164 The GOVCS variable applies when building package in both module-aware mode 165 and GOPATH mode. When using modules, the patterns match against the module path. 166 When using GOPATH, the patterns match against the import path corresponding to 167 the root of the version control repository. 168 169 The general form of the GOVCS setting is a comma-separated list of 170 pattern:vcslist rules. The pattern is a glob pattern that must match 171 one or more leading elements of the module or import path. The vcslist 172 is a pipe-separated list of allowed version control commands, or "all" 173 to allow use of any known command, or "off" to disallow all commands. 174 Note that if a module matches a pattern with vcslist "off", it may still be 175 downloaded if the origin server uses the "mod" scheme, which instructs the 176 go command to download the module using the GOPROXY protocol. 177 The earliest matching pattern in the list applies, even if later patterns 178 might also match. 179 180 For example, consider: 181 182 GOVCS=github.com:git,evil.com:off,*:git|hg 183 184 With this setting, code with a module or import path beginning with 185 github.com/ can only use git; paths on evil.com cannot use any version 186 control command, and all other paths (* matches everything) can use 187 only git or hg. 188 189 The special patterns "public" and "private" match public and private 190 module or import paths. A path is private if it matches the GOPRIVATE 191 variable; otherwise it is public. 192 193 If no rules in the GOVCS variable match a particular module or import path, 194 the 'go get' command applies its default rule, which can now be summarized 195 in GOVCS notation as 'public:git|hg,private:all'. 196 197 To allow unfettered use of any version control system for any package, use: 198 199 GOVCS=*:all 200 201 To disable all use of version control, use: 202 203 GOVCS=*:off 204 205 The 'go env -w' command (see 'go help env') can be used to set the GOVCS 206 variable for future go command invocations. 207 `, 208 } 209 210 var ( 211 getD = CmdGet.Flag.Bool("d", true, "") 212 getF = CmdGet.Flag.Bool("f", false, "") 213 getFix = CmdGet.Flag.Bool("fix", false, "") 214 getM = CmdGet.Flag.Bool("m", false, "") 215 getT = CmdGet.Flag.Bool("t", false, "") 216 getU upgradeFlag 217 getInsecure = CmdGet.Flag.Bool("insecure", false, "") 218 // -v is cfg.BuildV 219 ) 220 221 // upgradeFlag is a custom flag.Value for -u. 222 type upgradeFlag struct { 223 rawVersion string 224 version string 225 } 226 227 func (*upgradeFlag) IsBoolFlag() bool { return true } // allow -u 228 229 func (v *upgradeFlag) Set(s string) error { 230 if s == "false" { 231 v.version = "" 232 v.rawVersion = "" 233 } else if s == "true" { 234 v.version = "upgrade" 235 v.rawVersion = "" 236 } else { 237 v.version = s 238 v.rawVersion = s 239 } 240 return nil 241 } 242 243 func (v *upgradeFlag) String() string { return "" } 244 245 func init() { 246 work.AddBuildFlags(CmdGet, work.OmitModFlag) 247 CmdGet.Run = runGet // break init loop 248 CmdGet.Flag.Var(&getU, "u", "") 249 } 250 251 func runGet(ctx context.Context, cmd *base.Command, args []string) { 252 switch getU.version { 253 case "", "upgrade", "patch": 254 // ok 255 default: 256 base.Fatalf("go: unknown upgrade flag -u=%s", getU.rawVersion) 257 } 258 // TODO(#43684): in the future (Go 1.20), warn that -d is a no-op. 259 if !*getD { 260 base.Fatalf("go: -d flag may not be disabled") 261 } 262 if *getF { 263 fmt.Fprintf(os.Stderr, "go: -f flag is a no-op when using modules\n") 264 } 265 if *getFix { 266 fmt.Fprintf(os.Stderr, "go: -fix flag is a no-op when using modules\n") 267 } 268 if *getM { 269 base.Fatalf("go: -m flag is no longer supported") 270 } 271 if *getInsecure { 272 base.Fatalf("go: -insecure flag is no longer supported; use GOINSECURE instead") 273 } 274 275 modload.ForceUseModules = true 276 277 // Do not allow any updating of go.mod until we've applied 278 // all the requested changes and checked that the result matches 279 // what was requested. 280 modload.ExplicitWriteGoMod = true 281 282 // Allow looking up modules for import paths when outside of a module. 283 // 'go get' is expected to do this, unlike other commands. 284 modload.AllowMissingModuleImports() 285 286 // 'go get' no longer builds or installs packages, so there's nothing to do 287 // if there's no go.mod file. 288 // TODO(#40775): make modload.Init return ErrNoModRoot instead of exiting. 289 // We could handle that here by printing a different message. 290 modload.Init() 291 if !modload.HasModRoot() { 292 base.Fatalf("go: go.mod file not found in current directory or any parent directory.\n" + 293 "\t'go get' is no longer supported outside a module.\n" + 294 "\tTo build and install a command, use 'go install' with a version,\n" + 295 "\tlike 'go install example.com/cmd@latest'\n" + 296 "\tFor more information, see https://golang.org/doc/go-get-install-deprecation\n" + 297 "\tor run 'go help get' or 'go help install'.") 298 } 299 300 dropToolchain, queries := parseArgs(ctx, args) 301 opts := modload.WriteOpts{ 302 DropToolchain: dropToolchain, 303 } 304 for _, q := range queries { 305 if q.pattern == "toolchain" { 306 opts.ExplicitToolchain = true 307 } 308 } 309 310 r := newResolver(ctx, queries) 311 r.performLocalQueries(ctx) 312 r.performPathQueries(ctx) 313 314 for { 315 r.performWildcardQueries(ctx) 316 r.performPatternAllQueries(ctx) 317 318 if changed := r.resolveQueries(ctx, queries); changed { 319 // 'go get' arguments can be (and often are) package patterns rather than 320 // (just) modules. A package can be provided by any module with a prefix 321 // of its import path, and a wildcard can even match packages in modules 322 // with totally different paths. Because of these effects, and because any 323 // change to the selected version of a module can bring in entirely new 324 // module paths as dependencies, we need to reissue queries whenever we 325 // change the build list. 326 // 327 // The result of any version query for a given module — even "upgrade" or 328 // "patch" — is always relative to the build list at the start of 329 // the 'go get' command, not an intermediate state, and is therefore 330 // deterministic and therefore cacheable, and the constraints on the 331 // selected version of each module can only narrow as we iterate. 332 // 333 // "all" is functionally very similar to a wildcard pattern. The set of 334 // packages imported by the main module does not change, and the query 335 // result for the module containing each such package also does not change 336 // (it is always relative to the initial build list, before applying 337 // queries). So the only way that the result of an "all" query can change 338 // is if some matching package moves from one module in the build list 339 // to another, which should not happen very often. 340 continue 341 } 342 343 // When we load imports, we detect the following conditions: 344 // 345 // - missing transitive dependencies that need to be resolved from outside the 346 // current build list (note that these may add new matches for existing 347 // pattern queries!) 348 // 349 // - transitive dependencies that didn't match any other query, 350 // but need to be upgraded due to the -u flag 351 // 352 // - ambiguous import errors. 353 // TODO(#27899): Try to resolve ambiguous import errors automatically. 354 upgrades := r.findAndUpgradeImports(ctx, queries) 355 if changed := r.applyUpgrades(ctx, upgrades); changed { 356 continue 357 } 358 359 r.findMissingWildcards(ctx) 360 if changed := r.resolveQueries(ctx, r.wildcardQueries); changed { 361 continue 362 } 363 364 break 365 } 366 367 r.checkWildcardVersions(ctx) 368 369 var pkgPatterns []string 370 for _, q := range queries { 371 if q.matchesPackages { 372 pkgPatterns = append(pkgPatterns, q.pattern) 373 } 374 } 375 r.checkPackageProblems(ctx, pkgPatterns) 376 377 // Everything succeeded. Update go.mod. 378 oldReqs := reqsFromGoMod(modload.ModFile()) 379 380 if err := modload.WriteGoMod(ctx, opts); err != nil { 381 // A TooNewError can happen for 'go get go@newversion' 382 // when all the required modules are old enough 383 // but the command line is not. 384 // TODO(bcmills): modload.EditBuildList should catch this instead, 385 // and then this can be changed to base.Fatal(err). 386 toolchain.SwitchOrFatal(ctx, err) 387 } 388 389 newReqs := reqsFromGoMod(modload.ModFile()) 390 r.reportChanges(oldReqs, newReqs) 391 392 if gowork := modload.FindGoWork(base.Cwd()); gowork != "" { 393 wf, err := modload.ReadWorkFile(gowork) 394 if err == nil && modload.UpdateWorkGoVersion(wf, modload.MainModules.GoVersion()) { 395 modload.WriteWorkFile(gowork, wf) 396 } 397 } 398 } 399 400 // parseArgs parses command-line arguments and reports errors. 401 // 402 // The command-line arguments are of the form path@version or simply path, with 403 // implicit @upgrade. path@none is "downgrade away". 404 func parseArgs(ctx context.Context, rawArgs []string) (dropToolchain bool, queries []*query) { 405 defer base.ExitIfErrors() 406 407 for _, arg := range search.CleanPatterns(rawArgs) { 408 q, err := newQuery(arg) 409 if err != nil { 410 base.Error(err) 411 continue 412 } 413 414 if q.version == "none" { 415 switch q.pattern { 416 case "go": 417 base.Errorf("go: cannot use go@none") 418 continue 419 case "toolchain": 420 dropToolchain = true 421 continue 422 } 423 } 424 425 // If there were no arguments, CleanPatterns returns ".". Set the raw 426 // string back to "" for better errors. 427 if len(rawArgs) == 0 { 428 q.raw = "" 429 } 430 431 // Guard against 'go get x.go', a common mistake. 432 // Note that package and module paths may end with '.go', so only print an error 433 // if the argument has no version and either has no slash or refers to an existing file. 434 if strings.HasSuffix(q.raw, ".go") && q.rawVersion == "" { 435 if !strings.Contains(q.raw, "/") { 436 base.Errorf("go: %s: arguments must be package or module paths", q.raw) 437 continue 438 } 439 if fi, err := os.Stat(q.raw); err == nil && !fi.IsDir() { 440 base.Errorf("go: %s exists as a file, but 'go get' requires package arguments", q.raw) 441 continue 442 } 443 } 444 445 queries = append(queries, q) 446 } 447 448 return dropToolchain, queries 449 } 450 451 type resolver struct { 452 localQueries []*query // queries for absolute or relative paths 453 pathQueries []*query // package path literal queries in original order 454 wildcardQueries []*query // path wildcard queries in original order 455 patternAllQueries []*query // queries with the pattern "all" 456 457 // Indexed "none" queries. These are also included in the slices above; 458 // they are indexed here to speed up noneForPath. 459 nonesByPath map[string]*query // path-literal "@none" queries indexed by path 460 wildcardNones []*query // wildcard "@none" queries 461 462 // resolvedVersion maps each module path to the version of that module that 463 // must be selected in the final build list, along with the first query 464 // that resolved the module to that version (the “reason”). 465 resolvedVersion map[string]versionReason 466 467 buildList []module.Version 468 buildListVersion map[string]string // index of buildList (module path → version) 469 470 initialVersion map[string]string // index of the initial build list at the start of 'go get' 471 472 missing []pathSet // candidates for missing transitive dependencies 473 474 work *par.Queue 475 476 matchInModuleCache par.ErrCache[matchInModuleKey, []string] 477 } 478 479 type versionReason struct { 480 version string 481 reason *query 482 } 483 484 type matchInModuleKey struct { 485 pattern string 486 m module.Version 487 } 488 489 func newResolver(ctx context.Context, queries []*query) *resolver { 490 // LoadModGraph also sets modload.Target, which is needed by various resolver 491 // methods. 492 mg, err := modload.LoadModGraph(ctx, "") 493 if err != nil { 494 toolchain.SwitchOrFatal(ctx, err) 495 } 496 497 buildList := mg.BuildList() 498 initialVersion := make(map[string]string, len(buildList)) 499 for _, m := range buildList { 500 initialVersion[m.Path] = m.Version 501 } 502 503 r := &resolver{ 504 work: par.NewQueue(runtime.GOMAXPROCS(0)), 505 resolvedVersion: map[string]versionReason{}, 506 buildList: buildList, 507 buildListVersion: initialVersion, 508 initialVersion: initialVersion, 509 nonesByPath: map[string]*query{}, 510 } 511 512 for _, q := range queries { 513 if q.pattern == "all" { 514 r.patternAllQueries = append(r.patternAllQueries, q) 515 } else if q.patternIsLocal { 516 r.localQueries = append(r.localQueries, q) 517 } else if q.isWildcard() { 518 r.wildcardQueries = append(r.wildcardQueries, q) 519 } else { 520 r.pathQueries = append(r.pathQueries, q) 521 } 522 523 if q.version == "none" { 524 // Index "none" queries to make noneForPath more efficient. 525 if q.isWildcard() { 526 r.wildcardNones = append(r.wildcardNones, q) 527 } else { 528 // All "<path>@none" queries for the same path are identical; we only 529 // need to index one copy. 530 r.nonesByPath[q.pattern] = q 531 } 532 } 533 } 534 535 return r 536 } 537 538 // initialSelected returns the version of the module with the given path that 539 // was selected at the start of this 'go get' invocation. 540 func (r *resolver) initialSelected(mPath string) (version string) { 541 v, ok := r.initialVersion[mPath] 542 if !ok { 543 return "none" 544 } 545 return v 546 } 547 548 // selected returns the version of the module with the given path that is 549 // selected in the resolver's current build list. 550 func (r *resolver) selected(mPath string) (version string) { 551 v, ok := r.buildListVersion[mPath] 552 if !ok { 553 return "none" 554 } 555 return v 556 } 557 558 // noneForPath returns a "none" query matching the given module path, 559 // or found == false if no such query exists. 560 func (r *resolver) noneForPath(mPath string) (nq *query, found bool) { 561 if nq = r.nonesByPath[mPath]; nq != nil { 562 return nq, true 563 } 564 for _, nq := range r.wildcardNones { 565 if nq.matchesPath(mPath) { 566 return nq, true 567 } 568 } 569 return nil, false 570 } 571 572 // queryModule wraps modload.Query, substituting r.checkAllowedOr to decide 573 // allowed versions. 574 func (r *resolver) queryModule(ctx context.Context, mPath, query string, selected func(string) string) (module.Version, error) { 575 current := r.initialSelected(mPath) 576 rev, err := modload.Query(ctx, mPath, query, current, r.checkAllowedOr(query, selected)) 577 if err != nil { 578 return module.Version{}, err 579 } 580 return module.Version{Path: mPath, Version: rev.Version}, nil 581 } 582 583 // queryPackages wraps modload.QueryPackage, substituting r.checkAllowedOr to 584 // decide allowed versions. 585 func (r *resolver) queryPackages(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, err error) { 586 results, err := modload.QueryPackages(ctx, pattern, query, selected, r.checkAllowedOr(query, selected)) 587 if len(results) > 0 { 588 pkgMods = make([]module.Version, 0, len(results)) 589 for _, qr := range results { 590 pkgMods = append(pkgMods, qr.Mod) 591 } 592 } 593 return pkgMods, err 594 } 595 596 // queryPattern wraps modload.QueryPattern, substituting r.checkAllowedOr to 597 // decide allowed versions. 598 func (r *resolver) queryPattern(ctx context.Context, pattern, query string, selected func(string) string) (pkgMods []module.Version, mod module.Version, err error) { 599 results, modOnly, err := modload.QueryPattern(ctx, pattern, query, selected, r.checkAllowedOr(query, selected)) 600 if len(results) > 0 { 601 pkgMods = make([]module.Version, 0, len(results)) 602 for _, qr := range results { 603 pkgMods = append(pkgMods, qr.Mod) 604 } 605 } 606 if modOnly != nil { 607 mod = modOnly.Mod 608 } 609 return pkgMods, mod, err 610 } 611 612 // checkAllowedOr is like modload.CheckAllowed, but it always allows the requested 613 // and current versions (even if they are retracted or otherwise excluded). 614 func (r *resolver) checkAllowedOr(requested string, selected func(string) string) modload.AllowedFunc { 615 return func(ctx context.Context, m module.Version) error { 616 if m.Version == requested { 617 return modload.CheckExclusions(ctx, m) 618 } 619 if (requested == "upgrade" || requested == "patch") && m.Version == selected(m.Path) { 620 return nil 621 } 622 return modload.CheckAllowed(ctx, m) 623 } 624 } 625 626 // matchInModule is a caching wrapper around modload.MatchInModule. 627 func (r *resolver) matchInModule(ctx context.Context, pattern string, m module.Version) (packages []string, err error) { 628 return r.matchInModuleCache.Do(matchInModuleKey{pattern, m}, func() ([]string, error) { 629 match := modload.MatchInModule(ctx, pattern, m, imports.AnyTags()) 630 if len(match.Errs) > 0 { 631 return match.Pkgs, match.Errs[0] 632 } 633 return match.Pkgs, nil 634 }) 635 } 636 637 // queryNone adds a candidate set to q for each module matching q.pattern. 638 // Each candidate set has only one possible module version: the matched 639 // module at version "none". 640 // 641 // We interpret arguments to 'go get' as packages first, and fall back to 642 // modules second. However, no module exists at version "none", and therefore no 643 // package exists at that version either: we know that the argument cannot match 644 // any packages, and thus it must match modules instead. 645 func (r *resolver) queryNone(ctx context.Context, q *query) { 646 if search.IsMetaPackage(q.pattern) { 647 panic(fmt.Sprintf("internal error: queryNone called with pattern %q", q.pattern)) 648 } 649 650 if !q.isWildcard() { 651 q.pathOnce(q.pattern, func() pathSet { 652 hasModRoot := modload.HasModRoot() 653 if hasModRoot && modload.MainModules.Contains(q.pattern) { 654 v := module.Version{Path: q.pattern} 655 // The user has explicitly requested to downgrade their own module to 656 // version "none". This is not an entirely unreasonable request: it 657 // could plausibly mean “downgrade away everything that depends on any 658 // explicit version of the main module”, or “downgrade away the 659 // package with the same path as the main module, found in a module 660 // with a prefix of the main module's path”. 661 // 662 // However, neither of those behaviors would be consistent with the 663 // plain meaning of the query. To try to reduce confusion, reject the 664 // query explicitly. 665 return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{v}, Pattern: q.pattern, Query: q.version}) 666 } 667 668 return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}} 669 }) 670 } 671 672 for _, curM := range r.buildList { 673 if !q.matchesPath(curM.Path) { 674 continue 675 } 676 q.pathOnce(curM.Path, func() pathSet { 677 if modload.HasModRoot() && curM.Version == "" && modload.MainModules.Contains(curM.Path) { 678 return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version}) 679 } 680 return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}} 681 }) 682 } 683 } 684 685 func (r *resolver) performLocalQueries(ctx context.Context) { 686 for _, q := range r.localQueries { 687 q.pathOnce(q.pattern, func() pathSet { 688 absDetail := "" 689 if !filepath.IsAbs(q.pattern) { 690 if absPath, err := filepath.Abs(q.pattern); err == nil { 691 absDetail = fmt.Sprintf(" (%s)", absPath) 692 } 693 } 694 695 // Absolute paths like C:\foo and relative paths like ../foo... are 696 // restricted to matching packages in the main module. 697 pkgPattern, mainModule := modload.MainModules.DirImportPath(ctx, q.pattern) 698 if pkgPattern == "." { 699 modload.MustHaveModRoot() 700 var modRoots []string 701 for _, m := range modload.MainModules.Versions() { 702 modRoots = append(modRoots, modload.MainModules.ModRoot(m)) 703 } 704 var plural string 705 if len(modRoots) != 1 { 706 plural = "s" 707 } 708 return errSet(fmt.Errorf("%s%s is not within module%s rooted at %s", q.pattern, absDetail, plural, strings.Join(modRoots, ", "))) 709 } 710 711 match := modload.MatchInModule(ctx, pkgPattern, mainModule, imports.AnyTags()) 712 if len(match.Errs) > 0 { 713 return pathSet{err: match.Errs[0]} 714 } 715 716 if len(match.Pkgs) == 0 { 717 if q.raw == "" || q.raw == "." { 718 return errSet(fmt.Errorf("no package to get in current directory")) 719 } 720 if !q.isWildcard() { 721 modload.MustHaveModRoot() 722 return errSet(fmt.Errorf("%s%s is not a package in module rooted at %s", q.pattern, absDetail, modload.MainModules.ModRoot(mainModule))) 723 } 724 search.WarnUnmatched([]*search.Match{match}) 725 return pathSet{} 726 } 727 728 return pathSet{pkgMods: []module.Version{mainModule}} 729 }) 730 } 731 } 732 733 // performWildcardQueries populates the candidates for each query whose pattern 734 // is a wildcard. 735 // 736 // The candidates for a given module path matching (or containing a package 737 // matching) a wildcard query depend only on the initial build list, but the set 738 // of modules may be expanded by other queries, so wildcard queries need to be 739 // re-evaluated whenever a potentially-matching module path is added to the 740 // build list. 741 func (r *resolver) performWildcardQueries(ctx context.Context) { 742 for _, q := range r.wildcardQueries { 743 q := q 744 r.work.Add(func() { 745 if q.version == "none" { 746 r.queryNone(ctx, q) 747 } else { 748 r.queryWildcard(ctx, q) 749 } 750 }) 751 } 752 <-r.work.Idle() 753 } 754 755 // queryWildcard adds a candidate set to q for each module for which: 756 // - some version of the module is already in the build list, and 757 // - that module exists at some version matching q.version, and 758 // - either the module path itself matches q.pattern, or some package within 759 // the module at q.version matches q.pattern. 760 func (r *resolver) queryWildcard(ctx context.Context, q *query) { 761 // For wildcard patterns, modload.QueryPattern only identifies modules 762 // matching the prefix of the path before the wildcard. However, the build 763 // list may already contain other modules with matching packages, and we 764 // should consider those modules to satisfy the query too. 765 // We want to match any packages in existing dependencies, but we only want to 766 // resolve new dependencies if nothing else turns up. 767 for _, curM := range r.buildList { 768 if !q.canMatchInModule(curM.Path) { 769 continue 770 } 771 q.pathOnce(curM.Path, func() pathSet { 772 if _, hit := r.noneForPath(curM.Path); hit { 773 // This module is being removed, so it will no longer be in the build list 774 // (and thus will no longer match the pattern). 775 return pathSet{} 776 } 777 778 if modload.MainModules.Contains(curM.Path) && !versionOkForMainModule(q.version) { 779 if q.matchesPath(curM.Path) { 780 return errSet(&modload.QueryMatchesMainModulesError{ 781 MainModules: []module.Version{curM}, 782 Pattern: q.pattern, 783 Query: q.version, 784 }) 785 } 786 787 packages, err := r.matchInModule(ctx, q.pattern, curM) 788 if err != nil { 789 return errSet(err) 790 } 791 if len(packages) > 0 { 792 return errSet(&modload.QueryMatchesPackagesInMainModuleError{ 793 Pattern: q.pattern, 794 Query: q.version, 795 Packages: packages, 796 }) 797 } 798 799 return r.tryWildcard(ctx, q, curM) 800 } 801 802 m, err := r.queryModule(ctx, curM.Path, q.version, r.initialSelected) 803 if err != nil { 804 if !isNoSuchModuleVersion(err) { 805 // We can't tell whether a matching version exists. 806 return errSet(err) 807 } 808 // There is no version of curM.Path matching the query. 809 810 // We haven't checked whether curM contains any matching packages at its 811 // currently-selected version, or whether curM.Path itself matches q. If 812 // either of those conditions holds, *and* no other query changes the 813 // selected version of curM, then we will fail in checkWildcardVersions. 814 // (This could be an error, but it's too soon to tell.) 815 // 816 // However, even then the transitive requirements of some other query 817 // may downgrade this module out of the build list entirely, in which 818 // case the pattern will no longer include it and it won't be an error. 819 // 820 // Either way, punt on the query rather than erroring out just yet. 821 return pathSet{} 822 } 823 824 return r.tryWildcard(ctx, q, m) 825 }) 826 } 827 828 // Even if no modules matched, we shouldn't query for a new module to provide 829 // the pattern yet: some other query may yet induce a new requirement that 830 // will match the wildcard. Instead, we'll check in findMissingWildcards. 831 } 832 833 // tryWildcard returns a pathSet for module m matching query q. 834 // If m does not actually match q, tryWildcard returns an empty pathSet. 835 func (r *resolver) tryWildcard(ctx context.Context, q *query, m module.Version) pathSet { 836 mMatches := q.matchesPath(m.Path) 837 packages, err := r.matchInModule(ctx, q.pattern, m) 838 if err != nil { 839 return errSet(err) 840 } 841 if len(packages) > 0 { 842 return pathSet{pkgMods: []module.Version{m}} 843 } 844 if mMatches { 845 return pathSet{mod: m} 846 } 847 return pathSet{} 848 } 849 850 // findMissingWildcards adds a candidate set for each query in r.wildcardQueries 851 // that has not yet resolved to any version containing packages. 852 func (r *resolver) findMissingWildcards(ctx context.Context) { 853 for _, q := range r.wildcardQueries { 854 if q.version == "none" || q.matchesPackages { 855 continue // q is not “missing” 856 } 857 r.work.Add(func() { 858 q.pathOnce(q.pattern, func() pathSet { 859 pkgMods, mod, err := r.queryPattern(ctx, q.pattern, q.version, r.initialSelected) 860 if err != nil { 861 if isNoSuchPackageVersion(err) && len(q.resolved) > 0 { 862 // q already resolved one or more modules but matches no packages. 863 // That's ok: this pattern is just a module pattern, and we don't 864 // need to add any more modules to satisfy it. 865 return pathSet{} 866 } 867 return errSet(err) 868 } 869 870 return pathSet{pkgMods: pkgMods, mod: mod} 871 }) 872 }) 873 } 874 <-r.work.Idle() 875 } 876 877 // checkWildcardVersions reports an error if any module in the build list has a 878 // path (or contains a package) matching a query with a wildcard pattern, but 879 // has a selected version that does *not* match the query. 880 func (r *resolver) checkWildcardVersions(ctx context.Context) { 881 defer base.ExitIfErrors() 882 883 for _, q := range r.wildcardQueries { 884 for _, curM := range r.buildList { 885 if !q.canMatchInModule(curM.Path) { 886 continue 887 } 888 if !q.matchesPath(curM.Path) { 889 packages, err := r.matchInModule(ctx, q.pattern, curM) 890 if len(packages) == 0 { 891 if err != nil { 892 reportError(q, err) 893 } 894 continue // curM is not relevant to q. 895 } 896 } 897 898 rev, err := r.queryModule(ctx, curM.Path, q.version, r.initialSelected) 899 if err != nil { 900 reportError(q, err) 901 continue 902 } 903 if rev.Version == curM.Version { 904 continue // curM already matches q. 905 } 906 907 if !q.matchesPath(curM.Path) { 908 m := module.Version{Path: curM.Path, Version: rev.Version} 909 packages, err := r.matchInModule(ctx, q.pattern, m) 910 if err != nil { 911 reportError(q, err) 912 continue 913 } 914 if len(packages) == 0 { 915 // curM at its original version contains a path matching q.pattern, 916 // but at rev.Version it does not, so (somewhat paradoxically) if 917 // we changed the version of curM it would no longer match the query. 918 var version any = m 919 if rev.Version != q.version { 920 version = fmt.Sprintf("%s@%s (%s)", m.Path, q.version, m.Version) 921 } 922 reportError(q, fmt.Errorf("%v matches packages in %v but not %v: specify a different version for module %s", q, curM, version, m.Path)) 923 continue 924 } 925 } 926 927 // Since queryModule succeeded and either curM or one of the packages it 928 // contains matches q.pattern, we should have either selected the version 929 // of curM matching q, or reported a conflict error (and exited). 930 // If we're still here and the version doesn't match, 931 // something has gone very wrong. 932 reportError(q, fmt.Errorf("internal error: selected %v instead of %v", curM, rev.Version)) 933 } 934 } 935 } 936 937 // performPathQueries populates the candidates for each query whose pattern is 938 // a path literal. 939 // 940 // The candidate packages and modules for path literals depend only on the 941 // initial build list, not the current build list, so we only need to query path 942 // literals once. 943 func (r *resolver) performPathQueries(ctx context.Context) { 944 for _, q := range r.pathQueries { 945 q := q 946 r.work.Add(func() { 947 if q.version == "none" { 948 r.queryNone(ctx, q) 949 } else { 950 r.queryPath(ctx, q) 951 } 952 }) 953 } 954 <-r.work.Idle() 955 } 956 957 // queryPath adds a candidate set to q for the package with path q.pattern. 958 // The candidate set consists of all modules that could provide q.pattern 959 // and have a version matching q, plus (if it exists) the module whose path 960 // is itself q.pattern (at a matching version). 961 func (r *resolver) queryPath(ctx context.Context, q *query) { 962 q.pathOnce(q.pattern, func() pathSet { 963 if search.IsMetaPackage(q.pattern) || q.isWildcard() { 964 panic(fmt.Sprintf("internal error: queryPath called with pattern %q", q.pattern)) 965 } 966 if q.version == "none" { 967 panic(`internal error: queryPath called with version "none"`) 968 } 969 970 if search.IsStandardImportPath(q.pattern) { 971 stdOnly := module.Version{} 972 packages, _ := r.matchInModule(ctx, q.pattern, stdOnly) 973 if len(packages) > 0 { 974 if q.rawVersion != "" { 975 return errSet(fmt.Errorf("can't request explicit version %q of standard library package %s", q.version, q.pattern)) 976 } 977 978 q.matchesPackages = true 979 return pathSet{} // No module needed for standard library. 980 } 981 } 982 983 pkgMods, mod, err := r.queryPattern(ctx, q.pattern, q.version, r.initialSelected) 984 if err != nil { 985 return errSet(err) 986 } 987 return pathSet{pkgMods: pkgMods, mod: mod} 988 }) 989 } 990 991 // performPatternAllQueries populates the candidates for each query whose 992 // pattern is "all". 993 // 994 // The candidate modules for a given package in "all" depend only on the initial 995 // build list, but we cannot follow the dependencies of a given package until we 996 // know which candidate is selected — and that selection may depend on the 997 // results of other queries. We need to re-evaluate the "all" queries whenever 998 // the module for one or more packages in "all" are resolved. 999 func (r *resolver) performPatternAllQueries(ctx context.Context) { 1000 if len(r.patternAllQueries) == 0 { 1001 return 1002 } 1003 1004 findPackage := func(ctx context.Context, path string, m module.Version) (versionOk bool) { 1005 versionOk = true 1006 for _, q := range r.patternAllQueries { 1007 q.pathOnce(path, func() pathSet { 1008 pkgMods, err := r.queryPackages(ctx, path, q.version, r.initialSelected) 1009 if len(pkgMods) != 1 || pkgMods[0] != m { 1010 // There are candidates other than m for the given path, so we can't 1011 // be certain that m will actually be the module selected to provide 1012 // the package. Don't load its dependencies just yet, because they 1013 // might no longer be dependencies after we resolve the correct 1014 // version. 1015 versionOk = false 1016 } 1017 return pathSet{pkgMods: pkgMods, err: err} 1018 }) 1019 } 1020 return versionOk 1021 } 1022 1023 r.loadPackages(ctx, []string{"all"}, findPackage) 1024 1025 // Since we built up the candidate lists concurrently, they may be in a 1026 // nondeterministic order. We want 'go get' to be fully deterministic, 1027 // including in which errors it chooses to report, so sort the candidates 1028 // into a deterministic-but-arbitrary order. 1029 for _, q := range r.patternAllQueries { 1030 sort.Slice(q.candidates, func(i, j int) bool { 1031 return q.candidates[i].path < q.candidates[j].path 1032 }) 1033 } 1034 } 1035 1036 // findAndUpgradeImports returns a pathSet for each package that is not yet 1037 // in the build list but is transitively imported by the packages matching the 1038 // given queries (which must already have been resolved). 1039 // 1040 // If the getU flag ("-u") is set, findAndUpgradeImports also returns a 1041 // pathSet for each module that is not constrained by any other 1042 // command-line argument and has an available matching upgrade. 1043 func (r *resolver) findAndUpgradeImports(ctx context.Context, queries []*query) (upgrades []pathSet) { 1044 patterns := make([]string, 0, len(queries)) 1045 for _, q := range queries { 1046 if q.matchesPackages { 1047 patterns = append(patterns, q.pattern) 1048 } 1049 } 1050 if len(patterns) == 0 { 1051 return nil 1052 } 1053 1054 // mu guards concurrent writes to upgrades, which will be sorted 1055 // (to restore determinism) after loading. 1056 var mu sync.Mutex 1057 1058 findPackage := func(ctx context.Context, path string, m module.Version) (versionOk bool) { 1059 version := "latest" 1060 if m.Path != "" { 1061 if getU.version == "" { 1062 // The user did not request that we upgrade transitive dependencies. 1063 return true 1064 } 1065 if _, ok := r.resolvedVersion[m.Path]; ok { 1066 // We cannot upgrade m implicitly because its version is determined by 1067 // an explicit pattern argument. 1068 return true 1069 } 1070 version = getU.version 1071 } 1072 1073 // Unlike other queries, the "-u" flag upgrades relative to the build list 1074 // after applying changes so far, not the initial build list. 1075 // This is for two reasons: 1076 // 1077 // - The "-u" flag intentionally applies to transitive dependencies, 1078 // which may not be known or even resolved in advance of applying 1079 // other version changes. 1080 // 1081 // - The "-u" flag, unlike other arguments, does not cause version 1082 // conflicts with other queries. (The other query always wins.) 1083 1084 pkgMods, err := r.queryPackages(ctx, path, version, r.selected) 1085 for _, u := range pkgMods { 1086 if u == m { 1087 // The selected package version is already upgraded appropriately; there 1088 // is no need to change it. 1089 return true 1090 } 1091 } 1092 1093 if err != nil { 1094 if isNoSuchPackageVersion(err) || (m.Path == "" && module.CheckPath(path) != nil) { 1095 // We can't find the package because it doesn't — or can't — even exist 1096 // in any module at the latest version. (Note that invalid module paths 1097 // could in general exist due to replacements, so we at least need to 1098 // run the query to check those.) 1099 // 1100 // There is no version change we can make to fix the package, so leave 1101 // it unresolved. Either some other query (perhaps a wildcard matching a 1102 // newly-added dependency for some other missing package) will fill in 1103 // the gaps, or we will report an error (with a better import stack) in 1104 // the final LoadPackages call. 1105 return true 1106 } 1107 } 1108 1109 mu.Lock() 1110 upgrades = append(upgrades, pathSet{path: path, pkgMods: pkgMods, err: err}) 1111 mu.Unlock() 1112 return false 1113 } 1114 1115 r.loadPackages(ctx, patterns, findPackage) 1116 1117 // Since we built up the candidate lists concurrently, they may be in a 1118 // nondeterministic order. We want 'go get' to be fully deterministic, 1119 // including in which errors it chooses to report, so sort the candidates 1120 // into a deterministic-but-arbitrary order. 1121 sort.Slice(upgrades, func(i, j int) bool { 1122 return upgrades[i].path < upgrades[j].path 1123 }) 1124 return upgrades 1125 } 1126 1127 // loadPackages loads the packages matching the given patterns, invoking the 1128 // findPackage function for each package that may require a change to the 1129 // build list. 1130 // 1131 // loadPackages invokes the findPackage function for each package loaded from a 1132 // module outside the main module. If the module or version that supplies that 1133 // package needs to be changed due to a query, findPackage may return false 1134 // and the imports of that package will not be loaded. 1135 // 1136 // loadPackages also invokes the findPackage function for each imported package 1137 // that is neither present in the standard library nor in any module in the 1138 // build list. 1139 func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPackage func(ctx context.Context, path string, m module.Version) (versionOk bool)) { 1140 opts := modload.PackageOpts{ 1141 Tags: imports.AnyTags(), 1142 VendorModulesInGOROOTSrc: true, 1143 LoadTests: *getT, 1144 AssumeRootsImported: true, // After 'go get foo', imports of foo should build. 1145 SilencePackageErrors: true, // May be fixed by subsequent upgrades or downgrades. 1146 Switcher: new(toolchain.Switcher), 1147 } 1148 1149 opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error { 1150 if m.Path == "" || m.Version == "" { 1151 // Packages in the standard library and main modules are already at their 1152 // latest (and only) available versions. 1153 return nil 1154 } 1155 if ok := findPackage(ctx, path, m); !ok { 1156 return errVersionChange 1157 } 1158 return nil 1159 } 1160 1161 _, pkgs := modload.LoadPackages(ctx, opts, patterns...) 1162 for _, path := range pkgs { 1163 const ( 1164 parentPath = "" 1165 parentIsStd = false 1166 ) 1167 _, _, err := modload.Lookup(parentPath, parentIsStd, path) 1168 if err == nil { 1169 continue 1170 } 1171 if errors.Is(err, errVersionChange) { 1172 // We already added candidates during loading. 1173 continue 1174 } 1175 1176 var ( 1177 importMissing *modload.ImportMissingError 1178 ambiguous *modload.AmbiguousImportError 1179 ) 1180 if !errors.As(err, &importMissing) && !errors.As(err, &ambiguous) { 1181 // The package, which is a dependency of something we care about, has some 1182 // problem that we can't resolve with a version change. 1183 // Leave the error for the final LoadPackages call. 1184 continue 1185 } 1186 1187 path := path 1188 r.work.Add(func() { 1189 findPackage(ctx, path, module.Version{}) 1190 }) 1191 } 1192 <-r.work.Idle() 1193 } 1194 1195 // errVersionChange is a sentinel error indicating that a module's version needs 1196 // to be updated before its dependencies can be loaded. 1197 var errVersionChange = errors.New("version change needed") 1198 1199 // resolveQueries resolves candidate sets that are attached to the given 1200 // queries and/or needed to provide the given missing-package dependencies. 1201 // 1202 // resolveQueries starts by resolving one module version from each 1203 // unambiguous pathSet attached to the given queries. 1204 // 1205 // If no unambiguous query results in a change to the build list, 1206 // resolveQueries revisits the ambiguous query candidates and resolves them 1207 // arbitrarily in order to guarantee forward progress. 1208 // 1209 // If all pathSets are resolved without any changes to the build list, 1210 // resolveQueries returns with changed=false. 1211 func (r *resolver) resolveQueries(ctx context.Context, queries []*query) (changed bool) { 1212 defer base.ExitIfErrors() 1213 1214 // Note: this is O(N²) with the number of pathSets in the worst case. 1215 // 1216 // We could perhaps get it down to O(N) if we were to index the pathSets 1217 // by module path, so that we only revisit a given pathSet when the 1218 // version of some module in its containingPackage list has been determined. 1219 // 1220 // However, N tends to be small, and most candidate sets will include only one 1221 // candidate module (so they will be resolved in the first iteration), so for 1222 // now we'll stick to the simple O(N²) approach. 1223 1224 resolved := 0 1225 for { 1226 prevResolved := resolved 1227 1228 // If we found modules that were too new, find the max of the required versions 1229 // and then try to switch to a newer toolchain. 1230 var sw toolchain.Switcher 1231 for _, q := range queries { 1232 for _, cs := range q.candidates { 1233 sw.Error(cs.err) 1234 } 1235 } 1236 // Only switch if we need a newer toolchain. 1237 // Otherwise leave the cs.err for reporting later. 1238 if sw.NeedSwitch() { 1239 sw.Switch(ctx) 1240 // If NeedSwitch is true and Switch returns, Switch has failed to locate a newer toolchain. 1241 // It printed the errors along with one more about not finding a good toolchain. 1242 base.Exit() 1243 } 1244 1245 for _, q := range queries { 1246 unresolved := q.candidates[:0] 1247 1248 for _, cs := range q.candidates { 1249 if cs.err != nil { 1250 reportError(q, cs.err) 1251 resolved++ 1252 continue 1253 } 1254 1255 filtered, isPackage, m, unique := r.disambiguate(cs) 1256 if !unique { 1257 unresolved = append(unresolved, filtered) 1258 continue 1259 } 1260 1261 if m.Path == "" { 1262 // The query is not viable. Choose an arbitrary candidate from 1263 // before filtering and “resolve” it to report a conflict. 1264 isPackage, m = r.chooseArbitrarily(cs) 1265 } 1266 if isPackage { 1267 q.matchesPackages = true 1268 } 1269 r.resolve(q, m) 1270 resolved++ 1271 } 1272 1273 q.candidates = unresolved 1274 } 1275 1276 base.ExitIfErrors() 1277 if resolved == prevResolved { 1278 break // No unambiguous candidate remains. 1279 } 1280 } 1281 1282 if resolved > 0 { 1283 if changed = r.updateBuildList(ctx, nil); changed { 1284 // The build list has changed, so disregard any remaining ambiguous queries: 1285 // they might now be determined by requirements in the build list, which we 1286 // would prefer to use instead of arbitrary versions. 1287 return true 1288 } 1289 } 1290 1291 // The build list will be the same on the next iteration as it was on this 1292 // iteration, so any ambiguous queries will remain so. In order to make 1293 // progress, resolve them arbitrarily but deterministically. 1294 // 1295 // If that results in conflicting versions, the user can re-run 'go get' 1296 // with additional explicit versions for the conflicting packages or 1297 // modules. 1298 resolvedArbitrarily := 0 1299 for _, q := range queries { 1300 for _, cs := range q.candidates { 1301 isPackage, m := r.chooseArbitrarily(cs) 1302 if isPackage { 1303 q.matchesPackages = true 1304 } 1305 r.resolve(q, m) 1306 resolvedArbitrarily++ 1307 } 1308 } 1309 if resolvedArbitrarily > 0 { 1310 changed = r.updateBuildList(ctx, nil) 1311 } 1312 return changed 1313 } 1314 1315 // applyUpgrades disambiguates candidate sets that are needed to upgrade (or 1316 // provide) transitive dependencies imported by previously-resolved packages. 1317 // 1318 // applyUpgrades modifies the build list by adding one module version from each 1319 // pathSet in upgrades, then downgrading (or further upgrading) those modules as 1320 // needed to maintain any already-resolved versions of other modules. 1321 // applyUpgrades does not mark the new versions as resolved, so they can still 1322 // be further modified by other queries (such as wildcards). 1323 // 1324 // If all pathSets are resolved without any changes to the build list, 1325 // applyUpgrades returns with changed=false. 1326 func (r *resolver) applyUpgrades(ctx context.Context, upgrades []pathSet) (changed bool) { 1327 defer base.ExitIfErrors() 1328 1329 // Arbitrarily add a "latest" version that provides each missing package, but 1330 // do not mark the version as resolved: we still want to allow the explicit 1331 // queries to modify the resulting versions. 1332 var tentative []module.Version 1333 for _, cs := range upgrades { 1334 if cs.err != nil { 1335 base.Error(cs.err) 1336 continue 1337 } 1338 1339 filtered, _, m, unique := r.disambiguate(cs) 1340 if !unique { 1341 _, m = r.chooseArbitrarily(filtered) 1342 } 1343 if m.Path == "" { 1344 // There is no viable candidate for the missing package. 1345 // Leave it unresolved. 1346 continue 1347 } 1348 tentative = append(tentative, m) 1349 } 1350 base.ExitIfErrors() 1351 1352 changed = r.updateBuildList(ctx, tentative) 1353 return changed 1354 } 1355 1356 // disambiguate eliminates candidates from cs that conflict with other module 1357 // versions that have already been resolved. If there is only one (unique) 1358 // remaining candidate, disambiguate returns that candidate, along with 1359 // an indication of whether that result interprets cs.path as a package 1360 // 1361 // Note: we're only doing very simple disambiguation here. The goal is to 1362 // reproduce the user's intent, not to find a solution that a human couldn't. 1363 // In the vast majority of cases, we expect only one module per pathSet, 1364 // but we want to give some minimal additional tools so that users can add an 1365 // extra argument or two on the command line to resolve simple ambiguities. 1366 func (r *resolver) disambiguate(cs pathSet) (filtered pathSet, isPackage bool, m module.Version, unique bool) { 1367 if len(cs.pkgMods) == 0 && cs.mod.Path == "" { 1368 panic("internal error: resolveIfUnambiguous called with empty pathSet") 1369 } 1370 1371 for _, m := range cs.pkgMods { 1372 if _, ok := r.noneForPath(m.Path); ok { 1373 // A query with version "none" forces the candidate module to version 1374 // "none", so we cannot use any other version for that module. 1375 continue 1376 } 1377 1378 if modload.MainModules.Contains(m.Path) { 1379 if m.Version == "" { 1380 return pathSet{}, true, m, true 1381 } 1382 // A main module can only be set to its own version. 1383 continue 1384 } 1385 1386 vr, ok := r.resolvedVersion[m.Path] 1387 if !ok { 1388 // m is a viable answer to the query, but other answers may also 1389 // still be viable. 1390 filtered.pkgMods = append(filtered.pkgMods, m) 1391 continue 1392 } 1393 1394 if vr.version != m.Version { 1395 // Some query forces the candidate module to a version other than this 1396 // one. 1397 // 1398 // The command could be something like 1399 // 1400 // go get example.com/foo/bar@none example.com/foo/bar/baz@latest 1401 // 1402 // in which case we *cannot* resolve the package from 1403 // example.com/foo/bar (because it is constrained to version 1404 // "none") and must fall through to module example.com/foo@latest. 1405 continue 1406 } 1407 1408 // Some query forces the candidate module *to* the candidate version. 1409 // As a result, this candidate is the only viable choice to provide 1410 // its package(s): any other choice would result in an ambiguous import 1411 // for this path. 1412 // 1413 // For example, consider the command 1414 // 1415 // go get example.com/foo@latest example.com/foo/bar/baz@latest 1416 // 1417 // If modules example.com/foo and example.com/foo/bar both provide 1418 // package example.com/foo/bar/baz, then we *must* resolve the package 1419 // from example.com/foo: if we instead resolved it from 1420 // example.com/foo/bar, we would have two copies of the package. 1421 return pathSet{}, true, m, true 1422 } 1423 1424 if cs.mod.Path != "" { 1425 vr, ok := r.resolvedVersion[cs.mod.Path] 1426 if !ok || vr.version == cs.mod.Version { 1427 filtered.mod = cs.mod 1428 } 1429 } 1430 1431 if len(filtered.pkgMods) == 1 && 1432 (filtered.mod.Path == "" || filtered.mod == filtered.pkgMods[0]) { 1433 // Exactly one viable module contains the package with the given path 1434 // (by far the common case), so we can resolve it unambiguously. 1435 return pathSet{}, true, filtered.pkgMods[0], true 1436 } 1437 1438 if len(filtered.pkgMods) == 0 { 1439 // All modules that could provide the path as a package conflict with other 1440 // resolved arguments. If it can refer to a module instead, return that; 1441 // otherwise, this pathSet cannot be resolved (and we will return the 1442 // zero module.Version). 1443 return pathSet{}, false, filtered.mod, true 1444 } 1445 1446 // The query remains ambiguous: there are at least two different modules 1447 // to which cs.path could refer. 1448 return filtered, false, module.Version{}, false 1449 } 1450 1451 // chooseArbitrarily returns an arbitrary (but deterministic) module version 1452 // from among those in the given set. 1453 // 1454 // chooseArbitrarily prefers module paths that were already in the build list at 1455 // the start of 'go get', prefers modules that provide packages over those that 1456 // do not, and chooses the first module meeting those criteria (so biases toward 1457 // longer paths). 1458 func (r *resolver) chooseArbitrarily(cs pathSet) (isPackage bool, m module.Version) { 1459 // Prefer to upgrade some module that was already in the build list. 1460 for _, m := range cs.pkgMods { 1461 if r.initialSelected(m.Path) != "none" { 1462 return true, m 1463 } 1464 } 1465 1466 // Otherwise, arbitrarily choose the first module that provides the package. 1467 if len(cs.pkgMods) > 0 { 1468 return true, cs.pkgMods[0] 1469 } 1470 1471 return false, cs.mod 1472 } 1473 1474 // checkPackageProblems reloads packages for the given patterns and reports 1475 // missing and ambiguous package errors. It also reports retractions and 1476 // deprecations for resolved modules and modules needed to build named packages. 1477 // It also adds a sum for each updated module in the build list if we had one 1478 // before and didn't get one while loading packages. 1479 // 1480 // We skip missing-package errors earlier in the process, since we want to 1481 // resolve pathSets ourselves, but at that point, we don't have enough context 1482 // to log the package-import chains leading to each error. 1483 func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []string) { 1484 defer base.ExitIfErrors() 1485 1486 // Gather information about modules we might want to load retractions and 1487 // deprecations for. Loading this metadata requires at least one version 1488 // lookup per module, and we don't want to load information that's neither 1489 // relevant nor actionable. 1490 type modFlags int 1491 const ( 1492 resolved modFlags = 1 << iota // version resolved by 'go get' 1493 named // explicitly named on command line or provides a named package 1494 hasPkg // needed to build named packages 1495 direct // provides a direct dependency of the main module 1496 ) 1497 relevantMods := make(map[module.Version]modFlags) 1498 for path, reason := range r.resolvedVersion { 1499 m := module.Version{Path: path, Version: reason.version} 1500 relevantMods[m] |= resolved 1501 } 1502 1503 // Reload packages, reporting errors for missing and ambiguous imports. 1504 if len(pkgPatterns) > 0 { 1505 // LoadPackages will print errors (since it has more context) but will not 1506 // exit, since we need to load retractions later. 1507 pkgOpts := modload.PackageOpts{ 1508 VendorModulesInGOROOTSrc: true, 1509 LoadTests: *getT, 1510 ResolveMissingImports: false, 1511 AllowErrors: true, 1512 SilenceNoGoErrors: true, 1513 } 1514 matches, pkgs := modload.LoadPackages(ctx, pkgOpts, pkgPatterns...) 1515 for _, m := range matches { 1516 if len(m.Errs) > 0 { 1517 base.SetExitStatus(1) 1518 break 1519 } 1520 } 1521 for _, pkg := range pkgs { 1522 if dir, _, err := modload.Lookup("", false, pkg); err != nil { 1523 if dir != "" && errors.Is(err, imports.ErrNoGo) { 1524 // Since dir is non-empty, we must have located source files 1525 // associated with either the package or its test — ErrNoGo must 1526 // indicate that none of those source files happen to apply in this 1527 // configuration. If we are actually building the package (no -d 1528 // flag), we will report the problem then; otherwise, assume that the 1529 // user is going to build or test this package in some other 1530 // configuration and suppress the error. 1531 continue 1532 } 1533 1534 base.SetExitStatus(1) 1535 if ambiguousErr := (*modload.AmbiguousImportError)(nil); errors.As(err, &ambiguousErr) { 1536 for _, m := range ambiguousErr.Modules { 1537 relevantMods[m] |= hasPkg 1538 } 1539 } 1540 } 1541 if m := modload.PackageModule(pkg); m.Path != "" { 1542 relevantMods[m] |= hasPkg 1543 } 1544 } 1545 for _, match := range matches { 1546 for _, pkg := range match.Pkgs { 1547 m := modload.PackageModule(pkg) 1548 relevantMods[m] |= named 1549 } 1550 } 1551 } 1552 1553 reqs := modload.LoadModFile(ctx) 1554 for m := range relevantMods { 1555 if reqs.IsDirect(m.Path) { 1556 relevantMods[m] |= direct 1557 } 1558 } 1559 1560 // Load retractions for modules mentioned on the command line and modules 1561 // needed to build named packages. We care about retractions of indirect 1562 // dependencies, since we might be able to upgrade away from them. 1563 type modMessage struct { 1564 m module.Version 1565 message string 1566 } 1567 retractions := make([]modMessage, 0, len(relevantMods)) 1568 for m, flags := range relevantMods { 1569 if flags&(resolved|named|hasPkg) != 0 { 1570 retractions = append(retractions, modMessage{m: m}) 1571 } 1572 } 1573 sort.Slice(retractions, func(i, j int) bool { return retractions[i].m.Path < retractions[j].m.Path }) 1574 for i := range retractions { 1575 i := i 1576 r.work.Add(func() { 1577 err := modload.CheckRetractions(ctx, retractions[i].m) 1578 if retractErr := (*modload.ModuleRetractedError)(nil); errors.As(err, &retractErr) { 1579 retractions[i].message = err.Error() 1580 } 1581 }) 1582 } 1583 1584 // Load deprecations for modules mentioned on the command line. Only load 1585 // deprecations for indirect dependencies if they're also direct dependencies 1586 // of the main module. Deprecations of purely indirect dependencies are 1587 // not actionable. 1588 deprecations := make([]modMessage, 0, len(relevantMods)) 1589 for m, flags := range relevantMods { 1590 if flags&(resolved|named) != 0 || flags&(hasPkg|direct) == hasPkg|direct { 1591 deprecations = append(deprecations, modMessage{m: m}) 1592 } 1593 } 1594 sort.Slice(deprecations, func(i, j int) bool { return deprecations[i].m.Path < deprecations[j].m.Path }) 1595 for i := range deprecations { 1596 i := i 1597 r.work.Add(func() { 1598 deprecation, err := modload.CheckDeprecation(ctx, deprecations[i].m) 1599 if err != nil || deprecation == "" { 1600 return 1601 } 1602 deprecations[i].message = modload.ShortMessage(deprecation, "") 1603 }) 1604 } 1605 1606 // Load sums for updated modules that had sums before. When we update a 1607 // module, we may update another module in the build list that provides a 1608 // package in 'all' that wasn't loaded as part of this 'go get' command. 1609 // If we don't add a sum for that module, builds may fail later. 1610 // Note that an incidentally updated package could still import packages 1611 // from unknown modules or from modules in the build list that we didn't 1612 // need previously. We can't handle that case without loading 'all'. 1613 sumErrs := make([]error, len(r.buildList)) 1614 for i := range r.buildList { 1615 i := i 1616 m := r.buildList[i] 1617 mActual := m 1618 if mRepl := modload.Replacement(m); mRepl.Path != "" { 1619 mActual = mRepl 1620 } 1621 old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]} 1622 if old.Version == "" { 1623 continue 1624 } 1625 oldActual := old 1626 if oldRepl := modload.Replacement(old); oldRepl.Path != "" { 1627 oldActual = oldRepl 1628 } 1629 if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) { 1630 continue 1631 } 1632 r.work.Add(func() { 1633 if _, err := modfetch.DownloadZip(ctx, mActual); err != nil { 1634 verb := "upgraded" 1635 if gover.ModCompare(m.Path, m.Version, old.Version) < 0 { 1636 verb = "downgraded" 1637 } 1638 replaced := "" 1639 if mActual != m { 1640 replaced = fmt.Sprintf(" (replaced by %s)", mActual) 1641 } 1642 err = fmt.Errorf("%s %s %s => %s%s: error finding sum for %s: %v", verb, m.Path, old.Version, m.Version, replaced, mActual, err) 1643 sumErrs[i] = err 1644 } 1645 }) 1646 } 1647 1648 <-r.work.Idle() 1649 1650 // Report deprecations, then retractions, then errors fetching sums. 1651 // Only errors fetching sums are hard errors. 1652 for _, mm := range deprecations { 1653 if mm.message != "" { 1654 fmt.Fprintf(os.Stderr, "go: module %s is deprecated: %s\n", mm.m.Path, mm.message) 1655 } 1656 } 1657 var retractPath string 1658 for _, mm := range retractions { 1659 if mm.message != "" { 1660 fmt.Fprintf(os.Stderr, "go: warning: %v\n", mm.message) 1661 if retractPath == "" { 1662 retractPath = mm.m.Path 1663 } else { 1664 retractPath = "<module>" 1665 } 1666 } 1667 } 1668 if retractPath != "" { 1669 fmt.Fprintf(os.Stderr, "go: to switch to the latest unretracted version, run:\n\tgo get %s@latest\n", retractPath) 1670 } 1671 for _, err := range sumErrs { 1672 if err != nil { 1673 base.Error(err) 1674 } 1675 } 1676 base.ExitIfErrors() 1677 } 1678 1679 // reportChanges logs version changes to os.Stderr. 1680 // 1681 // reportChanges only logs changes to modules named on the command line and to 1682 // explicitly required modules in go.mod. Most changes to indirect requirements 1683 // are not relevant to the user and are not logged. 1684 // 1685 // reportChanges should be called after WriteGoMod. 1686 func (r *resolver) reportChanges(oldReqs, newReqs []module.Version) { 1687 type change struct { 1688 path, old, new string 1689 } 1690 changes := make(map[string]change) 1691 1692 // Collect changes in modules matched by command line arguments. 1693 for path, reason := range r.resolvedVersion { 1694 if gover.IsToolchain(path) { 1695 continue 1696 } 1697 old := r.initialVersion[path] 1698 new := reason.version 1699 if old != new && (old != "" || new != "none") { 1700 changes[path] = change{path, old, new} 1701 } 1702 } 1703 1704 // Collect changes to explicit requirements in go.mod. 1705 for _, req := range oldReqs { 1706 if gover.IsToolchain(req.Path) { 1707 continue 1708 } 1709 path := req.Path 1710 old := req.Version 1711 new := r.buildListVersion[path] 1712 if old != new { 1713 changes[path] = change{path, old, new} 1714 } 1715 } 1716 for _, req := range newReqs { 1717 if gover.IsToolchain(req.Path) { 1718 continue 1719 } 1720 path := req.Path 1721 old := r.initialVersion[path] 1722 new := req.Version 1723 if old != new { 1724 changes[path] = change{path, old, new} 1725 } 1726 } 1727 1728 // Toolchain diffs are easier than requirements: diff old and new directly. 1729 toolchainVersions := func(reqs []module.Version) (goV, toolchain string) { 1730 for _, req := range reqs { 1731 if req.Path == "go" { 1732 goV = req.Version 1733 } 1734 if req.Path == "toolchain" { 1735 toolchain = req.Version 1736 } 1737 } 1738 return 1739 } 1740 oldGo, oldToolchain := toolchainVersions(oldReqs) 1741 newGo, newToolchain := toolchainVersions(newReqs) 1742 if oldGo != newGo { 1743 changes["go"] = change{"go", oldGo, newGo} 1744 } 1745 if oldToolchain != newToolchain { 1746 changes["toolchain"] = change{"toolchain", oldToolchain, newToolchain} 1747 } 1748 1749 sortedChanges := make([]change, 0, len(changes)) 1750 for _, c := range changes { 1751 sortedChanges = append(sortedChanges, c) 1752 } 1753 sort.Slice(sortedChanges, func(i, j int) bool { 1754 pi := sortedChanges[i].path 1755 pj := sortedChanges[j].path 1756 if pi == pj { 1757 return false 1758 } 1759 // go first; toolchain second 1760 switch { 1761 case pi == "go": 1762 return true 1763 case pj == "go": 1764 return false 1765 case pi == "toolchain": 1766 return true 1767 case pj == "toolchain": 1768 return false 1769 } 1770 return pi < pj 1771 }) 1772 1773 for _, c := range sortedChanges { 1774 if c.old == "" { 1775 fmt.Fprintf(os.Stderr, "go: added %s %s\n", c.path, c.new) 1776 } else if c.new == "none" || c.new == "" { 1777 fmt.Fprintf(os.Stderr, "go: removed %s %s\n", c.path, c.old) 1778 } else if gover.ModCompare(c.path, c.new, c.old) > 0 { 1779 fmt.Fprintf(os.Stderr, "go: upgraded %s %s => %s\n", c.path, c.old, c.new) 1780 if c.path == "go" && gover.Compare(c.old, gover.ExplicitIndirectVersion) < 0 && gover.Compare(c.new, gover.ExplicitIndirectVersion) >= 0 { 1781 fmt.Fprintf(os.Stderr, "\tnote: expanded dependencies to upgrade to go %s or higher; run 'go mod tidy' to clean up\n", gover.ExplicitIndirectVersion) 1782 } 1783 1784 } else { 1785 fmt.Fprintf(os.Stderr, "go: downgraded %s %s => %s\n", c.path, c.old, c.new) 1786 } 1787 } 1788 1789 // TODO(golang.org/issue/33284): attribute changes to command line arguments. 1790 // For modules matched by command line arguments, this probably isn't 1791 // necessary, but it would be useful for unmatched direct dependencies of 1792 // the main module. 1793 } 1794 1795 // resolve records that module m must be at its indicated version (which may be 1796 // "none") due to query q. If some other query forces module m to be at a 1797 // different version, resolve reports a conflict error. 1798 func (r *resolver) resolve(q *query, m module.Version) { 1799 if m.Path == "" { 1800 panic("internal error: resolving a module.Version with an empty path") 1801 } 1802 1803 if modload.MainModules.Contains(m.Path) && m.Version != "" { 1804 reportError(q, &modload.QueryMatchesMainModulesError{ 1805 MainModules: []module.Version{{Path: m.Path}}, 1806 Pattern: q.pattern, 1807 Query: q.version, 1808 }) 1809 return 1810 } 1811 1812 vr, ok := r.resolvedVersion[m.Path] 1813 if ok && vr.version != m.Version { 1814 reportConflict(q, m, vr) 1815 return 1816 } 1817 r.resolvedVersion[m.Path] = versionReason{m.Version, q} 1818 q.resolved = append(q.resolved, m) 1819 } 1820 1821 // updateBuildList updates the module loader's global build list to be 1822 // consistent with r.resolvedVersion, and to include additional modules 1823 // provided that they do not conflict with the resolved versions. 1824 // 1825 // If the additional modules conflict with the resolved versions, they will be 1826 // downgraded to a non-conflicting version (possibly "none"). 1827 // 1828 // If the resulting build list is the same as the one resulting from the last 1829 // call to updateBuildList, updateBuildList returns with changed=false. 1830 func (r *resolver) updateBuildList(ctx context.Context, additions []module.Version) (changed bool) { 1831 defer base.ExitIfErrors() 1832 1833 resolved := make([]module.Version, 0, len(r.resolvedVersion)) 1834 for mPath, rv := range r.resolvedVersion { 1835 if !modload.MainModules.Contains(mPath) { 1836 resolved = append(resolved, module.Version{Path: mPath, Version: rv.version}) 1837 } 1838 } 1839 1840 changed, err := modload.EditBuildList(ctx, additions, resolved) 1841 if err != nil { 1842 if errors.Is(err, gover.ErrTooNew) { 1843 toolchain.SwitchOrFatal(ctx, err) 1844 } 1845 1846 var constraint *modload.ConstraintError 1847 if !errors.As(err, &constraint) { 1848 base.Fatal(err) 1849 } 1850 1851 if cfg.BuildV { 1852 // Log complete paths for the conflicts before we summarize them. 1853 for _, c := range constraint.Conflicts { 1854 fmt.Fprintf(os.Stderr, "go: %v\n", c.String()) 1855 } 1856 } 1857 1858 // modload.EditBuildList reports constraint errors at 1859 // the module level, but 'go get' operates on packages. 1860 // Rewrite the errors to explain them in terms of packages. 1861 reason := func(m module.Version) string { 1862 rv, ok := r.resolvedVersion[m.Path] 1863 if !ok { 1864 return fmt.Sprintf("(INTERNAL ERROR: no reason found for %v)", m) 1865 } 1866 return rv.reason.ResolvedString(module.Version{Path: m.Path, Version: rv.version}) 1867 } 1868 for _, c := range constraint.Conflicts { 1869 adverb := "" 1870 if len(c.Path) > 2 { 1871 adverb = "indirectly " 1872 } 1873 firstReason := reason(c.Path[0]) 1874 last := c.Path[len(c.Path)-1] 1875 if c.Err != nil { 1876 base.Errorf("go: %v %srequires %v: %v", firstReason, adverb, last, c.UnwrapModuleError()) 1877 } else { 1878 base.Errorf("go: %v %srequires %v, not %v", firstReason, adverb, last, reason(c.Constraint)) 1879 } 1880 } 1881 return false 1882 } 1883 if !changed { 1884 return false 1885 } 1886 1887 mg, err := modload.LoadModGraph(ctx, "") 1888 if err != nil { 1889 toolchain.SwitchOrFatal(ctx, err) 1890 } 1891 1892 r.buildList = mg.BuildList() 1893 r.buildListVersion = make(map[string]string, len(r.buildList)) 1894 for _, m := range r.buildList { 1895 r.buildListVersion[m.Path] = m.Version 1896 } 1897 return true 1898 } 1899 1900 func reqsFromGoMod(f *modfile.File) []module.Version { 1901 reqs := make([]module.Version, len(f.Require), 2+len(f.Require)) 1902 for i, r := range f.Require { 1903 reqs[i] = r.Mod 1904 } 1905 if f.Go != nil { 1906 reqs = append(reqs, module.Version{Path: "go", Version: f.Go.Version}) 1907 } 1908 if f.Toolchain != nil { 1909 reqs = append(reqs, module.Version{Path: "toolchain", Version: f.Toolchain.Name}) 1910 } 1911 return reqs 1912 } 1913 1914 // isNoSuchModuleVersion reports whether err indicates that the requested module 1915 // does not exist at the requested version, either because the module does not 1916 // exist at all or because it does not include that specific version. 1917 func isNoSuchModuleVersion(err error) bool { 1918 var noMatch *modload.NoMatchingVersionError 1919 return errors.Is(err, os.ErrNotExist) || errors.As(err, &noMatch) 1920 } 1921 1922 // isNoSuchPackageVersion reports whether err indicates that the requested 1923 // package does not exist at the requested version, either because no module 1924 // that could contain it exists at that version, or because every such module 1925 // that does exist does not actually contain the package. 1926 func isNoSuchPackageVersion(err error) bool { 1927 var noPackage *modload.PackageNotInModuleError 1928 return isNoSuchModuleVersion(err) || errors.As(err, &noPackage) 1929 }