github.com/ccccaoqing/test@v0.0.0-20220510085219-3985d23445c0/src/cmd/go/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 main 6 7 import ( 8 "fmt" 9 "go/build" 10 "os" 11 "path/filepath" 12 "regexp" 13 "runtime" 14 "strconv" 15 "strings" 16 ) 17 18 var cmdGet = &Command{ 19 UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]", 20 Short: "download and install packages and dependencies", 21 Long: ` 22 Get downloads and installs the packages named by the import paths, 23 along with their dependencies. 24 25 The -d flag instructs get to stop after downloading the packages; that is, 26 it instructs get not to install the packages. 27 28 The -f flag, valid only when -u is set, forces get -u not to verify that 29 each package has been checked out from the source control repository 30 implied by its import path. This can be useful if the source is a local fork 31 of the original. 32 33 The -fix flag instructs get to run the fix tool on the downloaded packages 34 before resolving dependencies or building the code. 35 36 The -t flag instructs get to also download the packages required to build 37 the tests for the specified packages. 38 39 The -u flag instructs get to use the network to update the named packages 40 and their dependencies. By default, get uses the network to check out 41 missing packages but does not use it to look for updates to existing packages. 42 43 Get also accepts build flags to control the installation. See 'go help build'. 44 45 When checking out or updating a package, get looks for a branch or tag 46 that matches the locally installed version of Go. The most important 47 rule is that if the local installation is running version "go1", get 48 searches for a branch or tag named "go1". If no such version exists it 49 retrieves the most recent version of the package. 50 51 For more about specifying packages, see 'go help packages'. 52 53 For more about how 'go get' finds source code to 54 download, see 'go help importpath'. 55 56 See also: go build, go install, go clean. 57 `, 58 } 59 60 var getD = cmdGet.Flag.Bool("d", false, "") 61 var getF = cmdGet.Flag.Bool("f", false, "") 62 var getT = cmdGet.Flag.Bool("t", false, "") 63 var getU = cmdGet.Flag.Bool("u", false, "") 64 var getFix = cmdGet.Flag.Bool("fix", false, "") 65 66 func init() { 67 addBuildFlags(cmdGet) 68 cmdGet.Run = runGet // break init loop 69 } 70 71 func runGet(cmd *Command, args []string) { 72 if *getF && !*getU { 73 fatalf("go get: cannot use -f flag without -u") 74 } 75 76 // Phase 1. Download/update. 77 var stk importStack 78 for _, arg := range downloadPaths(args) { 79 download(arg, &stk, *getT) 80 } 81 exitIfErrors() 82 83 // Phase 2. Rescan packages and re-evaluate args list. 84 85 // Code we downloaded and all code that depends on it 86 // needs to be evicted from the package cache so that 87 // the information will be recomputed. Instead of keeping 88 // track of the reverse dependency information, evict 89 // everything. 90 for name := range packageCache { 91 delete(packageCache, name) 92 } 93 94 args = importPaths(args) 95 96 // Phase 3. Install. 97 if *getD { 98 // Download only. 99 // Check delayed until now so that importPaths 100 // has a chance to print errors. 101 return 102 } 103 104 runInstall(cmd, args) 105 } 106 107 // downloadPaths prepares the list of paths to pass to download. 108 // It expands ... patterns that can be expanded. If there is no match 109 // for a particular pattern, downloadPaths leaves it in the result list, 110 // in the hope that we can figure out the repository from the 111 // initial ...-free prefix. 112 func downloadPaths(args []string) []string { 113 args = importPathsNoDotExpansion(args) 114 var out []string 115 for _, a := range args { 116 if strings.Contains(a, "...") { 117 var expand []string 118 // Use matchPackagesInFS to avoid printing 119 // warnings. They will be printed by the 120 // eventual call to importPaths instead. 121 if build.IsLocalImport(a) { 122 expand = matchPackagesInFS(a) 123 } else { 124 expand = matchPackages(a) 125 } 126 if len(expand) > 0 { 127 out = append(out, expand...) 128 continue 129 } 130 } 131 out = append(out, a) 132 } 133 return out 134 } 135 136 // downloadCache records the import paths we have already 137 // considered during the download, to avoid duplicate work when 138 // there is more than one dependency sequence leading to 139 // a particular package. 140 var downloadCache = map[string]bool{} 141 142 // downloadRootCache records the version control repository 143 // root directories we have already considered during the download. 144 // For example, all the packages in the code.google.com/p/codesearch repo 145 // share the same root (the directory for that path), and we only need 146 // to run the hg commands to consider each repository once. 147 var downloadRootCache = map[string]bool{} 148 149 // download runs the download half of the get command 150 // for the package named by the argument. 151 func download(arg string, stk *importStack, getTestDeps bool) { 152 p := loadPackage(arg, stk) 153 if p.Error != nil && p.Error.hard { 154 errorf("%s", p.Error) 155 return 156 } 157 158 // There's nothing to do if this is a package in the standard library. 159 if p.Standard { 160 return 161 } 162 163 // Only process each package once. 164 // (Unless we're fetching test dependencies for this package, 165 // in which case we want to process it again.) 166 if downloadCache[arg] && !getTestDeps { 167 return 168 } 169 downloadCache[arg] = true 170 171 pkgs := []*Package{p} 172 wildcardOkay := len(*stk) == 0 173 isWildcard := false 174 175 // Download if the package is missing, or update if we're using -u. 176 if p.Dir == "" || *getU { 177 // The actual download. 178 stk.push(p.ImportPath) 179 err := downloadPackage(p) 180 if err != nil { 181 errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()}) 182 stk.pop() 183 return 184 } 185 186 args := []string{arg} 187 // If the argument has a wildcard in it, re-evaluate the wildcard. 188 // We delay this until after reloadPackage so that the old entry 189 // for p has been replaced in the package cache. 190 if wildcardOkay && strings.Contains(arg, "...") { 191 if build.IsLocalImport(arg) { 192 args = matchPackagesInFS(arg) 193 } else { 194 args = matchPackages(arg) 195 } 196 isWildcard = true 197 } 198 199 // Clear all relevant package cache entries before 200 // doing any new loads. 201 for _, arg := range args { 202 p := packageCache[arg] 203 if p != nil { 204 delete(packageCache, p.Dir) 205 delete(packageCache, p.ImportPath) 206 } 207 } 208 209 pkgs = pkgs[:0] 210 for _, arg := range args { 211 stk.push(arg) 212 p := loadPackage(arg, stk) 213 stk.pop() 214 if p.Error != nil { 215 errorf("%s", p.Error) 216 continue 217 } 218 pkgs = append(pkgs, p) 219 } 220 } 221 222 // Process package, which might now be multiple packages 223 // due to wildcard expansion. 224 for _, p := range pkgs { 225 if *getFix { 226 run(stringList(tool("fix"), relPaths(p.allgofiles))) 227 228 // The imports might have changed, so reload again. 229 p = reloadPackage(arg, stk) 230 if p.Error != nil { 231 errorf("%s", p.Error) 232 return 233 } 234 } 235 236 if isWildcard { 237 // Report both the real package and the 238 // wildcard in any error message. 239 stk.push(p.ImportPath) 240 } 241 242 // Process dependencies, now that we know what they are. 243 for _, dep := range p.deps { 244 // Don't get test dependencies recursively. 245 download(dep.ImportPath, stk, false) 246 } 247 if getTestDeps { 248 // Process test dependencies when -t is specified. 249 // (Don't get test dependencies for test dependencies.) 250 for _, path := range p.TestImports { 251 download(path, stk, false) 252 } 253 for _, path := range p.XTestImports { 254 download(path, stk, false) 255 } 256 } 257 258 if isWildcard { 259 stk.pop() 260 } 261 } 262 } 263 264 // downloadPackage runs the create or download command 265 // to make the first copy of or update a copy of the given package. 266 func downloadPackage(p *Package) error { 267 var ( 268 vcs *vcsCmd 269 repo, rootPath string 270 err error 271 ) 272 if p.build.SrcRoot != "" { 273 // Directory exists. Look for checkout along path to src. 274 vcs, rootPath, err = vcsForDir(p) 275 if err != nil { 276 return err 277 } 278 repo = "<local>" // should be unused; make distinctive 279 280 // Double-check where it came from. 281 if *getU && vcs.remoteRepo != nil && !*getF { 282 dir := filepath.Join(p.build.SrcRoot, rootPath) 283 if remote, err := vcs.remoteRepo(vcs, dir); err == nil { 284 if rr, err := repoRootForImportPath(p.ImportPath); err == nil { 285 repo := rr.repo 286 if rr.vcs.resolveRepo != nil { 287 resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo) 288 if err == nil { 289 repo = resolved 290 } 291 } 292 if remote != repo { 293 return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote) 294 } 295 } 296 } 297 } 298 } else { 299 // Analyze the import path to determine the version control system, 300 // repository, and the import path for the root of the repository. 301 rr, err := repoRootForImportPath(p.ImportPath) 302 if err != nil { 303 return err 304 } 305 vcs, repo, rootPath = rr.vcs, rr.repo, rr.root 306 } 307 308 if p.build.SrcRoot == "" { 309 // Package not found. Put in first directory of $GOPATH. 310 list := filepath.SplitList(buildContext.GOPATH) 311 if len(list) == 0 { 312 return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath") 313 } 314 // Guard against people setting GOPATH=$GOROOT. 315 if list[0] == goroot { 316 return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath") 317 } 318 p.build.SrcRoot = filepath.Join(list[0], "src") 319 p.build.PkgRoot = filepath.Join(list[0], "pkg") 320 } 321 root := filepath.Join(p.build.SrcRoot, rootPath) 322 // If we've considered this repository already, don't do it again. 323 if downloadRootCache[root] { 324 return nil 325 } 326 downloadRootCache[root] = true 327 328 if buildV { 329 fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath) 330 } 331 332 // Check that this is an appropriate place for the repo to be checked out. 333 // The target directory must either not exist or have a repo checked out already. 334 meta := filepath.Join(root, "."+vcs.cmd) 335 st, err := os.Stat(meta) 336 if err == nil && !st.IsDir() { 337 return fmt.Errorf("%s exists but is not a directory", meta) 338 } 339 if err != nil { 340 // Metadata directory does not exist. Prepare to checkout new copy. 341 // Some version control tools require the target directory not to exist. 342 // We require that too, just to avoid stepping on existing work. 343 if _, err := os.Stat(root); err == nil { 344 return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta) 345 } 346 // Some version control tools require the parent of the target to exist. 347 parent, _ := filepath.Split(root) 348 if err = os.MkdirAll(parent, 0777); err != nil { 349 return err 350 } 351 if err = vcs.create(root, repo); err != nil { 352 return err 353 } 354 } else { 355 // Metadata directory does exist; download incremental updates. 356 if err = vcs.download(root); err != nil { 357 return err 358 } 359 } 360 361 if buildN { 362 // Do not show tag sync in -n; it's noise more than anything, 363 // and since we're not running commands, no tag will be found. 364 // But avoid printing nothing. 365 fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd) 366 return nil 367 } 368 369 // Select and sync to appropriate version of the repository. 370 tags, err := vcs.tags(root) 371 if err != nil { 372 return err 373 } 374 vers := runtime.Version() 375 if i := strings.Index(vers, " "); i >= 0 { 376 vers = vers[:i] 377 } 378 if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil { 379 return err 380 } 381 382 return nil 383 } 384 385 // goTag matches go release tags such as go1 and go1.2.3. 386 // The numbers involved must be small (at most 4 digits), 387 // have no unnecessary leading zeros, and the version cannot 388 // end in .0 - it is go1, not go1.0 or go1.0.0. 389 var goTag = regexp.MustCompile( 390 `^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`, 391 ) 392 393 // selectTag returns the closest matching tag for a given version. 394 // Closest means the latest one that is not after the current release. 395 // Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form. 396 // Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number). 397 // Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD". 398 // 399 // NOTE(rsc): Eventually we will need to decide on some logic here. 400 // For now, there is only "go1". This matches the docs in go help get. 401 func selectTag(goVersion string, tags []string) (match string) { 402 for _, t := range tags { 403 if t == "go1" { 404 return "go1" 405 } 406 } 407 return "" 408 409 /* 410 if goTag.MatchString(goVersion) { 411 v := goVersion 412 for _, t := range tags { 413 if !goTag.MatchString(t) { 414 continue 415 } 416 if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 { 417 match = t 418 } 419 } 420 } 421 422 return match 423 */ 424 } 425 426 // cmpGoVersion returns -1, 0, +1 reporting whether 427 // x < y, x == y, or x > y. 428 func cmpGoVersion(x, y string) int { 429 // Malformed strings compare less than well-formed strings. 430 if !goTag.MatchString(x) { 431 return -1 432 } 433 if !goTag.MatchString(y) { 434 return +1 435 } 436 437 // Compare numbers in sequence. 438 xx := strings.Split(x[len("go"):], ".") 439 yy := strings.Split(y[len("go"):], ".") 440 441 for i := 0; i < len(xx) && i < len(yy); i++ { 442 // The Atoi are guaranteed to succeed 443 // because the versions match goTag. 444 xi, _ := strconv.Atoi(xx[i]) 445 yi, _ := strconv.Atoi(yy[i]) 446 if xi < yi { 447 return -1 448 } else if xi > yi { 449 return +1 450 } 451 } 452 453 if len(xx) < len(yy) { 454 return -1 455 } 456 if len(xx) > len(yy) { 457 return +1 458 } 459 return 0 460 }