github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-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 "fmt" 10 "go/build" 11 "os" 12 "path/filepath" 13 "runtime" 14 "strings" 15 16 "github.com/gagliardetto/golang-go/cmd/go/not-internal/base" 17 "github.com/gagliardetto/golang-go/cmd/go/not-internal/cfg" 18 "github.com/gagliardetto/golang-go/cmd/go/not-internal/load" 19 "github.com/gagliardetto/golang-go/cmd/go/not-internal/search" 20 "github.com/gagliardetto/golang-go/cmd/go/not-internal/str" 21 "github.com/gagliardetto/golang-go/cmd/go/not-internal/web" 22 "github.com/gagliardetto/golang-go/cmd/go/not-internal/work" 23 ) 24 25 var CmdGet = &base.Command{ 26 UsageLine: "go get [-d] [-f] [-t] [-u] [-v] [-fix] [-insecure] [build flags] [packages]", 27 Short: "download and install packages and dependencies", 28 Long: ` 29 Get downloads the packages named by the import paths, along with their 30 dependencies. It then installs the named packages, like 'go install'. 31 32 The -d flag instructs get to stop after downloading the packages; that is, 33 it instructs get not to install the packages. 34 35 The -f flag, valid only when -u is set, forces get -u not to verify that 36 each package has been checked out from the source control repository 37 implied by its import path. This can be useful if the source is a local fork 38 of the original. 39 40 The -fix flag instructs get to run the fix tool on the downloaded packages 41 before resolving dependencies or building the code. 42 43 The -insecure flag permits fetching from repositories and resolving 44 custom domains using insecure schemes such as HTTP. Use with caution. 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 107 Insecure bool 108 ) 109 110 func init() { 111 work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags) 112 CmdGet.Run = runGet // break init loop 113 CmdGet.Flag.BoolVar(&Insecure, "insecure", Insecure, "") 114 } 115 116 func runGet(cmd *base.Command, args []string) { 117 if cfg.ModulesEnabled { 118 // Should not happen: main.go should install the separate module-enabled get code. 119 base.Fatalf("go get: modules not implemented") 120 } 121 122 work.BuildInit() 123 124 if *getF && !*getU { 125 base.Fatalf("go get: cannot use -f flag without -u") 126 } 127 128 // Disable any prompting for passwords by Git. 129 // Only has an effect for 2.3.0 or later, but avoiding 130 // the prompt in earlier versions is just too hard. 131 // If user has explicitly set GIT_TERMINAL_PROMPT=1, keep 132 // prompting. 133 // See golang.org/issue/9341 and golang.org/issue/12706. 134 if os.Getenv("GIT_TERMINAL_PROMPT") == "" { 135 os.Setenv("GIT_TERMINAL_PROMPT", "0") 136 } 137 138 // Disable any ssh connection pooling by Git. 139 // If a Git subprocess forks a child into the background to cache a new connection, 140 // that child keeps stdout/stderr open. After the Git subprocess exits, 141 // os /exec expects to be able to read from the stdout/stderr pipe 142 // until EOF to get all the data that the Git subprocess wrote before exiting. 143 // The EOF doesn't come until the child exits too, because the child 144 // is holding the write end of the pipe. 145 // This is unfortunate, but it has come up at least twice 146 // (see golang.org/issue/13453 and golang.org/issue/16104) 147 // and confuses users when it does. 148 // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND, 149 // assume they know what they are doing and don't step on it. 150 // But default to turning off ControlMaster. 151 if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" { 152 os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no") 153 } 154 155 // Phase 1. Download/update. 156 var stk load.ImportStack 157 mode := 0 158 if *getT { 159 mode |= load.GetTestDeps 160 } 161 for _, pkg := range downloadPaths(args) { 162 download(pkg, nil, &stk, mode) 163 } 164 base.ExitIfErrors() 165 166 // Phase 2. Rescan packages and re-evaluate args list. 167 168 // Code we downloaded and all code that depends on it 169 // needs to be evicted from the package cache so that 170 // the information will be recomputed. Instead of keeping 171 // track of the reverse dependency information, evict 172 // everything. 173 load.ClearPackageCache() 174 175 pkgs := load.PackagesForBuild(args) 176 177 // Phase 3. Install. 178 if *getD { 179 // Download only. 180 // Check delayed until now so that importPaths 181 // and packagesForBuild have a chance to print errors. 182 return 183 } 184 185 work.InstallPackages(args, pkgs) 186 } 187 188 // downloadPaths prepares the list of paths to pass to download. 189 // It expands ... patterns that can be expanded. If there is no match 190 // for a particular pattern, downloadPaths leaves it in the result list, 191 // in the hope that we can figure out the repository from the 192 // initial ...-free prefix. 193 func downloadPaths(patterns []string) []string { 194 for _, arg := range patterns { 195 if strings.Contains(arg, "@") { 196 base.Fatalf("go: cannot use path@version syntax in GOPATH mode") 197 } 198 } 199 var pkgs []string 200 for _, m := range search.ImportPathsQuiet(patterns) { 201 if len(m.Pkgs) == 0 && strings.Contains(m.Pattern, "...") { 202 pkgs = append(pkgs, m.Pattern) 203 } else { 204 pkgs = append(pkgs, m.Pkgs...) 205 } 206 } 207 return pkgs 208 } 209 210 // downloadCache records the import paths we have already 211 // considered during the download, to avoid duplicate work when 212 // there is more than one dependency sequence leading to 213 // a particular package. 214 var downloadCache = map[string]bool{} 215 216 // downloadRootCache records the version control repository 217 // root directories we have already considered during the download. 218 // For example, all the packages in the github.com/google/codesearch repo 219 // share the same root (the directory for that path), and we only need 220 // to run the hg commands to consider each repository once. 221 var downloadRootCache = map[string]bool{} 222 223 // download runs the download half of the get command 224 // for the package or pattern named by the argument. 225 func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) { 226 if mode&load.ResolveImport != 0 { 227 // Caller is responsible for expanding vendor paths. 228 panic("internal error: download mode has useVendor set") 229 } 230 load1 := func(path string, mode int) *load.Package { 231 if parent == nil { 232 mode := 0 // don't do module or vendor resolution 233 return load.LoadImport(path, base.Cwd, nil, stk, nil, mode) 234 } 235 return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule) 236 } 237 238 p := load1(arg, mode) 239 if p.Error != nil && p.Error.Hard { 240 base.Errorf("%s", p.Error) 241 return 242 } 243 244 // loadPackage inferred the canonical ImportPath from arg. 245 // Use that in the following to prevent hysteresis effects 246 // in e.g. downloadCache and packageCache. 247 // This allows invocations such as: 248 // mkdir -p $GOPATH/src/github.com/user 249 // cd $GOPATH/src/github.com/user 250 // go get ./foo 251 // see: golang.org/issue/9767 252 arg = p.ImportPath 253 254 // There's nothing to do if this is a package in the standard library. 255 if p.Standard { 256 return 257 } 258 259 // Only process each package once. 260 // (Unless we're fetching test dependencies for this package, 261 // in which case we want to process it again.) 262 if downloadCache[arg] && mode&load.GetTestDeps == 0 { 263 return 264 } 265 downloadCache[arg] = true 266 267 pkgs := []*load.Package{p} 268 wildcardOkay := len(*stk) == 0 269 isWildcard := false 270 271 // Download if the package is missing, or update if we're using -u. 272 if p.Dir == "" || *getU { 273 // The actual download. 274 stk.Push(arg) 275 err := downloadPackage(p) 276 if err != nil { 277 base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err}) 278 stk.Pop() 279 return 280 } 281 stk.Pop() 282 283 args := []string{arg} 284 // If the argument has a wildcard in it, re-evaluate the wildcard. 285 // We delay this until after reloadPackage so that the old entry 286 // for p has been replaced in the package cache. 287 if wildcardOkay && strings.Contains(arg, "...") { 288 if build.IsLocalImport(arg) { 289 args = search.MatchPackagesInFS(arg).Pkgs 290 } else { 291 args = search.MatchPackages(arg).Pkgs 292 } 293 isWildcard = true 294 } 295 296 // Clear all relevant package cache entries before 297 // doing any new loads. 298 load.ClearPackageCachePartial(args) 299 300 pkgs = pkgs[:0] 301 for _, arg := range args { 302 // Note: load calls loadPackage or loadImport, 303 // which push arg onto stk already. 304 // Do not push here too, or else stk will say arg imports arg. 305 p := load1(arg, mode) 306 if p.Error != nil { 307 base.Errorf("%s", p.Error) 308 continue 309 } 310 pkgs = append(pkgs, p) 311 } 312 } 313 314 // Process package, which might now be multiple packages 315 // due to wildcard expansion. 316 for _, p := range pkgs { 317 if *getFix { 318 files := base.RelPaths(p.InternalAllGoFiles()) 319 base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files)) 320 321 // The imports might have changed, so reload again. 322 p = load.ReloadPackageNoFlags(arg, stk) 323 if p.Error != nil { 324 base.Errorf("%s", p.Error) 325 return 326 } 327 } 328 329 if isWildcard { 330 // Report both the real package and the 331 // wildcard in any error message. 332 stk.Push(p.ImportPath) 333 } 334 335 // Process dependencies, now that we know what they are. 336 imports := p.Imports 337 if mode&load.GetTestDeps != 0 { 338 // Process test dependencies when -t is specified. 339 // (But don't get test dependencies for test dependencies: 340 // we always pass mode 0 to the recursive calls below.) 341 imports = str.StringList(imports, p.TestImports, p.XTestImports) 342 } 343 for i, path := range imports { 344 if path == "C" { 345 continue 346 } 347 // Fail fast on import naming full vendor path. 348 // Otherwise expand path as needed for test imports. 349 // Note that p.Imports can have additional entries beyond p.Internal.Build.Imports. 350 orig := path 351 if i < len(p.Internal.Build.Imports) { 352 orig = p.Internal.Build.Imports[i] 353 } 354 if j, ok := load.FindVendor(orig); ok { 355 stk.Push(path) 356 err := &load.PackageError{ 357 ImportStack: stk.Copy(), 358 Err: load.ImportErrorf(path, "%s must be imported as %s", path, path[j+len("vendor/"):]), 359 } 360 stk.Pop() 361 base.Errorf("%s", err) 362 continue 363 } 364 // If this is a test import, apply module and vendor lookup now. 365 // We cannot pass ResolveImport to download, because 366 // download does caching based on the value of path, 367 // so it must be the fully qualified path already. 368 if i >= len(p.Imports) { 369 path = load.ResolveImportPath(p, path) 370 } 371 download(path, p, stk, 0) 372 } 373 374 if isWildcard { 375 stk.Pop() 376 } 377 } 378 } 379 380 // downloadPackage runs the create or download command 381 // to make the first copy of or update a copy of the given package. 382 func downloadPackage(p *load.Package) error { 383 var ( 384 vcs *vcsCmd 385 repo, rootPath string 386 err error 387 blindRepo bool // set if the repo has unusual configuration 388 ) 389 390 security := web.SecureOnly 391 if Insecure { 392 security = web.Insecure 393 } 394 395 // p can be either a real package, or a pseudo-package whose “import path” is 396 // actually a wildcard pattern. 397 // Trim the path at the element containing the first wildcard, 398 // and hope that it applies to the wildcarded parts too. 399 // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH. 400 importPrefix := p.ImportPath 401 if i := strings.Index(importPrefix, "..."); i >= 0 { 402 slash := strings.LastIndexByte(importPrefix[:i], '/') 403 if slash < 0 { 404 return fmt.Errorf("cannot expand ... in %q", p.ImportPath) 405 } 406 importPrefix = importPrefix[:slash] 407 } 408 if err := CheckImportPath(importPrefix); err != nil { 409 return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err) 410 } 411 412 if p.Internal.Build.SrcRoot != "" { 413 // Directory exists. Look for checkout along path to src. 414 vcs, rootPath, err = vcsFromDir(p.Dir, p.Internal.Build.SrcRoot) 415 if err != nil { 416 return err 417 } 418 repo = "<local>" // should be unused; make distinctive 419 420 // Double-check where it came from. 421 if *getU && vcs.remoteRepo != nil { 422 dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) 423 remote, err := vcs.remoteRepo(vcs, dir) 424 if err != nil { 425 // Proceed anyway. The package is present; we likely just don't understand 426 // the repo configuration (e.g. unusual remote protocol). 427 blindRepo = true 428 } 429 repo = remote 430 if !*getF && err == nil { 431 if rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security); err == nil { 432 repo := rr.Repo 433 if rr.vcs.resolveRepo != nil { 434 resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo) 435 if err == nil { 436 repo = resolved 437 } 438 } 439 if remote != repo && rr.IsCustom { 440 return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.Root, repo, dir, remote) 441 } 442 } 443 } 444 } 445 } else { 446 // Analyze the import path to determine the version control system, 447 // repository, and the import path for the root of the repository. 448 rr, err := RepoRootForImportPath(importPrefix, IgnoreMod, security) 449 if err != nil { 450 return err 451 } 452 vcs, repo, rootPath = rr.vcs, rr.Repo, rr.Root 453 } 454 if !blindRepo && !vcs.isSecure(repo) && !Insecure { 455 return fmt.Errorf("cannot download, %v uses insecure protocol", repo) 456 } 457 458 if p.Internal.Build.SrcRoot == "" { 459 // Package not found. Put in first directory of $GOPATH. 460 list := filepath.SplitList(cfg.BuildContext.GOPATH) 461 if len(list) == 0 { 462 return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'") 463 } 464 // Guard against people setting GOPATH=$GOROOT. 465 if filepath.Clean(list[0]) == filepath.Clean(cfg.GOROOT) { 466 return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'") 467 } 468 if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil { 469 return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0]) 470 } 471 p.Internal.Build.Root = list[0] 472 p.Internal.Build.SrcRoot = filepath.Join(list[0], "src") 473 p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg") 474 } 475 root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) 476 477 if err := checkNestedVCS(vcs, root, p.Internal.Build.SrcRoot); err != nil { 478 return err 479 } 480 481 // If we've considered this repository already, don't do it again. 482 if downloadRootCache[root] { 483 return nil 484 } 485 downloadRootCache[root] = true 486 487 if cfg.BuildV { 488 fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath) 489 } 490 491 // Check that this is an appropriate place for the repo to be checked out. 492 // The target directory must either not exist or have a repo checked out already. 493 meta := filepath.Join(root, "."+vcs.cmd) 494 if _, err := os.Stat(meta); err != nil { 495 // Metadata file or directory does not exist. Prepare to checkout new copy. 496 // Some version control tools require the target directory not to exist. 497 // We require that too, just to avoid stepping on existing work. 498 if _, err := os.Stat(root); err == nil { 499 return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta) 500 } 501 502 _, err := os.Stat(p.Internal.Build.Root) 503 gopathExisted := err == nil 504 505 // Some version control tools require the parent of the target to exist. 506 parent, _ := filepath.Split(root) 507 if err = os.MkdirAll(parent, 0777); err != nil { 508 return err 509 } 510 if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH { 511 fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root) 512 } 513 514 if err = vcs.create(root, repo); err != nil { 515 return err 516 } 517 } else { 518 // Metadata directory does exist; download incremental updates. 519 if err = vcs.download(root); err != nil { 520 return err 521 } 522 } 523 524 if cfg.BuildN { 525 // Do not show tag sync in -n; it's noise more than anything, 526 // and since we're not running commands, no tag will be found. 527 // But avoid printing nothing. 528 fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd) 529 return nil 530 } 531 532 // Select and sync to appropriate version of the repository. 533 tags, err := vcs.tags(root) 534 if err != nil { 535 return err 536 } 537 vers := runtime.Version() 538 if i := strings.Index(vers, " "); i >= 0 { 539 vers = vers[:i] 540 } 541 if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil { 542 return err 543 } 544 545 return nil 546 } 547 548 // selectTag returns the closest matching tag for a given version. 549 // Closest means the latest one that is not after the current release. 550 // Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form. 551 // Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number). 552 // Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD". 553 // 554 // NOTE(rsc): Eventually we will need to decide on some logic here. 555 // For now, there is only "go1". This matches the docs in go help get. 556 func selectTag(goVersion string, tags []string) (match string) { 557 for _, t := range tags { 558 if t == "go1" { 559 return "go1" 560 } 561 } 562 return "" 563 }