Merge branch 'albrow-feature/no-color' Conflicts: glide.go
diff --git a/.travis.yml b/.travis.yml index 4c85a20..b66cd48 100644 --- a/.travis.yml +++ b/.travis.yml
@@ -17,8 +17,7 @@ # in the vendor directory. We don't need to test all dependent packages. # Only testing this project. script: - - GO15VENDOREXPERIMENT=1 go test -v . - - GO15VENDOREXPERIMENT=1 go test -v ./cmd + - GO15VENDOREXPERIMENT=1 go test -v . ./cmd ./gb ./util ./yaml notifications: irc: "irc.freenode.net#masterminds"
diff --git a/README.md b/README.md index 5d97527..2d93340 100644 --- a/README.md +++ b/README.md
@@ -25,6 +25,7 @@ - hg - svn * Support custom local and global plugins (see docs/plugins.md) +* Repository caching including reuse of packages in the `$GOPATH` ## How It Works
diff --git a/cmd/cache.go b/cmd/cache.go new file mode 100644 index 0000000..0a976e5 --- /dev/null +++ b/cmd/cache.go
@@ -0,0 +1,101 @@ +package cmd + +import ( + "encoding/json" + "errors" + "io/ioutil" + "net/url" + "os" + "path/filepath" + "strings" + "time" + + "github.com/Masterminds/cookoo" +) + +// EnsureCacheDir Creates the $HOME/.glide/cache directory (unless home is +// specified to be different) if it does not exist. +func EnsureCacheDir(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { + home := p.Get("home", "").(string) + if home == "" { + return nil, errors.New("No home directory set to create") + } + err := os.MkdirAll(filepath.Join(home, "cache", "info"), os.ModeDir|os.ModePerm) + if err != nil { + Warn("Error creating Glide directory %s", home) + } + return false, nil +} + +// Pass in a repo location and get a cache key from it. +func cacheCreateKey(repo string) (string, error) { + + // A url needs a scheme. A git repo such as + // git@github.com:Masterminds/cookoo.git reworked to the url parser. + c := strings.Contains(repo, "://") + if !c { + repo = "ssh://" + repo + } + + u, err := url.Parse(repo) + if err != nil { + return "", err + } + + if !c { + u.Scheme = "" + } + + var key string + if u.Scheme != "" { + key = u.Scheme + "-" + } + if u.User != nil && u.User.Username() != "" { + key = key + u.User.Username() + "-" + } + key = key + u.Host + if u.Path != "" { + key = key + strings.Replace(u.Path, "/", "-", -1) + } + + key = strings.Replace(key, ":", "-", -1) + + return key, nil +} + +type cacheRepoInfo struct { + DefaultBranch string `json:"default-branch"` + LastUpdate string `json:"last-update"` +} + +func saveCacheRepoData(key string, data cacheRepoInfo, location string) error { + data.LastUpdate = time.Now().String() + d, err := json.Marshal(data) + if err != nil { + return err + } + + p := filepath.Join(location, "cache", "info", key+".json") + f, err := os.Create(p) + if err != nil { + return err + } + defer f.Close() + + _, err = f.Write(d) + return err +} + +func cacheRepoData(key, location string) (*cacheRepoInfo, error) { + c := &cacheRepoInfo{} + p := filepath.Join(location, "cache", "info", key+".json") + f, err := ioutil.ReadFile(p) + if err != nil { + return &cacheRepoInfo{}, err + } + err = json.Unmarshal(f, c) + if err != nil { + return &cacheRepoInfo{}, err + } + return c, nil +}
diff --git a/cmd/cache_test.go b/cmd/cache_test.go new file mode 100644 index 0000000..6104434 --- /dev/null +++ b/cmd/cache_test.go
@@ -0,0 +1,21 @@ +package cmd + +import "testing" + +func TestCacheCreateKey(t *testing.T) { + tests := map[string]string{ + "https://github.com/foo/bar": "https-github.com-foo-bar", + "git@github.com:foo/bar": "git-github.com-foo-bar", + } + + for k, v := range tests { + key, err := cacheCreateKey(k) + if err != nil { + t.Errorf("Cache key generation err: %s", err) + continue + } + if key != v { + t.Errorf("Expected cache key %s for %s but got %s", v, k, key) + } + } +}
diff --git a/cmd/flatten.go b/cmd/flatten.go index c5174ea..abb3ce8 100644 --- a/cmd/flatten.go +++ b/cmd/flatten.go
@@ -27,6 +27,11 @@ func Flatten(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { conf := p.Get("conf", &yaml.Config{}).(*yaml.Config) skip := p.Get("skip", false).(bool) + home := p.Get("home", "").(string) + cache := p.Get("cache", false).(bool) + cacheGopath := p.Get("cacheGopath", false).(bool) + skipGopath := p.Get("skipGopath", false).(bool) + if skip { return conf, nil } @@ -50,7 +55,7 @@ f := &flattening{conf, vend, vend, deps, packages} - err := recFlatten(f, force) + err := recFlatten(f, force, home, cache, cacheGopath, skipGopath) flattenSetRefs(f) Info("Project relies on %d dependencies.", len(deps)) exportFlattenedDeps(conf, deps) @@ -84,7 +89,7 @@ var updateCache = map[string]bool{} // refFlatten recursively flattens the vendor tree. -func recFlatten(f *flattening, force bool) error { +func recFlatten(f *flattening, force bool, home string, cache, cacheGopath, skipGopath bool) error { Debug("---> Inspecting %s for changes (%d packages).\n", f.curr, len(f.scan)) for _, imp := range f.scan { Debug("----> Scanning %s", imp) @@ -104,14 +109,14 @@ if len(mod) > 0 { Debug("----> Updating all dependencies for %q (%d)", imp, len(mod)) - flattenGlideUp(f, base, force) + flattenGlideUp(f, base, home, force, cache, cacheGopath, skipGopath) f2 := &flattening{ conf: f.conf, top: f.top, curr: base, deps: f.deps, scan: mod} - recFlatten(f2, force) + recFlatten(f2, force, home, cache, cacheGopath, skipGopath) } } @@ -123,7 +128,7 @@ // While this is expensive, it is also necessary to make sure we have the // correct version of all dependencies. We might be able to simplify by // marking packages dirty when they are added. -func flattenGlideUp(f *flattening, base string, force bool) error { +func flattenGlideUp(f *flattening, base, home string, force, cache, cacheGopath, skipGopath bool) error { //vdir := path.Join(base, "vendor") for _, imp := range f.deps { wd := path.Join(f.top, imp.Name) @@ -133,7 +138,7 @@ continue } Debug("Updating project %s (%s)\n", imp.Name, wd) - if err := VcsUpdate(imp, f.top, force); err != nil { + if err := VcsUpdate(imp, f.top, home, force, cache, cacheGopath, skipGopath); err != nil { // We can still go on just fine even if this fails. Warn("Skipped update %s: %s\n", imp.Name, err) continue @@ -141,7 +146,7 @@ updateCache[imp.Name] = true } else { Debug("Importing %s to project %s\n", imp.Name, wd) - if err := VcsGet(imp, wd); err != nil { + if err := VcsGet(imp, wd, home, cache, cacheGopath, skipGopath); err != nil { Warn("Skipped getting %s: %v\n", imp.Name, err) continue }
diff --git a/cmd/get_imports.go b/cmd/get_imports.go index 3740cc9..fa55356 100644 --- a/cmd/get_imports.go +++ b/cmd/get_imports.go
@@ -1,7 +1,13 @@ package cmd import ( + "encoding/json" "fmt" + "io/ioutil" + "net/http" + "net/url" + "os/exec" + "path/filepath" "sort" //"log" @@ -38,6 +44,10 @@ names := p.Get("packages", []string{}).([]string) cfg := p.Get("conf", nil).(*yaml.Config) insecure := p.Get("insecure", false).(bool) + home := p.Get("home", "").(string) + cache := p.Get("cache", false).(bool) + cacheGopath := p.Get("cacheGopath", false).(bool) + skipGopath := p.Get("skipGopath", false).(bool) Info("Preparing to install %d package.", len(names)) @@ -60,13 +70,6 @@ dest := path.Join(cwd, root) - var repoURL string - if insecure { - repoURL = "http://" + root - } else { - repoURL = "https://" + root - } - repo, err := v.NewRepo(repoURL, dest) if err != nil { Error("Could not construct repo for %q: %s", name, err) return false, err @@ -86,8 +89,7 @@ if len(subpkg) > 0 && subpkg != "/" { dep.Subpackages = []string{subpkg} } - - if err := repo.Get(); err != nil { + if err := VcsGet(dep, dest, home, cache, cacheGopath, skipGopath); err != nil { return dep, err } @@ -99,29 +101,6 @@ return deps, nil } -// GetImports iterates over the imported packages and gets them. -func GetImports(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) { - cfg := p.Get("conf", nil).(*yaml.Config) - cwd, err := VendorPath(c) - if err != nil { - Error("Failed to prepare vendor directory: %s", err) - return false, err - } - - if len(cfg.Imports) == 0 { - Info("No dependencies found. Nothing downloaded.\n") - return false, nil - } - - for _, dep := range cfg.Imports { - if err := VcsGet(dep, cwd); err != nil { - Warn("Skipped getting %s: %v\n", dep.Name, err) - } - } - - return true, nil -} - // UpdateImports iterates over the imported packages and updates them. // // Params: @@ -133,6 +112,11 @@ cfg := p.Get("conf", nil).(*yaml.Config) force := p.Get("force", true).(bool) plist := p.Get("packages", []string{}).([]string) + home := p.Get("home", "").(string) + cache := p.Get("cache", false).(bool) + cacheGopath := p.Get("cacheGopath", false).(bool) + skipGopath := p.Get("skipGopath", false).(bool) + pkgs := list2map(plist) restrict := len(pkgs) > 0 @@ -157,7 +141,7 @@ // flattening from causing unnecessary updates. updateCache[dep.Name] = true - if err := VcsUpdate(dep, cwd, force); err != nil { + if err := VcsUpdate(dep, cwd, home, force, cache, cacheGopath, skipGopath); err != nil { Warn("Update failed for %s: %s\n", dep.Name, err) } } @@ -233,18 +217,206 @@ // VcsGet figures out how to fetch a dependency, and then gets it. // // VcsGet installs into the dest. -func VcsGet(dep *yaml.Dependency, dest string) error { +func VcsGet(dep *yaml.Dependency, dest, home string, cache, cacheGopath, skipGopath bool) error { + // When not skipping the $GOPATH look in it for a copy of the package + if !skipGopath { + // Check if the $GOPATH has a viable version to use and if so copy to vendor + gps := Gopaths() + for _, p := range gps { + d := filepath.Join(p, "src", dep.Name) + if _, err := os.Stat(d); err == nil { + empty, err := isDirectoryEmpty(d) + if empty || err != nil { + continue + } + + repo, err := dep.GetRepo(d) + if err != nil { + continue + } + + // Dirty repos have uncomitted changes. + if repo.IsDirty() { + continue + } + + // Having found a repo we copy it to vendor and update it. + Debug("Found %s in GOPATH at %s. Copying to %s", dep.Name, d, dest) + err = copyDir(d, dest) + if err != nil { + return err + } + + // Update the repo in the vendor directory + Debug("Updating %s, now in the vendor path at %s", dep.Name, dest) + repo, err = dep.GetRepo(dest) + if err != nil { + return err + } + err = repo.Update() + if err != nil { + return err + } + + // If there is no reference set on the dep we try to checkout + // the default branch. + if dep.Reference == "" { + db := defaultBranch(repo, home) + if db != "" { + err = repo.UpdateVersion(db) + if err != nil { + Debug("Attempting to set the version on %s to %s failed. Error %s", dep.Name, db, err) + } + } + } + return nil + } + } + } + + // When opting in to cache in the GOPATH attempt to do put a copy there. + if cacheGopath { + + // Since we didn't find an existing copy in the GOPATHs try to clone there. + gp := Gopath() + if gp != "" { + d := filepath.Join(gp, "src", dep.Name) + if _, err := os.Stat(d); os.IsNotExist(err) { + // Empty directory so we checkout out the code here. + Debug("Retrieving %s to %s before copying to vendor", dep.Name, d) + repo, err := dep.GetRepo(d) + if err != nil { + return err + } + repo.Get() + + branch := findCurrentBranch(repo) + if branch != "" { + // we know the default branch so we can store it in the cache + var loc string + if dep.Repository != "" { + loc = dep.Repository + } else { + loc = "https://" + dep.Name + } + key, err := cacheCreateKey(loc) + if err == nil { + Debug("Saving default branch for %s", repo.Remote()) + c := cacheRepoInfo{DefaultBranch: branch} + saveCacheRepoData(key, c, home) + } + } + + Debug("Copying %s from GOPATH at %s to %s", dep.Name, d, dest) + err = copyDir(d, dest) + if err != nil { + return err + } + + return nil + } + } + } + + // If opting in to caching attempt to put it in the cache folder + if cache { + // Check if the cache has a viable version and try to use that. + var loc string + if dep.Repository != "" { + loc = dep.Repository + } else { + loc = "https://" + dep.Name + } + key, err := cacheCreateKey(loc) + if err == nil { + d := filepath.Join(home, "cache", "src", key) + + repo, err := dep.GetRepo(d) + if err != nil { + return err + } + // If the directory does not exist this is a first cache. + if _, err = os.Stat(d); os.IsNotExist(err) { + Debug("Adding %s to the cache for the first time", dep.Name) + err = repo.Get() + if err != nil { + return err + } + branch := findCurrentBranch(repo) + if branch != "" { + // we know the default branch so we can store it in the cache + var loc string + if dep.Repository != "" { + loc = dep.Repository + } else { + loc = "https://" + dep.Name + } + key, err := cacheCreateKey(loc) + if err == nil { + Debug("Saving default branch for %s", repo.Remote()) + c := cacheRepoInfo{DefaultBranch: branch} + err = saveCacheRepoData(key, c, home) + if err != nil { + Debug("Error saving %s to cache. Error: %s", repo.Remote(), err) + } + } + } + + } else { + Debug("Updating %s in the cache", dep.Name) + err = repo.Update() + if err != nil { + return err + } + } + + Debug("Copying %s from the cache to %s", dep.Name, dest) + err = copyDir(d, dest) + if err != nil { + return err + } + + return nil + } else { + Warn("Cache key generation error: %s", err) + } + } + + // If unable to cache pull directly into the vendor/ directory. repo, err := dep.GetRepo(dest) if err != nil { return err } - return repo.Get() + gerr := repo.Get() + + // Attempt to cache the default branch + branch := findCurrentBranch(repo) + if branch != "" { + // we know the default branch so we can store it in the cache + var loc string + if dep.Repository != "" { + loc = dep.Repository + } else { + loc = "https://" + dep.Name + } + key, err := cacheCreateKey(loc) + if err == nil { + Debug("Saving default branch for %s", repo.Remote()) + c := cacheRepoInfo{DefaultBranch: branch} + err = saveCacheRepoData(key, c, home) + if err != nil { + Debug("Error saving %s to cache. Error: %s", repo.Remote(), err) + } + } + } + + return gerr } // VcsUpdate updates to a particular checkout based on the VCS setting. -func VcsUpdate(dep *yaml.Dependency, vend string, force bool) error { +func VcsUpdate(dep *yaml.Dependency, vend, home string, force, cache, cacheGopath, skipGopath bool) error { Info("Fetching updates for %s.\n", dep.Name) if filterArchOs(dep) { @@ -255,7 +427,7 @@ dest := path.Join(vend, dep.Name) // If destination doesn't exist we need to perform an initial checkout. if _, err := os.Stat(dest); os.IsNotExist(err) { - if err = VcsGet(dep, dest); err != nil { + if err = VcsGet(dep, dest, home, cache, cacheGopath, skipGopath); err != nil { Warn("Unable to checkout %s\n", dep.Name) return err } @@ -292,7 +464,7 @@ if rerr != nil { return rerr } - if err = VcsGet(dep, dest); err != nil { + if err = VcsGet(dep, dest, home, cache, cacheGopath, skipGopath); err != nil { Warn("Unable to checkout %s\n", dep.Name) return err } @@ -430,3 +602,158 @@ return version, nil } + +// Some repos will have multiple branches in them (e.g. Git) while others +// (e.g. Svn) will not. +// TODO(mattfarina): Add API calls to github, bitbucket, etc. +func defaultBranch(repo v.Repo, home string) string { + + // Svn and Bzr use different locations (paths or entire locations) + // for branches so we won't have a default branch. + if repo.Vcs() == v.Svn || repo.Vcs() == v.Bzr { + return "" + } + + // Check the cache for a value. + key, kerr := cacheCreateKey(repo.Remote()) + var d cacheRepoInfo + if kerr == nil { + d, err := cacheRepoData(key, home) + if err == nil { + if d.DefaultBranch != "" { + return d.DefaultBranch + } + } + } + + // If we don't have it in the store try some APIs + r := repo.Remote() + u, err := url.Parse(r) + if err != nil { + return "" + } + if u.Scheme == "" { + // Where there is no scheme we try urls like git@github.com:foo/bar + r = strings.Replace(r, ":", "/", -1) + r = "ssh://" + r + u, err = url.Parse(r) + if err != nil { + return "" + } + u.Scheme = "" + } + if u.Host == "github.com" { + parts := strings.Split(u.Path, "/") + if len(parts) != 2 { + return "" + } + api := fmt.Sprintf("https://api.github.com/repos/%s/%s", parts[0], parts[1]) + resp, err := http.Get(api) + if err != nil { + return "" + } + defer resp.Body.Close() + if resp.StatusCode >= 300 || resp.StatusCode < 200 { + return "" + } + body, err := ioutil.ReadAll(resp.Body) + var data interface{} + err = json.Unmarshal(body, &data) + if err != nil { + return "" + } + gh := data.(map[string]interface{}) + db := gh["default_branch"].(string) + if kerr == nil { + d.DefaultBranch = db + saveCacheRepoData(key, d, home) + } + return db + } + + if u.Host == "bitbucket.org" { + parts := strings.Split(u.Path, "/") + if len(parts) != 2 { + return "" + } + api := fmt.Sprintf("https://bitbucket.org/api/1.0/repositories/%s/%s/main-branch/", parts[0], parts[1]) + resp, err := http.Get(api) + if err != nil { + return "" + } + defer resp.Body.Close() + if resp.StatusCode >= 300 || resp.StatusCode < 200 { + return "" + } + body, err := ioutil.ReadAll(resp.Body) + var data interface{} + err = json.Unmarshal(body, &data) + if err != nil { + return "" + } + bb := data.(map[string]interface{}) + db := bb["name"].(string) + if kerr == nil { + d.DefaultBranch = db + saveCacheRepoData(key, d, home) + } + return db + } + + return "" +} + +// From a local repo find out the current branch name if there is one. +func findCurrentBranch(repo v.Repo) string { + Debug("Attempting to find current branch for %s", repo.Remote()) + // Svn and Bzr don't have default branches. + if repo.Vcs() == v.Svn || repo.Vcs() == v.Bzr { + return "" + } + + if repo.Vcs() == v.Git { + c := exec.Command("git", "symbolic-ref", "--short", "HEAD") + c.Dir = repo.LocalPath() + c.Env = envForDir(c.Dir) + out, err := c.CombinedOutput() + if err != nil { + Debug("Unable to find current branch for %s, error: %s", repo.Remote(), err) + return "" + } + return strings.TrimSpace(string(out)) + } + + if repo.Vcs() == v.Hg { + c := exec.Command("hg", "branch") + c.Dir = repo.LocalPath() + c.Env = envForDir(c.Dir) + out, err := c.CombinedOutput() + if err != nil { + Debug("Unable to find current branch for %s, error: %s", repo.Remote(), err) + return "" + } + return strings.TrimSpace(string(out)) + } + + return "" +} + +func envForDir(dir string) []string { + env := os.Environ() + return mergeEnvLists([]string{"PWD=" + dir}, env) +} + +func mergeEnvLists(in, out []string) []string { +NextVar: + for _, inkv := range in { + k := strings.SplitAfterN(inkv, "=", 2)[0] + for i, outkv := range out { + if strings.HasPrefix(outkv, k) { + out[i] = inkv + continue NextVar + } + } + out = append(out, inkv) + } + return out +}
diff --git a/cmd/get_imports_test.go b/cmd/get_imports_test.go index 9deddf4..b072ed4 100644 --- a/cmd/get_imports_test.go +++ b/cmd/get_imports_test.go
@@ -1,26 +1,6 @@ package cmd -import ( - "testing" - - "github.com/Masterminds/cookoo" - "github.com/Masterminds/glide/yaml" -) - -func TestGetImportsEmptyConfig(t *testing.T) { - _, _, c := cookoo.Cookoo() - SilenceLogs(c) - cfg := new(yaml.Config) - p := cookoo.NewParamsWithValues(map[string]interface{}{"conf": cfg}) - res, it := GetImports(c, p) - if it != nil { - t.Errorf("Interrupt value non-nil") - } - bres, ok := res.(bool) - if !ok || bres { - t.Errorf("Result was non-bool or true: ok=%t bres=%t", ok, bres) - } -} +import "github.com/Masterminds/cookoo" func SilenceLogs(c cookoo.Context) { p := cookoo.NewParamsWithValues(map[string]interface{}{"quiet": true})
diff --git a/cmd/util.go b/cmd/util.go index 9bc1c96..3a27e63 100644 --- a/cmd/util.go +++ b/cmd/util.go
@@ -162,3 +162,78 @@ } return true, err } + +// We copy the directory here rather than jumping out to a shell so we can +// support multiple operating systems. +func copyDir(source string, dest string) error { + + // get properties of source dir + si, err := os.Stat(source) + if err != nil { + return err + } + + err = os.MkdirAll(dest, si.Mode()) + if err != nil { + return err + } + + d, _ := os.Open(source) + + objects, err := d.Readdir(-1) + + for _, obj := range objects { + + sp := filepath.Join(source, "/", obj.Name()) + + dp := filepath.Join(dest, "/", obj.Name()) + + if obj.IsDir() { + err = copyDir(sp, dp) + if err != nil { + return err + } + } else { + // perform copy + err = copyFile(sp, dp) + if err != nil { + return err + } + } + + } + return nil +} + +func copyFile(source string, dest string) error { + ln, err := os.Readlink(source) + if err == nil { + return os.Symlink(ln, dest) + } + s, err := os.Open(source) + if err != nil { + return err + } + + defer s.Close() + + d, err := os.Create(dest) + if err != nil { + return err + } + + defer d.Close() + + _, err = io.Copy(d, s) + if err != nil { + return err + } + + si, err := os.Stat(source) + if err != nil { + return err + } + err = os.Chmod(dest, si.Mode()) + + return err +}
diff --git a/glide.go b/glide.go index 89be05c..9e7ad57 100644 --- a/glide.go +++ b/glide.go
@@ -37,6 +37,8 @@ package main import ( + "path/filepath" + "github.com/Masterminds/glide/cmd" "github.com/Masterminds/cookoo" @@ -44,6 +46,7 @@ "fmt" "os" + "os/user" ) var version = "dev" @@ -94,6 +97,12 @@ Name: "debug", Usage: "Print Debug messages (verbose)", }, + cli.StringFlag{ + Name: "home", + Value: defaultGlideDir(), + Usage: "The location of Glide files", + EnvVar: "GLIDE_HOME", + }, cli.BoolFlag{ Name: "no-color", Usage: "Turn off colored output for log messages", @@ -172,6 +181,18 @@ Name: "insecure", Usage: "Use http:// rather than https:// to retrieve pacakges.", }, + cli.BoolFlag{ + Name: "cache", + Usage: "When downloading dependencies attempt to cache them.", + }, + cli.BoolFlag{ + Name: "cache-gopath", + Usage: "When downloading dependencies attempt to put them in the GOPATH, too.", + }, + cli.BoolFlag{ + Name: "skip-gopath", + Usage: "Skip attempting to copy a dependency from the GOPATH.", + }, }, Action: func(c *cli.Context) { if len(c.Args()) < 1 { @@ -181,6 +202,9 @@ cxt.Put("packages", []string(c.Args())) cxt.Put("skipFlatten", !c.Bool("no-recursive")) cxt.Put("insecure", c.Bool("insecure")) + cxt.Put("useCache", c.Bool("cache")) + cxt.Put("cacheGopath", c.Bool("cache-gopath")) + cxt.Put("skipGopath", c.Bool("skip-gopath")) // FIXME: Are these used anywhere? if c.Bool("import") { cxt.Put("importGodeps", true) @@ -342,6 +366,18 @@ Name: "file, f", Usage: "Save all of the discovered dependencies to a Glide YAML file.", }, + cli.BoolFlag{ + Name: "cache", + Usage: "When downloading dependencies attempt to cache them.", + }, + cli.BoolFlag{ + Name: "cache-gopath", + Usage: "When downloading dependencies attempt to put them in the GOPATH, too.", + }, + cli.BoolFlag{ + Name: "skip-gopath", + Usage: "Skip attempting to copy a dependency from the GOPATH.", + }, }, Action: func(c *cli.Context) { cxt.Put("deleteOptIn", c.Bool("delete")) @@ -350,6 +386,9 @@ cxt.Put("deleteFlatten", c.Bool("delete-flatten")) cxt.Put("toPath", c.String("file")) cxt.Put("toStdout", false) + cxt.Put("useCache", c.Bool("cache")) + cxt.Put("cacheGopath", c.Bool("cache-gopath")) + cxt.Put("skipGopath", c.Bool("skip-gopath")) if c.Bool("import") { cxt.Put("importGodeps", true) cxt.Put("importGPM", true) @@ -425,6 +464,7 @@ cxt.Put("debug", c.GlobalBool("debug")) cxt.Put("no-color", c.GlobalBool("no-color")) cxt.Put("yaml", c.GlobalString("yaml")) + cxt.Put("home", c.GlobalString("home")) cxt.Put("cliArgs", c.Args()) if err := router.HandleRequest(route, cxt, false); err != nil { fmt.Printf("Oops! %s\n", err) @@ -444,7 +484,8 @@ reg.Route("@ready", "Prepare for glide commands."). Does(cmd.ReadyToGlide, "ready").Using("filename").From("cxt:yaml"). - Does(cmd.ParseYaml, "cfg").Using("filename").From("cxt:yaml") + Does(cmd.ParseYaml, "cfg").Using("filename").From("cxt:yaml"). + Does(cmd.EnsureCacheDir, "_").Using("home").From("cxt:home") reg.Route("get", "Install a pkg in vendor, and store the results in the glide.yaml"). Includes("@startup"). @@ -454,9 +495,17 @@ Using("packages").From("cxt:packages"). Using("conf").From("cxt:cfg"). Using("insecure").From("cxt:insecure"). + Using("home").From("cxt:home"). + Using("cache").From("cxt:useCache"). + Using("cacheGopath").From("cxt:cacheGopath"). + Using("skipGopath").From("cxt:skipGopath"). Does(cmd.Flatten, "flatten").Using("conf").From("cxt:cfg"). Using("packages").From("cxt:packages"). Using("force").From("cxt:forceUpdate"). + Using("home").From("cxt:home"). + Using("cache").From("cxt:useCache"). + Using("cacheGopath").From("cxt:cacheGopath"). + Using("skipGopath").From("cxt:skipGopath"). Does(cmd.WriteYaml, "out"). Using("conf").From("cxt:cfg"). Using("filename").WithDefault("glide.yaml").From("cxt:yaml") @@ -483,11 +532,19 @@ Using("conf").From("cxt:cfg"). Using("force").From("cxt:forceUpdate"). Using("packages").From("cxt:packages"). + Using("home").From("cxt:home"). + Using("cache").From("cxt:useCache"). + Using("cacheGopath").From("cxt:cacheGopath"). + Using("skipGopath").From("cxt:skipGopath"). Does(cmd.SetReference, "version").Using("conf").From("cxt:cfg"). Does(cmd.Flatten, "flattened").Using("conf").From("cxt:cfg"). Using("packages").From("cxt:packages"). Using("force").From("cxt:forceUpdate"). Using("skip").From("cxt:skipFlatten"). + Using("home").From("cxt:home"). + Using("cache").From("cxt:useCache"). + Using("cacheGopath").From("cxt:cacheGopath"). + Using("skipGopath").From("cxt:skipGopath"). Does(cmd.VendoredCleanUp, "_"). Using("conf").From("cxt:cfg"). Using("update").From("cxt:updateVendoredDeps"). @@ -588,3 +645,11 @@ Does(cmd.DropToShell, "plugin"). Using("command").From("cxt:command") } + +func defaultGlideDir() string { + c, err := user.Current() + if err != nil { + return "" + } + return filepath.Join(c.HomeDir, ".glide") +}
diff --git a/glide.yaml b/glide.yaml index aefd6a6..55f6078 100644 --- a/glide.yaml +++ b/glide.yaml
@@ -1,9 +1,6 @@ package: github.com/Masterminds/glide import: - - package: github.com/kylelemons/go-gypsy - subpackages: - - yaml - flatten: true + - package: gopkg.in/yaml.v2 - package: github.com/Masterminds/cookoo version: master repo: git@github.com:Masterminds/cookoo.git @@ -11,7 +8,7 @@ subpackages: - . - package: github.com/Masterminds/vcs - version: ^1.1.4 + version: ^1.2.0 - package: github.com/codegangsta/cli - package: github.com/Masterminds/semver version: ^1.0.0
diff --git a/yaml/yaml.go b/yaml/yaml.go index de0fcb2..be1e8bb 100644 --- a/yaml/yaml.go +++ b/yaml/yaml.go
@@ -72,7 +72,7 @@ Parent *Config Name string `yaml:"package"` Imports Dependencies `yaml:"import"` - DevImports Dependencies `yaml:"devimport"` + DevImports Dependencies `yaml:"devimport,omitempty"` } // HasDependency returns true if the given name is listed as an import or dev import.