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