github.com/bir3/gocompiler@v0.3.205/src/cmd/gocmd/internal/get/get.go (about) 1 // Copyright 2011 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 get implements the “go get” command. 6 package get 7 8 import ( 9 "context" 10 "fmt" 11 "os" 12 "path/filepath" 13 "runtime" 14 "strings" 15 16 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/base" 17 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/cfg" 18 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/load" 19 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/search" 20 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/str" 21 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/vcs" 22 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/web" 23 "github.com/bir3/gocompiler/src/cmd/gocmd/internal/work" 24 25 "github.com/bir3/gocompiler/src/xvendor/golang.org/x/mod/module" 26 ) 27 28 var CmdGet = &base.Command{ 29 UsageLine: "go get [-d] [-f] [-t] [-u] [-v] [-fix] [build flags] [packages]", 30 Short: "download and install packages and dependencies", 31 Long: ` 32 Get downloads the packages named by the import paths, along with their 33 dependencies. It then installs the named packages, like 'go install'. 34 35 The -d flag instructs get to stop after downloading the packages; that is, 36 it instructs get not to install the packages. 37 38 The -f flag, valid only when -u is set, forces get -u not to verify that 39 each package has been checked out from the source control repository 40 implied by its import path. This can be useful if the source is a local fork 41 of the original. 42 43 The -fix flag instructs get to run the fix tool on the downloaded packages 44 before resolving dependencies or building the code. 45 46 The -t flag instructs get to also download the packages required to build 47 the tests for the specified packages. 48 49 The -u flag instructs get to use the network to update the named packages 50 and their dependencies. By default, get uses the network to check out 51 missing packages but does not use it to look for updates to existing packages. 52 53 The -v flag enables verbose progress and debug output. 54 55 Get also accepts build flags to control the installation. See 'go help build'. 56 57 When checking out a new package, get creates the target directory 58 GOPATH/src/<import-path>. If the GOPATH contains multiple entries, 59 get uses the first one. For more details see: 'go help gopath'. 60 61 When checking out or updating a package, get looks for a branch or tag 62 that matches the locally installed version of Go. The most important 63 rule is that if the local installation is running version "go1", get 64 searches for a branch or tag named "go1". If no such version exists 65 it retrieves the default branch of the package. 66 67 When go get checks out or updates a Git repository, 68 it also updates any git submodules referenced by the repository. 69 70 Get never checks out or updates code stored in vendor directories. 71 72 For more about specifying packages, see 'go help packages'. 73 74 For more about how 'go get' finds source code to 75 download, see 'go help importpath'. 76 77 This text describes the behavior of get when using GOPATH 78 to manage source code and dependencies. 79 If instead the go command is running in module-aware mode, 80 the details of get's flags and effects change, as does 'go help get'. 81 See 'go help modules' and 'go help module-get'. 82 83 See also: go build, go install, go clean. 84 `, 85 } 86 87 var HelpGopathGet = &base.Command{ 88 UsageLine: "gopath-get", 89 Short: "legacy GOPATH go get", 90 Long: ` 91 The 'go get' command changes behavior depending on whether the 92 go command is running in module-aware mode or legacy GOPATH mode. 93 This help text, accessible as 'go help gopath-get' even in module-aware mode, 94 describes 'go get' as it operates in legacy GOPATH mode. 95 96 Usage: ` + CmdGet.UsageLine + ` 97 ` + CmdGet.Long, 98 } 99 100 var ( 101 getD = CmdGet.Flag.Bool("d", false, "") 102 getF = CmdGet.Flag.Bool("f", false, "") 103 getT = CmdGet.Flag.Bool("t", false, "") 104 getU = CmdGet.Flag.Bool("u", false, "") 105 getFix = CmdGet.Flag.Bool("fix", false, "") 106 getInsecure = CmdGet.Flag.Bool("insecure", false, "") 107 ) 108 109 func init() { 110 work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags) 111 CmdGet.Run = runGet // break init loop 112 } 113 114 func runGet(ctx context.Context, cmd *base.Command, args []string) { 115 if cfg.ModulesEnabled { 116 // Should not happen: main.go should install the separate module-enabled get code. 117 base.Fatalf("go: modules not implemented") 118 } 119 120 work.BuildInit() 121 122 if *getF && !*getU { 123 base.Fatalf("go: cannot use -f flag without -u") 124 } 125 if *getInsecure { 126 base.Fatalf("go: -insecure flag is no longer supported; use GOINSECURE instead") 127 } 128 129 // Disable any prompting for passwords by Git itself. 130 // Only has an effect for 2.3.0 or later, but avoiding 131 // the prompt in earlier versions is just too hard. 132 // If user has explicitly set GIT_TERMINAL_PROMPT=1, keep 133 // prompting. 134 // See golang.org/issue/9341 and golang.org/issue/12706. 135 if os.Getenv("GIT_TERMINAL_PROMPT") == "" { 136 os.Setenv("GIT_TERMINAL_PROMPT", "0") 137 } 138 139 // Also disable prompting for passwords by the 'ssh' subprocess spawned by 140 // Git, because apparently GIT_TERMINAL_PROMPT isn't sufficient to do that. 141 // Adding '-o BatchMode=yes' should do the trick. 142 // 143 // If a Git subprocess forks a child into the background to cache a new connection, 144 // that child keeps stdout/stderr open. After the Git subprocess exits, 145 // os /exec expects to be able to read from the stdout/stderr pipe 146 // until EOF to get all the data that the Git subprocess wrote before exiting. 147 // The EOF doesn't come until the child exits too, because the child 148 // is holding the write end of the pipe. 149 // This is unfortunate, but it has come up at least twice 150 // (see golang.org/issue/13453 and golang.org/issue/16104) 151 // and confuses users when it does. 152 // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND, 153 // assume they know what they are doing and don't step on it. 154 // But default to turning off ControlMaster. 155 if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" { 156 os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no -o BatchMode=yes") 157 } 158 159 // And one more source of Git prompts: the Git Credential Manager Core for Windows. 160 // 161 // See https://github.com/microsoft/Git-Credential-Manager-Core/blob/master/docs/environment.md#gcm_interactive. 162 if os.Getenv("GCM_INTERACTIVE") == "" { 163 os.Setenv("GCM_INTERACTIVE", "never") 164 } 165 166 // Phase 1. Download/update. 167 var stk load.ImportStack 168 mode := 0 169 if *getT { 170 mode |= load.GetTestDeps 171 } 172 for _, pkg := range downloadPaths(args) { 173 download(ctx, pkg, nil, &stk, mode) 174 } 175 base.ExitIfErrors() 176 177 // Phase 2. Rescan packages and re-evaluate args list. 178 179 // Code we downloaded and all code that depends on it 180 // needs to be evicted from the package cache so that 181 // the information will be recomputed. Instead of keeping 182 // track of the reverse dependency information, evict 183 // everything. 184 load.ClearPackageCache() 185 186 pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{}, args) 187 load.CheckPackageErrors(pkgs) 188 189 // Phase 3. Install. 190 if *getD { 191 // Download only. 192 // Check delayed until now so that downloadPaths 193 // and CheckPackageErrors have a chance to print errors. 194 return 195 } 196 197 work.InstallPackages(ctx, args, pkgs) 198 } 199 200 // downloadPaths prepares the list of paths to pass to download. 201 // It expands ... patterns that can be expanded. If there is no match 202 // for a particular pattern, downloadPaths leaves it in the result list, 203 // in the hope that we can figure out the repository from the 204 // initial ...-free prefix. 205 func downloadPaths(patterns []string) []string { 206 for _, arg := range patterns { 207 if strings.Contains(arg, "@") { 208 base.Fatalf("go: can only use path@version syntax with 'go get' and 'go install' in module-aware mode") 209 } 210 211 // Guard against 'go get x.go', a common mistake. 212 // Note that package and module paths may end with '.go', so only print an error 213 // if the argument has no slash or refers to an existing file. 214 if strings.HasSuffix(arg, ".go") { 215 if !strings.Contains(arg, "/") { 216 base.Errorf("go: %s: arguments must be package or module paths", arg) 217 continue 218 } 219 if fi, err := os.Stat(arg); err == nil && !fi.IsDir() { 220 base.Errorf("go: %s exists as a file, but 'go get' requires package arguments", arg) 221 } 222 } 223 } 224 base.ExitIfErrors() 225 226 var pkgs []string 227 noModRoots := []string{} 228 for _, m := range search.ImportPathsQuiet(patterns, noModRoots) { 229 if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") { 230 pkgs = append(pkgs, m.Pattern()) 231 } else { 232 pkgs = append(pkgs, m.Pkgs...) 233 } 234 } 235 return pkgs 236 } 237 238 // downloadCache records the import paths we have already 239 // considered during the download, to avoid duplicate work when 240 // there is more than one dependency sequence leading to 241 // a particular package. 242 var downloadCache = map[string]bool{} 243 244 // downloadRootCache records the version control repository 245 // root directories we have already considered during the download. 246 // For example, all the packages in the github.com/google/codesearch repo 247 // share the same root (the directory for that path), and we only need 248 // to run the hg commands to consider each repository once. 249 var downloadRootCache = map[string]bool{} 250 251 // download runs the download half of the get command 252 // for the package or pattern named by the argument. 253 func download(ctx context.Context, arg string, parent *load.Package, stk *load.ImportStack, mode int) { 254 if mode&load.ResolveImport != 0 { 255 // Caller is responsible for expanding vendor paths. 256 panic("internal error: download mode has useVendor set") 257 } 258 load1 := func(path string, mode int) *load.Package { 259 if parent == nil { 260 mode := 0 // don't do module or vendor resolution 261 return load.LoadImport(ctx, load.PackageOpts{}, path, base.Cwd(), nil, stk, nil, mode) 262 } 263 return load.LoadImport(ctx, load.PackageOpts{}, path, parent.Dir, parent, stk, nil, mode|load.ResolveModule) 264 } 265 266 p := load1(arg, mode) 267 if p.Error != nil && p.Error.Hard { 268 base.Errorf("%s", p.Error) 269 return 270 } 271 272 // loadPackage inferred the canonical ImportPath from arg. 273 // Use that in the following to prevent hysteresis effects 274 // in e.g. downloadCache and packageCache. 275 // This allows invocations such as: 276 // mkdir -p $GOPATH/src/github.com/user 277 // cd $GOPATH/src/github.com/user 278 // go get ./foo 279 // see: golang.org/issue/9767 280 arg = p.ImportPath 281 282 // There's nothing to do if this is a package in the standard library. 283 if p.Standard { 284 return 285 } 286 287 // Only process each package once. 288 // (Unless we're fetching test dependencies for this package, 289 // in which case we want to process it again.) 290 if downloadCache[arg] && mode&load.GetTestDeps == 0 { 291 return 292 } 293 downloadCache[arg] = true 294 295 pkgs := []*load.Package{p} 296 wildcardOkay := len(*stk) == 0 297 isWildcard := false 298 299 // Download if the package is missing, or update if we're using -u. 300 if p.Dir == "" || *getU { 301 // The actual download. 302 stk.Push(arg) 303 err := downloadPackage(p) 304 if err != nil { 305 base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err}) 306 stk.Pop() 307 return 308 } 309 stk.Pop() 310 311 args := []string{arg} 312 // If the argument has a wildcard in it, re-evaluate the wildcard. 313 // We delay this until after reloadPackage so that the old entry 314 // for p has been replaced in the package cache. 315 if wildcardOkay && strings.Contains(arg, "...") { 316 match := search.NewMatch(arg) 317 if match.IsLocal() { 318 noModRoots := []string{} // We're in gopath mode, so there are no modroots. 319 match.MatchDirs(noModRoots) 320 args = match.Dirs 321 } else { 322 match.MatchPackages() 323 args = match.Pkgs 324 } 325 for _, err := range match.Errs { 326 base.Errorf("%s", err) 327 } 328 isWildcard = true 329 } 330 331 // Clear all relevant package cache entries before 332 // doing any new loads. 333 load.ClearPackageCachePartial(args) 334 335 pkgs = pkgs[:0] 336 for _, arg := range args { 337 // Note: load calls loadPackage or loadImport, 338 // which push arg onto stk already. 339 // Do not push here too, or else stk will say arg imports arg. 340 p := load1(arg, mode) 341 if p.Error != nil { 342 base.Errorf("%s", p.Error) 343 continue 344 } 345 pkgs = append(pkgs, p) 346 } 347 } 348 349 // Process package, which might now be multiple packages 350 // due to wildcard expansion. 351 for _, p := range pkgs { 352 if *getFix { 353 files := base.RelPaths(p.InternalAllGoFiles()) 354 base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files)) 355 356 // The imports might have changed, so reload again. 357 p = load.ReloadPackageNoFlags(arg, stk) 358 if p.Error != nil { 359 base.Errorf("%s", p.Error) 360 return 361 } 362 } 363 364 if isWildcard { 365 // Report both the real package and the 366 // wildcard in any error message. 367 stk.Push(p.ImportPath) 368 } 369 370 // Process dependencies, now that we know what they are. 371 imports := p.Imports 372 if mode&load.GetTestDeps != 0 { 373 // Process test dependencies when -t is specified. 374 // (But don't get test dependencies for test dependencies: 375 // we always pass mode 0 to the recursive calls below.) 376 imports = str.StringList(imports, p.TestImports, p.XTestImports) 377 } 378 for i, path := range imports { 379 if path == "C" { 380 continue 381 } 382 // Fail fast on import naming full vendor path. 383 // Otherwise expand path as needed for test imports. 384 // Note that p.Imports can have additional entries beyond p.Internal.Build.Imports. 385 orig := path 386 if i < len(p.Internal.Build.Imports) { 387 orig = p.Internal.Build.Imports[i] 388 } 389 if j, ok := load.FindVendor(orig); ok { 390 stk.Push(path) 391 err := &load.PackageError{ 392 ImportStack: stk.Copy(), 393 Err: load.ImportErrorf(path, "%s must be imported as %s", path, path[j+len("vendor/"):]), 394 } 395 stk.Pop() 396 base.Errorf("%s", err) 397 continue 398 } 399 // If this is a test import, apply module and vendor lookup now. 400 // We cannot pass ResolveImport to download, because 401 // download does caching based on the value of path, 402 // so it must be the fully qualified path already. 403 if i >= len(p.Imports) { 404 path = load.ResolveImportPath(p, path) 405 } 406 download(ctx, path, p, stk, 0) 407 } 408 409 if isWildcard { 410 stk.Pop() 411 } 412 } 413 } 414 415 // downloadPackage runs the create or download command 416 // to make the first copy of or update a copy of the given package. 417 func downloadPackage(p *load.Package) error { 418 var ( 419 vcsCmd *vcs.Cmd 420 repo, rootPath, repoDir string 421 err error 422 blindRepo bool // set if the repo has unusual configuration 423 ) 424 425 // p can be either a real package, or a pseudo-package whose “import path” is 426 // actually a wildcard pattern. 427 // Trim the path at the element containing the first wildcard, 428 // and hope that it applies to the wildcarded parts too. 429 // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH. 430 importPrefix := p.ImportPath 431 if i := strings.Index(importPrefix, "..."); i >= 0 { 432 slash := strings.LastIndexByte(importPrefix[:i], '/') 433 if slash < 0 { 434 return fmt.Errorf("cannot expand ... in %q", p.ImportPath) 435 } 436 importPrefix = importPrefix[:slash] 437 } 438 if err := checkImportPath(importPrefix); err != nil { 439 return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err) 440 } 441 security := web.SecureOnly 442 if module.MatchPrefixPatterns(cfg.GOINSECURE, importPrefix) { 443 security = web.Insecure 444 } 445 446 if p.Internal.Build.SrcRoot != "" { 447 // Directory exists. Look for checkout along path to src. 448 const allowNesting = false 449 repoDir, vcsCmd, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot, allowNesting) 450 if err != nil { 451 return err 452 } 453 if !str.HasFilePathPrefix(repoDir, p.Internal.Build.SrcRoot) { 454 panic(fmt.Sprintf("repository %q not in source root %q", repo, p.Internal.Build.SrcRoot)) 455 } 456 rootPath = str.TrimFilePathPrefix(repoDir, p.Internal.Build.SrcRoot) 457 if err := vcs.CheckGOVCS(vcsCmd, rootPath); err != nil { 458 return err 459 } 460 461 repo = "<local>" // should be unused; make distinctive 462 463 // Double-check where it came from. 464 if *getU && vcsCmd.RemoteRepo != nil { 465 dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) 466 remote, err := vcsCmd.RemoteRepo(vcsCmd, dir) 467 if err != nil { 468 // Proceed anyway. The package is present; we likely just don't understand 469 // the repo configuration (e.g. unusual remote protocol). 470 blindRepo = true 471 } 472 repo = remote 473 if !*getF && err == nil { 474 if rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security); err == nil { 475 repo := rr.Repo 476 if rr.VCS.ResolveRepo != nil { 477 resolved, err := rr.VCS.ResolveRepo(rr.VCS, dir, repo) 478 if err == nil { 479 repo = resolved 480 } 481 } 482 if remote != repo && rr.IsCustom { 483 return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.Root, repo, dir, remote) 484 } 485 } 486 } 487 } 488 } else { 489 // Analyze the import path to determine the version control system, 490 // repository, and the import path for the root of the repository. 491 rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security) 492 if err != nil { 493 return err 494 } 495 vcsCmd, repo, rootPath = rr.VCS, rr.Repo, rr.Root 496 } 497 if !blindRepo && !vcsCmd.IsSecure(repo) && security != web.Insecure { 498 return fmt.Errorf("cannot download: %v uses insecure protocol", repo) 499 } 500 501 if p.Internal.Build.SrcRoot == "" { 502 // Package not found. Put in first directory of $GOPATH. 503 list := filepath.SplitList(cfg.BuildContext.GOPATH) 504 if len(list) == 0 { 505 return fmt.Errorf("cannot download: $GOPATH not set. For more details see: 'go help gopath'") 506 } 507 // Guard against people setting GOPATH=$GOROOT. 508 if filepath.Clean(list[0]) == filepath.Clean(cfg.GOROOT) { 509 return fmt.Errorf("cannot download: $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'") 510 } 511 if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil { 512 return fmt.Errorf("cannot download: %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0]) 513 } 514 p.Internal.Build.Root = list[0] 515 p.Internal.Build.SrcRoot = filepath.Join(list[0], "src") 516 p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg") 517 } 518 root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) 519 520 if err := vcs.CheckNested(vcsCmd, root, p.Internal.Build.SrcRoot); err != nil { 521 return err 522 } 523 524 // If we've considered this repository already, don't do it again. 525 if downloadRootCache[root] { 526 return nil 527 } 528 downloadRootCache[root] = true 529 530 if cfg.BuildV { 531 fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath) 532 } 533 534 // Check that this is an appropriate place for the repo to be checked out. 535 // The target directory must either not exist or have a repo checked out already. 536 meta := filepath.Join(root, "."+vcsCmd.Cmd) 537 if _, err := os.Stat(meta); err != nil { 538 // Metadata file or directory does not exist. Prepare to checkout new copy. 539 // Some version control tools require the target directory not to exist. 540 // We require that too, just to avoid stepping on existing work. 541 if _, err := os.Stat(root); err == nil { 542 return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta) 543 } 544 545 _, err := os.Stat(p.Internal.Build.Root) 546 gopathExisted := err == nil 547 548 // Some version control tools require the parent of the target to exist. 549 parent, _ := filepath.Split(root) 550 if err = os.MkdirAll(parent, 0777); err != nil { 551 return err 552 } 553 if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH { 554 fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root) 555 } 556 557 if err = vcsCmd.Create(root, repo); err != nil { 558 return err 559 } 560 } else { 561 // Metadata directory does exist; download incremental updates. 562 if err = vcsCmd.Download(root); err != nil { 563 return err 564 } 565 } 566 567 if cfg.BuildN { 568 // Do not show tag sync in -n; it's noise more than anything, 569 // and since we're not running commands, no tag will be found. 570 // But avoid printing nothing. 571 fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcsCmd.Cmd) 572 return nil 573 } 574 575 // Select and sync to appropriate version of the repository. 576 tags, err := vcsCmd.Tags(root) 577 if err != nil { 578 return err 579 } 580 vers := runtime.Version() 581 if i := strings.Index(vers, " "); i >= 0 { 582 vers = vers[:i] 583 } 584 if err := vcsCmd.TagSync(root, selectTag(vers, tags)); err != nil { 585 return err 586 } 587 588 return nil 589 } 590 591 // selectTag returns the closest matching tag for a given version. 592 // Closest means the latest one that is not after the current release. 593 // Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form. 594 // Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number). 595 // Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD". 596 // 597 // NOTE(rsc): Eventually we will need to decide on some logic here. 598 // For now, there is only "go1". This matches the docs in go help get. 599 func selectTag(goVersion string, tags []string) (match string) { 600 for _, t := range tags { 601 if t == "go1" { 602 return "go1" 603 } 604 } 605 return "" 606 } 607 608 // checkImportPath is like module.CheckImportPath, but it forbids leading dots 609 // in path elements. This can lead to 'go get' creating .git and other VCS 610 // directories in places we might run VCS tools later. 611 func checkImportPath(path string) error { 612 if err := module.CheckImportPath(path); err != nil { 613 return err 614 } 615 checkElem := func(elem string) error { 616 if elem[0] == '.' { 617 return fmt.Errorf("malformed import path %q: leading dot in path element", path) 618 } 619 return nil 620 } 621 elemStart := 0 622 for i, r := range path { 623 if r == '/' { 624 if err := checkElem(path[elemStart:]); err != nil { 625 return err 626 } 627 elemStart = i + 1 628 } 629 } 630 if err := checkElem(path[elemStart:]); err != nil { 631 return err 632 } 633 return nil 634 }