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