rsc.io/go@v0.0.0-20150416155037-e040fd465409/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 // loadPackage inferred the canonical ImportPath from arg. 159 // Use that in the following to prevent hysteresis effects 160 // in e.g. downloadCache and packageCache. 161 // This allows invocations such as: 162 // mkdir -p $GOPATH/src/github.com/user 163 // cd $GOPATH/src/github.com/user 164 // go get ./foo 165 // see: golang.org/issue/9767 166 arg = p.ImportPath 167 168 // There's nothing to do if this is a package in the standard library. 169 if p.Standard { 170 return 171 } 172 173 // Only process each package once. 174 // (Unless we're fetching test dependencies for this package, 175 // in which case we want to process it again.) 176 if downloadCache[arg] && !getTestDeps { 177 return 178 } 179 downloadCache[arg] = true 180 181 pkgs := []*Package{p} 182 wildcardOkay := len(*stk) == 0 183 isWildcard := false 184 185 // Download if the package is missing, or update if we're using -u. 186 if p.Dir == "" || *getU { 187 // The actual download. 188 stk.push(p.ImportPath) 189 err := downloadPackage(p) 190 if err != nil { 191 errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()}) 192 stk.pop() 193 return 194 } 195 196 args := []string{arg} 197 // If the argument has a wildcard in it, re-evaluate the wildcard. 198 // We delay this until after reloadPackage so that the old entry 199 // for p has been replaced in the package cache. 200 if wildcardOkay && strings.Contains(arg, "...") { 201 if build.IsLocalImport(arg) { 202 args = matchPackagesInFS(arg) 203 } else { 204 args = matchPackages(arg) 205 } 206 isWildcard = true 207 } 208 209 // Clear all relevant package cache entries before 210 // doing any new loads. 211 for _, arg := range args { 212 p := packageCache[arg] 213 if p != nil { 214 delete(packageCache, p.Dir) 215 delete(packageCache, p.ImportPath) 216 } 217 } 218 219 pkgs = pkgs[:0] 220 for _, arg := range args { 221 stk.push(arg) 222 p := loadPackage(arg, stk) 223 stk.pop() 224 if p.Error != nil { 225 errorf("%s", p.Error) 226 continue 227 } 228 pkgs = append(pkgs, p) 229 } 230 } 231 232 // Process package, which might now be multiple packages 233 // due to wildcard expansion. 234 for _, p := range pkgs { 235 if *getFix { 236 run(buildToolExec, stringList(tool("fix"), relPaths(p.allgofiles))) 237 238 // The imports might have changed, so reload again. 239 p = reloadPackage(arg, stk) 240 if p.Error != nil { 241 errorf("%s", p.Error) 242 return 243 } 244 } 245 246 if isWildcard { 247 // Report both the real package and the 248 // wildcard in any error message. 249 stk.push(p.ImportPath) 250 } 251 252 // Process dependencies, now that we know what they are. 253 for _, dep := range p.deps { 254 // Don't get test dependencies recursively. 255 download(dep.ImportPath, stk, false) 256 } 257 if getTestDeps { 258 // Process test dependencies when -t is specified. 259 // (Don't get test dependencies for test dependencies.) 260 for _, path := range p.TestImports { 261 download(path, stk, false) 262 } 263 for _, path := range p.XTestImports { 264 download(path, stk, false) 265 } 266 } 267 268 if isWildcard { 269 stk.pop() 270 } 271 } 272 } 273 274 // downloadPackage runs the create or download command 275 // to make the first copy of or update a copy of the given package. 276 func downloadPackage(p *Package) error { 277 var ( 278 vcs *vcsCmd 279 repo, rootPath string 280 err error 281 ) 282 if p.build.SrcRoot != "" { 283 // Directory exists. Look for checkout along path to src. 284 vcs, rootPath, err = vcsForDir(p) 285 if err != nil { 286 return err 287 } 288 repo = "<local>" // should be unused; make distinctive 289 290 // Double-check where it came from. 291 if *getU && vcs.remoteRepo != nil && !*getF { 292 dir := filepath.Join(p.build.SrcRoot, rootPath) 293 if remote, err := vcs.remoteRepo(vcs, dir); err == nil { 294 if rr, err := repoRootForImportPath(p.ImportPath); err == nil { 295 repo := rr.repo 296 if rr.vcs.resolveRepo != nil { 297 resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo) 298 if err == nil { 299 repo = resolved 300 } 301 } 302 if remote != repo { 303 return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote) 304 } 305 } 306 } 307 } 308 } else { 309 // Analyze the import path to determine the version control system, 310 // repository, and the import path for the root of the repository. 311 rr, err := repoRootForImportPath(p.ImportPath) 312 if err != nil { 313 return err 314 } 315 vcs, repo, rootPath = rr.vcs, rr.repo, rr.root 316 } 317 318 if p.build.SrcRoot == "" { 319 // Package not found. Put in first directory of $GOPATH. 320 list := filepath.SplitList(buildContext.GOPATH) 321 if len(list) == 0 { 322 return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath") 323 } 324 // Guard against people setting GOPATH=$GOROOT. 325 if list[0] == goroot { 326 return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath") 327 } 328 p.build.SrcRoot = filepath.Join(list[0], "src") 329 p.build.PkgRoot = filepath.Join(list[0], "pkg") 330 } 331 root := filepath.Join(p.build.SrcRoot, rootPath) 332 // If we've considered this repository already, don't do it again. 333 if downloadRootCache[root] { 334 return nil 335 } 336 downloadRootCache[root] = true 337 338 if buildV { 339 fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath) 340 } 341 342 // Check that this is an appropriate place for the repo to be checked out. 343 // The target directory must either not exist or have a repo checked out already. 344 meta := filepath.Join(root, "."+vcs.cmd) 345 st, err := os.Stat(meta) 346 if err == nil && !st.IsDir() { 347 return fmt.Errorf("%s exists but is not a directory", meta) 348 } 349 if err != nil { 350 // Metadata directory does not exist. Prepare to checkout new copy. 351 // Some version control tools require the target directory not to exist. 352 // We require that too, just to avoid stepping on existing work. 353 if _, err := os.Stat(root); err == nil { 354 return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta) 355 } 356 // Some version control tools require the parent of the target to exist. 357 parent, _ := filepath.Split(root) 358 if err = os.MkdirAll(parent, 0777); err != nil { 359 return err 360 } 361 if err = vcs.create(root, repo); err != nil { 362 return err 363 } 364 } else { 365 // Metadata directory does exist; download incremental updates. 366 if err = vcs.download(root); err != nil { 367 return err 368 } 369 } 370 371 if buildN { 372 // Do not show tag sync in -n; it's noise more than anything, 373 // and since we're not running commands, no tag will be found. 374 // But avoid printing nothing. 375 fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd) 376 return nil 377 } 378 379 // Select and sync to appropriate version of the repository. 380 tags, err := vcs.tags(root) 381 if err != nil { 382 return err 383 } 384 vers := runtime.Version() 385 if i := strings.Index(vers, " "); i >= 0 { 386 vers = vers[:i] 387 } 388 if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil { 389 return err 390 } 391 392 return nil 393 } 394 395 // goTag matches go release tags such as go1 and go1.2.3. 396 // The numbers involved must be small (at most 4 digits), 397 // have no unnecessary leading zeros, and the version cannot 398 // end in .0 - it is go1, not go1.0 or go1.0.0. 399 var goTag = regexp.MustCompile( 400 `^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`, 401 ) 402 403 // selectTag returns the closest matching tag for a given version. 404 // Closest means the latest one that is not after the current release. 405 // Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form. 406 // Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number). 407 // Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD". 408 // 409 // NOTE(rsc): Eventually we will need to decide on some logic here. 410 // For now, there is only "go1". This matches the docs in go help get. 411 func selectTag(goVersion string, tags []string) (match string) { 412 for _, t := range tags { 413 if t == "go1" { 414 return "go1" 415 } 416 } 417 return "" 418 419 /* 420 if goTag.MatchString(goVersion) { 421 v := goVersion 422 for _, t := range tags { 423 if !goTag.MatchString(t) { 424 continue 425 } 426 if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 { 427 match = t 428 } 429 } 430 } 431 432 return match 433 */ 434 } 435 436 // cmpGoVersion returns -1, 0, +1 reporting whether 437 // x < y, x == y, or x > y. 438 func cmpGoVersion(x, y string) int { 439 // Malformed strings compare less than well-formed strings. 440 if !goTag.MatchString(x) { 441 return -1 442 } 443 if !goTag.MatchString(y) { 444 return +1 445 } 446 447 // Compare numbers in sequence. 448 xx := strings.Split(x[len("go"):], ".") 449 yy := strings.Split(y[len("go"):], ".") 450 451 for i := 0; i < len(xx) && i < len(yy); i++ { 452 // The Atoi are guaranteed to succeed 453 // because the versions match goTag. 454 xi, _ := strconv.Atoi(xx[i]) 455 yi, _ := strconv.Atoi(yy[i]) 456 if xi < yi { 457 return -1 458 } else if xi > yi { 459 return +1 460 } 461 } 462 463 if len(xx) < len(yy) { 464 return -1 465 } 466 if len(xx) > len(yy) { 467 return +1 468 } 469 return 0 470 }