github.com/n0needt0/glide@v0.0.0-20160325160517-844a77136d85/glide.go (about) 1 // Glide is a command line utility that manages Go project dependencies and 2 // your GOPATH. 3 // 4 // Dependencies are managed via a glide.yaml in the root of a project. The yaml 5 // 6 // Params: 7 // - filename (string): The name of the glide YAML file. Default is glide.yaml. 8 // - project (string): The name of the project. Default is 'main'. 9 // file lets you specify projects, versions (tags, branches, or references), 10 // and even alias one location in as other one. Aliasing is useful when supporting 11 // forks without needing to rewrite the imports in a codebase. 12 // 13 // A glide.yaml file looks like: 14 // 15 // package: github.com/Masterminds/glide 16 // imports: 17 // - package: github.com/Masterminds/cookoo 18 // vcs: git 19 // ref: 1.1.0 20 // subpackages: ** 21 // - package: github.com/kylelemons/go-gypsy 22 // subpackages: yaml 23 // 24 // Glide puts dependencies in a vendor directory. Go utilities require this to 25 // be in your GOPATH. Glide makes this easy. Use the `glide in` command to enter 26 // a shell (your default) with the GOPATH set to the projects vendor directory. 27 // To leave this shell simply exit it. 28 // 29 // If your .bashrc, .zshrc, or other startup shell sets your GOPATH you many need 30 // to optionally set it using something like: 31 // 32 // if [ "" = "${GOPATH}" ]; then 33 // export GOPATH="/some/dir" 34 // fi 35 // 36 // For more information use the `glide help` command or see https://github.com/Masterminds/glide 37 package main 38 39 import ( 40 "path/filepath" 41 42 "github.com/Masterminds/glide/action" 43 "github.com/Masterminds/glide/msg" 44 gpath "github.com/Masterminds/glide/path" 45 "github.com/Masterminds/glide/repo" 46 "github.com/Masterminds/glide/util" 47 48 "github.com/codegangsta/cli" 49 50 "fmt" 51 "os" 52 "os/user" 53 ) 54 55 var version = "0.11.0-dev" 56 57 const usage = `The lightweight vendor package manager for your Go projects. 58 59 Each project should have a 'glide.yaml' file in the project directory. Files 60 look something like this: 61 62 package: github.com/Masterminds/glide 63 imports: 64 - package: github.com/Masterminds/cookoo 65 vcs: git 66 ref: 1.1.0 67 subpackages: ** 68 - package: github.com/kylelemons/go-gypsy 69 subpackages: yaml 70 flatten: true 71 72 NOTE: As of Glide 0.5, the commands 'into', 'gopath', 'status', and 'env' 73 no longer exist. 74 ` 75 76 // VendorDir default vendor directory name 77 var VendorDir = "vendor" 78 79 func main() { 80 app := cli.NewApp() 81 app.Name = "glide" 82 app.Usage = usage 83 app.Version = version 84 app.Flags = []cli.Flag{ 85 cli.StringFlag{ 86 Name: "yaml, y", 87 Value: "glide.yaml", 88 Usage: "Set a YAML configuration file.", 89 }, 90 cli.BoolFlag{ 91 Name: "quiet, q", 92 Usage: "Quiet (no info or debug messages)", 93 }, 94 cli.BoolFlag{ 95 Name: "debug", 96 Usage: "Print Debug messages (verbose)", 97 }, 98 cli.StringFlag{ 99 Name: "home", 100 Value: defaultGlideDir(), 101 Usage: "The location of Glide files", 102 EnvVar: "GLIDE_HOME", 103 }, 104 cli.BoolFlag{ 105 Name: "no-color", 106 Usage: "Turn off colored output for log messages", 107 }, 108 } 109 app.CommandNotFound = func(c *cli.Context, command string) { 110 // TODO: Set some useful env vars. 111 action.Plugin(command, os.Args) 112 } 113 app.Before = startup 114 app.Commands = commands() 115 116 // Detect errors from the Before and After calls and exit on them. 117 if err := app.Run(os.Args); err != nil { 118 msg.Err(err.Error()) 119 os.Exit(1) 120 } 121 122 // If there was a Error message exit non-zero. 123 if msg.HasErrored() { 124 m := msg.Color(msg.Red, "An Error has occurred") 125 msg.Msg(m) 126 os.Exit(2) 127 } 128 } 129 130 func commands() []cli.Command { 131 return []cli.Command{ 132 { 133 Name: "create", 134 ShortName: "init", 135 Usage: "Initialize a new project, creating a glide.yaml file", 136 Description: `This command starts from a project without Glide and 137 sets it up. It generates a glide.yaml file, parsing your codebase to guess 138 the dependencies to include. Once this step is done you may edit the 139 glide.yaml file to update imported dependency properties such as the version 140 or version range to include. 141 142 To fetch the dependencies you may run 'glide install'.`, 143 Flags: []cli.Flag{ 144 cli.BoolFlag{ 145 Name: "skip-import", 146 Usage: "When initializing skip importing from other package managers.", 147 }, 148 }, 149 Action: func(c *cli.Context) { 150 action.Create(".", c.Bool("skip-import")) 151 }, 152 }, 153 { 154 Name: "get", 155 Usage: "Install one or more packages into `vendor/` and add dependency to glide.yaml.", 156 Description: `Gets one or more package (like 'go get') and then adds that file 157 to the glide.yaml file. Multiple package names can be specified on one line. 158 159 $ glide get github.com/Masterminds/cookoo/web 160 161 The above will install the project github.com/Masterminds/cookoo and add 162 the subpackage 'web'. 163 164 If a fetched dependency has a glide.yaml file, configuration from Godep, 165 GPM, or GB Glide that configuration will be used to find the dependencies 166 and versions to fetch. If those are not available the dependent packages will 167 be fetched as either a version specified elsewhere or the latest version. 168 169 When adding a new dependency Glide will perform an update to work out the 170 the versions to use from the dependency tree. This will generate an updated 171 glide.lock file with specific locked versions to use. 172 173 If you are storing the outside dependencies in your version control system 174 (VCS), also known as vendoring, there are a few flags that may be useful. 175 The '--update-vendored' flag will cause Glide to update packages when VCS 176 information is unavailable. This can be used with the '--strip-vcs' flag which 177 will strip VCS data found in the vendor directory. This is useful for 178 removing VCS data from transitive dependencies and initial setups. The 179 '--strip-vendor' flag will remove any nested 'vendor' folders and 180 'Godeps/_workspace' folders after an update (along with undoing any Godep 181 import rewriting). Note, The Godeps specific functionality is deprecated and 182 will be removed when most Godeps users have migrated to using the vendor 183 folder.`, 184 Flags: []cli.Flag{ 185 cli.BoolFlag{ 186 Name: "insecure", 187 Usage: "Use http:// rather than https:// to retrieve pacakges.", 188 }, 189 cli.BoolFlag{ 190 Name: "no-recursive, quick", 191 Usage: "Disable updating dependencies' dependencies.", 192 }, 193 cli.BoolFlag{ 194 Name: "force", 195 Usage: "If there was a change in the repo or VCS switch to new one. Warning, changes will be lost.", 196 }, 197 cli.BoolFlag{ 198 Name: "all-dependencies", 199 Usage: "This will resolve all dependencies for all packages, not just those directly used.", 200 }, 201 cli.BoolFlag{ 202 Name: "update-vendored, u", 203 Usage: "Update vendored packages (without local VCS repo). Warning, changes will be lost.", 204 }, 205 cli.BoolFlag{ 206 Name: "cache", 207 Usage: "When downloading dependencies attempt to cache them.", 208 }, 209 cli.BoolFlag{ 210 Name: "cache-gopath", 211 Usage: "When downloading dependencies attempt to put them in the GOPATH, too.", 212 }, 213 cli.BoolFlag{ 214 Name: "use-gopath", 215 Usage: "Copy dependencies from the GOPATH if they exist there.", 216 }, 217 cli.BoolFlag{ 218 Name: "resolve-current", 219 Usage: "Resolve dependencies for only the current system rather than all build modes.", 220 }, 221 cli.BoolFlag{ 222 Name: "strip-vcs, s", 223 Usage: "Removes version control metada (e.g, .git directory) from the vendor folder.", 224 }, 225 cli.BoolFlag{ 226 Name: "strip-vendor, v", 227 Usage: "Removes nested vendor and Godeps/_workspace directories. Requires --strip-vcs.", 228 }, 229 }, 230 Action: func(c *cli.Context) { 231 if c.Bool("strip-vendor") && !c.Bool("strip-vcs") { 232 msg.Die("--strip-vendor cannot be used without --strip-vcs") 233 } 234 235 if len(c.Args()) < 1 { 236 fmt.Println("Oops! Package name is required.") 237 os.Exit(1) 238 } 239 240 if c.Bool("resolve-current") { 241 util.ResolveCurrent = true 242 msg.Warn("Only resolving dependencies for the current OS/Arch") 243 } 244 245 inst := repo.NewInstaller() 246 inst.Force = c.Bool("force") 247 inst.UseCache = c.Bool("cache") 248 inst.UseGopath = c.Bool("use-gopath") 249 inst.UseCacheGopath = c.Bool("cache-gopath") 250 inst.UpdateVendored = c.Bool("update-vendored") 251 inst.ResolveAllFiles = c.Bool("all-dependencies") 252 packages := []string(c.Args()) 253 insecure := c.Bool("insecure") 254 action.Get(packages, inst, insecure, c.Bool("no-recursive"), c.Bool("strip-vcs"), c.Bool("strip-vendor")) 255 }, 256 }, 257 { 258 Name: "remove", 259 ShortName: "rm", 260 Usage: "Remove a package from the glide.yaml file, and regenerate the lock file.", 261 Description: `This takes one or more package names, and removes references from the glide.yaml file. 262 This will rebuild the glide lock file with the following constraints: 263 264 - Dependencies are re-negotiated. Any that are no longer used are left out of the lock. 265 - Minor version re-nogotiation is performed on remaining dependencies. 266 - No updates are peformed. You may want to run 'glide up' to accomplish that. 267 `, 268 Flags: []cli.Flag{ 269 cli.BoolFlag{ 270 Name: "delete,d", 271 Usage: "Also delete from vendor/ any packages that are no longer used.", 272 }, 273 }, 274 Action: func(c *cli.Context) { 275 if len(c.Args()) < 1 { 276 fmt.Println("Oops! At least one package name is required.") 277 os.Exit(1) 278 } 279 280 if c.Bool("delete") { 281 // FIXME: Implement this in the installer. 282 fmt.Println("Delete is not currently implemented.") 283 } 284 inst := repo.NewInstaller() 285 inst.Force = c.Bool("force") 286 packages := []string(c.Args()) 287 action.Remove(packages, inst) 288 }, 289 }, 290 { 291 Name: "import", 292 Usage: "Import files from other dependency management systems.", 293 Subcommands: []cli.Command{ 294 { 295 Name: "godep", 296 Usage: "Import Godep's Godeps.json files and display the would-be yaml file", 297 Flags: []cli.Flag{ 298 cli.StringFlag{ 299 Name: "file, f", 300 Usage: "Save all of the discovered dependencies to a Glide YAML file.", 301 }, 302 }, 303 Action: func(c *cli.Context) { 304 action.ImportGodep(c.String("file")) 305 }, 306 }, 307 { 308 Name: "gpm", 309 Usage: "Import GPM's Godeps and Godeps-Git files and display the would-be yaml file", 310 Flags: []cli.Flag{ 311 cli.StringFlag{ 312 Name: "file, f", 313 Usage: "Save all of the discovered dependencies to a Glide YAML file.", 314 }, 315 }, 316 Action: func(c *cli.Context) { 317 action.ImportGPM(c.String("file")) 318 }, 319 }, 320 { 321 Name: "gb", 322 Usage: "Import gb's manifest file and display the would-be yaml file", 323 Flags: []cli.Flag{ 324 cli.StringFlag{ 325 Name: "file, f", 326 Usage: "Save all of the discovered dependencies to a Glide YAML file.", 327 }, 328 }, 329 Action: func(c *cli.Context) { 330 action.ImportGB(c.String("file")) 331 }, 332 }, 333 { 334 Name: "gom", 335 Usage: "Import Gomfile and display the would-be yaml file", 336 Flags: []cli.Flag{ 337 cli.StringFlag{ 338 Name: "file, f", 339 Usage: "Save all of the discovered dependencies to a Glide YAML file.", 340 }, 341 }, 342 Action: func(c *cli.Context) { 343 action.ImportGom(c.String("file")) 344 }, 345 }, 346 }, 347 }, 348 { 349 Name: "name", 350 Usage: "Print the name of this project.", 351 Description: `Read the glide.yaml file and print the name given on the 'package' line.`, 352 Action: func(c *cli.Context) { 353 action.Name() 354 }, 355 }, 356 { 357 Name: "novendor", 358 ShortName: "nv", 359 Usage: "List all non-vendor paths in a directory.", 360 Description: `Given a directory, list all the relevant Go paths that are not vendored. 361 362 Example: 363 364 $ go test $(glide novendor) 365 `, 366 Flags: []cli.Flag{ 367 cli.StringFlag{ 368 Name: "dir,d", 369 Usage: "Specify a directory to run novendor against.", 370 Value: ".", 371 }, 372 cli.BoolFlag{ 373 Name: "no-subdir,x", 374 Usage: "Specify this to prevent nv from append '/...' to all directories.", 375 }, 376 }, 377 Action: func(c *cli.Context) { 378 action.NoVendor(c.String("dir"), true, !c.Bool("no-subdir")) 379 }, 380 }, 381 { 382 Name: "rebuild", 383 Usage: "Rebuild ('go build') the dependencies", 384 Description: `This rebuilds the packages' '.a' files. On some systems 385 this can improve performance on subsequent 'go run' and 'go build' calls.`, 386 Action: func(c *cli.Context) { 387 action.Rebuild() 388 }, 389 }, 390 { 391 Name: "install", 392 ShortName: "i", 393 Usage: "Install a project's dependencies", 394 Description: `This uses the native VCS of each packages to install 395 the appropriate version. There are two ways a projects dependencies can 396 be installed. When there is a glide.yaml file defining the dependencies but 397 no lock file (glide.lock) the dependencies are installed using the "update" 398 command and a glide.lock file is generated pinning all dependencies. If a 399 glide.lock file is already present the dependencies are installed or updated 400 from the lock file.`, 401 Flags: []cli.Flag{ 402 cli.BoolFlag{ 403 Name: "delete", 404 Usage: "Delete vendor packages not specified in config.", 405 }, 406 cli.BoolFlag{ 407 Name: "force", 408 Usage: "If there was a change in the repo or VCS switch to new one. Warning: changes will be lost.", 409 }, 410 cli.BoolFlag{ 411 Name: "update-vendored, u", 412 Usage: "Update vendored packages (without local VCS repo). Warning: this may destroy local modifications to vendor/.", 413 }, 414 cli.StringFlag{ 415 Name: "file, f", 416 Usage: "Save all of the discovered dependencies to a Glide YAML file. (DEPRECATED: This has no impact.)", 417 }, 418 cli.BoolFlag{ 419 Name: "cache", 420 Usage: "When downloading dependencies attempt to cache them.", 421 }, 422 cli.BoolFlag{ 423 Name: "cache-gopath", 424 Usage: "When downloading dependencies attempt to put them in the GOPATH, too.", 425 }, 426 cli.BoolFlag{ 427 Name: "use-gopath", 428 Usage: "Copy dependencies from the GOPATH if they exist there.", 429 }, 430 cli.BoolFlag{ 431 Name: "strip-vcs, s", 432 Usage: "Removes version control metada (e.g, .git directory) from the vendor folder.", 433 }, 434 cli.BoolFlag{ 435 Name: "strip-vendor, v", 436 Usage: "Removes nested vendor and Godeps/_workspace directories. Requires --strip-vcs.", 437 }, 438 }, 439 Action: func(c *cli.Context) { 440 if c.Bool("strip-vendor") && !c.Bool("strip-vcs") { 441 msg.Die("--strip-vendor cannot be used without --strip-vcs") 442 } 443 444 installer := repo.NewInstaller() 445 installer.Force = c.Bool("force") 446 installer.UseCache = c.Bool("cache") 447 installer.UseGopath = c.Bool("use-gopath") 448 installer.UseCacheGopath = c.Bool("cache-gopath") 449 installer.UpdateVendored = c.Bool("update-vendored") 450 installer.Home = gpath.Home() 451 installer.DeleteUnused = c.Bool("deleteOptIn") 452 453 action.Install(installer, c.Bool("strip-vcs"), c.Bool("strip-vendor")) 454 }, 455 }, 456 { 457 Name: "update", 458 ShortName: "up", 459 Usage: "Update a project's dependencies", 460 Description: `This uses the native VCS of each package to try to 461 pull the most applicable updates. Packages with fixed refs (Versions or 462 tags) will not be updated. Packages with no ref or with a branch ref will 463 be updated as expected. 464 465 If a dependency has a glide.yaml file, update will read that file and 466 update those dependencies accordingly. Those dependencies are maintained in 467 a the top level 'vendor/' directory. 'vendor/foo/bar' will have its 468 dependencies stored in 'vendor/'. This behavior can be disabled with 469 '--no-recursive'. When this behavior is skipped a glide.lock file is not 470 generated because the full dependency tree cannot be known. 471 472 Glide will also import Godep, GB, and GPM files as it finds them in dependencies. 473 It will create a glide.yaml file from the Godeps data, and then update. This 474 has no effect if '--no-recursive' is set. 475 476 If you are storing the outside dependencies in your version control system 477 (VCS), also known as vendoring, there are a few flags that may be useful. 478 The '--update-vendored' flag will cause Glide to update packages when VCS 479 information is unavailable. This can be used with the '--strip-vcs' flag which 480 will strip VCS data found in the vendor directory. This is useful for 481 removing VCS data from transitive dependencies and initial setups. The 482 '--strip-vendor' flag will remove any nested 'vendor' folders and 483 'Godeps/_workspace' folders after an update (along with undoing any Godep 484 import rewriting). Note, The Godeps specific functionality is deprecated and 485 will be removed when most Godeps users have migrated to using the vendor 486 folder. 487 488 By default, packages that are discovered are considered transient, and are 489 not stored in the glide.yaml file. The --file=NAME.yaml flag allows you 490 to save the discovered dependencies to a YAML file. 491 `, 492 Flags: []cli.Flag{ 493 cli.BoolFlag{ 494 Name: "delete", 495 Usage: "Delete vendor packages not specified in config.", 496 }, 497 cli.BoolFlag{ 498 Name: "no-recursive, quick", 499 Usage: "Disable updating dependencies' dependencies. Only update things in glide.yaml.", 500 }, 501 cli.BoolFlag{ 502 Name: "force", 503 Usage: "If there was a change in the repo or VCS switch to new one. Warning, changes will be lost.", 504 }, 505 cli.BoolFlag{ 506 Name: "all-dependencies", 507 Usage: "This will resolve all dependencies for all packages, not just those directly used.", 508 }, 509 cli.BoolFlag{ 510 Name: "update-vendored, u", 511 Usage: "Update vendored packages (without local VCS repo). Warning, changes will be lost.", 512 }, 513 cli.StringFlag{ 514 Name: "file, f", 515 Usage: "Save all of the discovered dependencies to a Glide YAML file.", 516 }, 517 cli.BoolFlag{ 518 Name: "cache", 519 Usage: "When downloading dependencies attempt to cache them.", 520 }, 521 cli.BoolFlag{ 522 Name: "cache-gopath", 523 Usage: "When downloading dependencies attempt to put them in the GOPATH, too.", 524 }, 525 cli.BoolFlag{ 526 Name: "use-gopath", 527 Usage: "Copy dependencies from the GOPATH if they exist there.", 528 }, 529 cli.BoolFlag{ 530 Name: "resolve-current", 531 Usage: "Resolve dependencies for only the current system rather than all build modes.", 532 }, 533 cli.BoolFlag{ 534 Name: "strip-vcs, s", 535 Usage: "Removes version control metada (e.g, .git directory) from the vendor folder.", 536 }, 537 cli.BoolFlag{ 538 Name: "strip-vendor, v", 539 Usage: "Removes nested vendor and Godeps/_workspace directories. Requires --strip-vcs.", 540 }, 541 }, 542 Action: func(c *cli.Context) { 543 if c.Bool("strip-vendor") && !c.Bool("strip-vcs") { 544 msg.Die("--strip-vendor cannot be used without --strip-vcs") 545 } 546 547 if c.Bool("resolve-current") { 548 util.ResolveCurrent = true 549 msg.Warn("Only resolving dependencies for the current OS/Arch") 550 } 551 552 installer := repo.NewInstaller() 553 installer.Force = c.Bool("force") 554 installer.UseCache = c.Bool("cache") 555 installer.UseGopath = c.Bool("use-gopath") 556 installer.UseCacheGopath = c.Bool("cache-gopath") 557 installer.UpdateVendored = c.Bool("update-vendored") 558 installer.ResolveAllFiles = c.Bool("all-dependencies") 559 installer.Home = gpath.Home() 560 installer.DeleteUnused = c.Bool("deleteOptIn") 561 562 action.Update(installer, c.Bool("no-recursive"), c.Bool("strip-vcs"), c.Bool("strip-vendor")) 563 }, 564 }, 565 { 566 Name: "tree", 567 Usage: "Tree prints the dependencies of this project as a tree.", 568 Description: `This scans a project's source files and builds a tree 569 representation of the import graph. 570 571 It ignores testdata/ and directories that begin with . or _. Packages in 572 vendor/ are only included if they are referenced by the main project or 573 one of its dependencies.`, 574 Action: func(c *cli.Context) { 575 action.Tree(".", false) 576 }, 577 }, 578 { 579 Name: "list", 580 Usage: "List prints all dependencies that the present code references.", 581 Description: `List scans your code and lists all of the packages that are used. 582 583 It does not use the glide.yaml. Instead, it inspects the code to determine what packages are 584 imported. 585 586 Directories that begin with . or _ are ignored, as are testdata directories. Packages in 587 vendor are only included if they are used by the project. 588 `, 589 Action: func(c *cli.Context) { 590 action.List(".", true) 591 }, 592 }, 593 { 594 Name: "about", 595 Usage: "Learn about Glide", 596 Action: func(c *cli.Context) { 597 action.About() 598 }, 599 }, 600 } 601 } 602 603 func defaultGlideDir() string { 604 c, err := user.Current() 605 if err != nil { 606 return "" 607 } 608 return filepath.Join(c.HomeDir, ".glide") 609 } 610 611 // startup sets up the base environment. 612 // 613 // It does not assume the presence of a Glide.yaml file or vendor/ directory, 614 // so it can be used by any Glide command. 615 func startup(c *cli.Context) error { 616 action.Debug(c.Bool("debug")) 617 action.NoColor(c.Bool("no-color")) 618 action.Quiet(c.Bool("quiet")) 619 action.Init(c.String("yaml"), c.String("home")) 620 action.EnsureGoVendor() 621 return nil 622 } 623 624 // Get the path to the glide.yaml file. 625 // 626 // This returns the name of the path, even if the file does not exist. The value 627 // may be set by the user, or it may be the default. 628 func glidefile(c *cli.Context) string { 629 path := c.String("file") 630 if path == "" { 631 // For now, we construct a basic assumption. In the future, we could 632 // traverse backward to see if a glide.yaml exists in a parent. 633 path = "./glide.yaml" 634 } 635 a, err := filepath.Abs(path) 636 if err != nil { 637 // Underlying fs didn't provide working dir. 638 return path 639 } 640 return a 641 }