github.com/goguardian/glide@v0.0.0-20160311175917-84255172e124/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 = "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 Flags: []cli.Flag{ 174 cli.BoolFlag{ 175 Name: "insecure", 176 Usage: "Use http:// rather than https:// to retrieve pacakges.", 177 }, 178 cli.BoolFlag{ 179 Name: "no-recursive, quick", 180 Usage: "Disable updating dependencies' dependencies.", 181 }, 182 cli.BoolFlag{ 183 Name: "force", 184 Usage: "If there was a change in the repo or VCS switch to new one. Warning, changes will be lost.", 185 }, 186 cli.BoolFlag{ 187 Name: "all-dependencies", 188 Usage: "This will resolve all dependencies for all packages, not just those directly used.", 189 }, 190 cli.BoolFlag{ 191 Name: "update-vendored, u", 192 Usage: "Update vendored packages (without local VCS repo). Warning, changes will be lost.", 193 }, 194 cli.BoolFlag{ 195 Name: "cache", 196 Usage: "When downloading dependencies attempt to cache them.", 197 }, 198 cli.BoolFlag{ 199 Name: "cache-gopath", 200 Usage: "When downloading dependencies attempt to put them in the GOPATH, too.", 201 }, 202 cli.BoolFlag{ 203 Name: "use-gopath", 204 Usage: "Copy dependencies from the GOPATH if they exist there.", 205 }, 206 cli.BoolFlag{ 207 Name: "resolve-current", 208 Usage: "Resolve dependencies for only the current system rather than all build modes.", 209 }, 210 }, 211 Action: func(c *cli.Context) { 212 if len(c.Args()) < 1 { 213 fmt.Println("Oops! Package name is required.") 214 os.Exit(1) 215 } 216 217 if c.Bool("resolve-current") { 218 util.ResolveCurrent = true 219 msg.Warn("Only resolving dependencies for the current OS/Arch") 220 } 221 222 inst := repo.NewInstaller() 223 inst.Force = c.Bool("force") 224 inst.UseCache = c.Bool("cache") 225 inst.UseGopath = c.Bool("use-gopath") 226 inst.UseCacheGopath = c.Bool("cache-gopath") 227 inst.UpdateVendored = c.Bool("update-vendored") 228 inst.ResolveAllFiles = c.Bool("all-dependencies") 229 packages := []string(c.Args()) 230 insecure := c.Bool("insecure") 231 action.Get(packages, inst, insecure, c.Bool("no-recursive")) 232 }, 233 }, 234 { 235 Name: "remove", 236 ShortName: "rm", 237 Usage: "Remove a package from the glide.yaml file, and regenerate the lock file.", 238 Description: `This takes one or more package names, and removes references from the glide.yaml file. 239 This will rebuild the glide lock file with the following constraints: 240 241 - Dependencies are re-negotiated. Any that are no longer used are left out of the lock. 242 - Minor version re-nogotiation is performed on remaining dependencies. 243 - No updates are peformed. You may want to run 'glide up' to accomplish that. 244 `, 245 Flags: []cli.Flag{ 246 cli.BoolFlag{ 247 Name: "delete,d", 248 Usage: "Also delete from vendor/ any packages that are no longer used.", 249 }, 250 }, 251 Action: func(c *cli.Context) { 252 if len(c.Args()) < 1 { 253 fmt.Println("Oops! At least one package name is required.") 254 os.Exit(1) 255 } 256 257 if c.Bool("delete") { 258 // FIXME: Implement this in the installer. 259 fmt.Println("Delete is not currently implemented.") 260 } 261 inst := repo.NewInstaller() 262 inst.Force = c.Bool("force") 263 packages := []string(c.Args()) 264 action.Remove(packages, inst) 265 }, 266 }, 267 { 268 Name: "import", 269 Usage: "Import files from other dependency management systems.", 270 Subcommands: []cli.Command{ 271 { 272 Name: "godep", 273 Usage: "Import Godep's Godeps.json files and display the would-be yaml file", 274 Flags: []cli.Flag{ 275 cli.StringFlag{ 276 Name: "file, f", 277 Usage: "Save all of the discovered dependencies to a Glide YAML file.", 278 }, 279 }, 280 Action: func(c *cli.Context) { 281 action.ImportGodep(c.String("file")) 282 }, 283 }, 284 { 285 Name: "gpm", 286 Usage: "Import GPM's Godeps and Godeps-Git files and display the would-be yaml file", 287 Flags: []cli.Flag{ 288 cli.StringFlag{ 289 Name: "file, f", 290 Usage: "Save all of the discovered dependencies to a Glide YAML file.", 291 }, 292 }, 293 Action: func(c *cli.Context) { 294 action.ImportGPM(c.String("file")) 295 }, 296 }, 297 { 298 Name: "gb", 299 Usage: "Import gb's manifest file and display the would-be yaml file", 300 Flags: []cli.Flag{ 301 cli.StringFlag{ 302 Name: "file, f", 303 Usage: "Save all of the discovered dependencies to a Glide YAML file.", 304 }, 305 }, 306 Action: func(c *cli.Context) { 307 action.ImportGB(c.String("file")) 308 }, 309 }, 310 { 311 Name: "gom", 312 Usage: "Import Gomfile and display the would-be yaml file", 313 Flags: []cli.Flag{ 314 cli.StringFlag{ 315 Name: "file, f", 316 Usage: "Save all of the discovered dependencies to a Glide YAML file.", 317 }, 318 }, 319 Action: func(c *cli.Context) { 320 action.ImportGom(c.String("file")) 321 }, 322 }, 323 }, 324 }, 325 { 326 Name: "name", 327 Usage: "Print the name of this project.", 328 Description: `Read the glide.yaml file and print the name given on the 'package' line.`, 329 Action: func(c *cli.Context) { 330 action.Name() 331 }, 332 }, 333 { 334 Name: "novendor", 335 ShortName: "nv", 336 Usage: "List all non-vendor paths in a directory.", 337 Description: `Given a directory, list all the relevant Go paths that are not vendored. 338 339 Example: 340 341 $ go test $(glide novendor) 342 `, 343 Flags: []cli.Flag{ 344 cli.StringFlag{ 345 Name: "dir,d", 346 Usage: "Specify a directory to run novendor against.", 347 Value: ".", 348 }, 349 cli.BoolFlag{ 350 Name: "no-subdir,x", 351 Usage: "Specify this to prevent nv from append '/...' to all directories.", 352 }, 353 }, 354 Action: func(c *cli.Context) { 355 action.NoVendor(c.String("dir"), true, !c.Bool("no-subdir")) 356 }, 357 }, 358 { 359 Name: "rebuild", 360 Usage: "Rebuild ('go build') the dependencies", 361 Description: `This rebuilds the packages' '.a' files. On some systems 362 this can improve performance on subsequent 'go run' and 'go build' calls.`, 363 Action: func(c *cli.Context) { 364 action.Rebuild() 365 }, 366 }, 367 { 368 Name: "install", 369 ShortName: "i", 370 Usage: "Install a project's dependencies", 371 Description: `This uses the native VCS of each packages to install 372 the appropriate version. There are two ways a projects dependencies can 373 be installed. When there is a glide.yaml file defining the dependencies but 374 no lock file (glide.lock) the dependencies are installed using the "update" 375 command and a glide.lock file is generated pinning all dependencies. If a 376 glide.lock file is already present the dependencies are installed or updated 377 from the lock file.`, 378 Flags: []cli.Flag{ 379 cli.BoolFlag{ 380 Name: "delete", 381 Usage: "Delete vendor packages not specified in config.", 382 }, 383 cli.BoolFlag{ 384 Name: "force", 385 Usage: "If there was a change in the repo or VCS switch to new one. Warning: changes will be lost.", 386 }, 387 cli.BoolFlag{ 388 Name: "update-vendored, u", 389 Usage: "Update vendored packages (without local VCS repo). Warning: this may destroy local modifications to vendor/.", 390 }, 391 cli.StringFlag{ 392 Name: "file, f", 393 Usage: "Save all of the discovered dependencies to a Glide YAML file. (DEPRECATED: This has no impact.)", 394 }, 395 cli.BoolFlag{ 396 Name: "cache", 397 Usage: "When downloading dependencies attempt to cache them.", 398 }, 399 cli.BoolFlag{ 400 Name: "cache-gopath", 401 Usage: "When downloading dependencies attempt to put them in the GOPATH, too.", 402 }, 403 cli.BoolFlag{ 404 Name: "use-gopath", 405 Usage: "Copy dependencies from the GOPATH if they exist there.", 406 }, 407 }, 408 Action: func(c *cli.Context) { 409 installer := repo.NewInstaller() 410 installer.Force = c.Bool("force") 411 installer.UseCache = c.Bool("cache") 412 installer.UseGopath = c.Bool("use-gopath") 413 installer.UseCacheGopath = c.Bool("cache-gopath") 414 installer.UpdateVendored = c.Bool("update-vendored") 415 installer.Home = gpath.Home() 416 installer.DeleteUnused = c.Bool("deleteOptIn") 417 418 action.Install(installer) 419 }, 420 }, 421 { 422 Name: "update", 423 ShortName: "up", 424 Usage: "Update a project's dependencies", 425 Description: `This uses the native VCS of each package to try to 426 pull the most applicable updates. Packages with fixed refs (Versions or 427 tags) will not be updated. Packages with no ref or with a branch ref will 428 be updated as expected. 429 430 If a dependency has a glide.yaml file, update will read that file and 431 update those dependencies accordingly. Those dependencies are maintained in 432 a the top level 'vendor/' directory. 'vendor/foo/bar' will have its 433 dependencies stored in 'vendor/'. This behavior can be disabled with 434 '--no-recursive'. When this behavior is skipped a glide.lock file is not 435 generated because the full dependency tree cannot be known. 436 437 Glide will also import Godep, GB, and GPM files as it finds them in dependencies. 438 It will create a glide.yaml file from the Godeps data, and then update. This 439 has no effect if '--no-recursive' is set. 440 441 If the '--update-vendored' flag (aliased to '-u') is present vendored 442 dependencies, stored in your projects VCS repository, will be updated. This 443 works by removing the old package, checking out an the repo and setting the 444 version, and removing the VCS directory. 445 446 By default, packages that are discovered are considered transient, and are 447 not stored in the glide.yaml file. The --file=NAME.yaml flag allows you 448 to save the discovered dependencies to a YAML file. 449 `, 450 Flags: []cli.Flag{ 451 cli.BoolFlag{ 452 Name: "delete", 453 Usage: "Delete vendor packages not specified in config.", 454 }, 455 cli.BoolFlag{ 456 Name: "no-recursive, quick", 457 Usage: "Disable updating dependencies' dependencies. Only update things in glide.yaml.", 458 }, 459 cli.BoolFlag{ 460 Name: "force", 461 Usage: "If there was a change in the repo or VCS switch to new one. Warning, changes will be lost.", 462 }, 463 cli.BoolFlag{ 464 Name: "all-dependencies", 465 Usage: "This will resolve all dependencies for all packages, not just those directly used.", 466 }, 467 cli.BoolFlag{ 468 Name: "update-vendored, u", 469 Usage: "Update vendored packages (without local VCS repo). Warning, changes will be lost.", 470 }, 471 cli.StringFlag{ 472 Name: "file, f", 473 Usage: "Save all of the discovered dependencies to a Glide YAML file.", 474 }, 475 cli.BoolFlag{ 476 Name: "cache", 477 Usage: "When downloading dependencies attempt to cache them.", 478 }, 479 cli.BoolFlag{ 480 Name: "cache-gopath", 481 Usage: "When downloading dependencies attempt to put them in the GOPATH, too.", 482 }, 483 cli.BoolFlag{ 484 Name: "use-gopath", 485 Usage: "Copy dependencies from the GOPATH if they exist there.", 486 }, 487 cli.BoolFlag{ 488 Name: "resolve-current", 489 Usage: "Resolve dependencies for only the current system rather than all build modes.", 490 }, 491 }, 492 Action: func(c *cli.Context) { 493 494 if c.Bool("resolve-current") { 495 util.ResolveCurrent = true 496 msg.Warn("Only resolving dependencies for the current OS/Arch") 497 } 498 499 installer := repo.NewInstaller() 500 installer.Force = c.Bool("force") 501 installer.UseCache = c.Bool("cache") 502 installer.UseGopath = c.Bool("use-gopath") 503 installer.UseCacheGopath = c.Bool("cache-gopath") 504 installer.UpdateVendored = c.Bool("update-vendored") 505 installer.ResolveAllFiles = c.Bool("all-dependencies") 506 installer.Home = gpath.Home() 507 installer.DeleteUnused = c.Bool("deleteOptIn") 508 509 action.Update(installer, c.Bool("no-recursive")) 510 }, 511 }, 512 { 513 Name: "tree", 514 Usage: "Tree prints the dependencies of this project as a tree.", 515 Description: `This scans a project's source files and builds a tree 516 representation of the import graph. 517 518 It ignores testdata/ and directories that begin with . or _. Packages in 519 vendor/ are only included if they are referenced by the main project or 520 one of its dependencies.`, 521 Action: func(c *cli.Context) { 522 action.Tree(".", false) 523 }, 524 }, 525 { 526 Name: "list", 527 Usage: "List prints all dependencies that the present code references.", 528 Description: `List scans your code and lists all of the packages that are used. 529 530 It does not use the glide.yaml. Instead, it inspects the code to determine what packages are 531 imported. 532 533 Directories that begin with . or _ are ignored, as are testdata directories. Packages in 534 vendor are only included if they are used by the project. 535 `, 536 Action: func(c *cli.Context) { 537 action.List(".", true) 538 }, 539 }, 540 { 541 Name: "about", 542 Usage: "Learn about Glide", 543 Action: func(c *cli.Context) { 544 action.About() 545 }, 546 }, 547 } 548 } 549 550 func defaultGlideDir() string { 551 c, err := user.Current() 552 if err != nil { 553 return "" 554 } 555 return filepath.Join(c.HomeDir, ".glide") 556 } 557 558 // startup sets up the base environment. 559 // 560 // It does not assume the presence of a Glide.yaml file or vendor/ directory, 561 // so it can be used by any Glide command. 562 func startup(c *cli.Context) error { 563 action.Debug(c.Bool("debug")) 564 action.NoColor(c.Bool("no-color")) 565 action.Quiet(c.Bool("quiet")) 566 action.Init(c.String("yaml"), c.String("home")) 567 action.EnsureGoVendor() 568 return nil 569 } 570 571 // Get the path to the glide.yaml file. 572 // 573 // This returns the name of the path, even if the file does not exist. The value 574 // may be set by the user, or it may be the default. 575 func glidefile(c *cli.Context) string { 576 path := c.String("file") 577 if path == "" { 578 // For now, we construct a basic assumption. In the future, we could 579 // traverse backward to see if a glide.yaml exists in a parent. 580 path = "./glide.yaml" 581 } 582 a, err := filepath.Abs(path) 583 if err != nil { 584 // Underlying fs didn't provide working dir. 585 return path 586 } 587 return a 588 }