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