Merge pull request #124 from Masterminds/feature/cache
Feature/cache
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..3462cfe 100644
--- a/cmd/flatten.go
+++ b/cmd/flatten.go
@@ -27,6 +27,9 @@
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)
+
if skip {
return conf, nil
}
@@ -50,7 +53,7 @@
f := &flattening{conf, vend, vend, deps, packages}
- err := recFlatten(f, force)
+ err := recFlatten(f, force, home, cache)
flattenSetRefs(f)
Info("Project relies on %d dependencies.", len(deps))
exportFlattenedDeps(conf, deps)
@@ -84,7 +87,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 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 +107,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)
f2 := &flattening{
conf: f.conf,
top: f.top,
curr: base,
deps: f.deps,
scan: mod}
- recFlatten(f2, force)
+ recFlatten(f2, force, home, cache)
}
}
@@ -123,7 +126,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 bool) error {
//vdir := path.Join(base, "vendor")
for _, imp := range f.deps {
wd := path.Join(f.top, imp.Name)
@@ -133,7 +136,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); 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 +144,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); 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..e3f01fa 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,7 +44,8 @@
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)
Info("Preparing to install %d package.", len(names))
deps := []*yaml.Dependency{}
@@ -60,13 +67,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 +86,7 @@
if len(subpkg) > 0 && subpkg != "/" {
dep.Subpackages = []string{subpkg}
}
-
- if err := repo.Get(); err != nil {
+ if err := VcsGet(dep, dest, home, cache); err != nil {
return dep, err
}
@@ -99,29 +98,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 +109,8 @@
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)
pkgs := list2map(plist)
restrict := len(pkgs) > 0
@@ -157,7 +135,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); err != nil {
Warn("Update failed for %s: %s\n", dep.Name, err)
}
}
@@ -233,8 +211,165 @@
// 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 bool) error {
+ if !cache {
+ // 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
+ }
+ }
+
+ // 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
+ }
+ }
+ }
+
+ // 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
@@ -244,7 +379,7 @@
}
// 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 bool) error {
Info("Fetching updates for %s.\n", dep.Name)
if filterArchOs(dep) {
@@ -255,7 +390,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); err != nil {
Warn("Unable to checkout %s\n", dep.Name)
return err
}
@@ -292,7 +427,7 @@
if rerr != nil {
return rerr
}
- if err = VcsGet(dep, dest); err != nil {
+ if err = VcsGet(dep, dest, home, cache); err != nil {
Warn("Unable to checkout %s\n", dep.Name)
return err
}
@@ -430,3 +565,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 5527153..d4fd8ba 100644
--- a/cmd/util.go
+++ b/cmd/util.go
@@ -154,3 +154,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 e1456a0..6675b2c 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",
+ },
}
app.CommandNotFound = func(c *cli.Context, command string) {
cxt.Put("os.Args", os.Args)
@@ -168,6 +177,10 @@
Name: "insecure",
Usage: "Use http:// rather than https:// to retrieve pacakges.",
},
+ cli.BoolFlag{
+ Name: "cache",
+ Usage: "Setting will only and use files from the cache (excluding the GOPATH)",
+ },
},
Action: func(c *cli.Context) {
if len(c.Args()) < 1 {
@@ -177,6 +190,7 @@
cxt.Put("packages", []string(c.Args()))
cxt.Put("skipFlatten", !c.Bool("no-recursive"))
cxt.Put("insecure", c.Bool("insecure"))
+ cxt.Put("forceCache", c.Bool("cache"))
// FIXME: Are these used anywhere?
if c.Bool("import") {
cxt.Put("importGodeps", true)
@@ -338,6 +352,10 @@
Name: "file, f",
Usage: "Save all of the discovered dependencies to a Glide YAML file.",
},
+ cli.BoolFlag{
+ Name: "cache",
+ Usage: "Setting will only and use files from the cache (excluding the GOPATH)",
+ },
},
Action: func(c *cli.Context) {
cxt.Put("deleteOptIn", c.Bool("delete"))
@@ -346,6 +364,7 @@
cxt.Put("deleteFlatten", c.Bool("delete-flatten"))
cxt.Put("toPath", c.String("file"))
cxt.Put("toStdout", false)
+ cxt.Put("forceCache", c.Bool("cache"))
if c.Bool("import") {
cxt.Put("importGodeps", true)
cxt.Put("importGPM", true)
@@ -420,6 +439,7 @@
cxt.Put("q", c.GlobalBool("quiet"))
cxt.Put("debug", c.GlobalBool("debug"))
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)
@@ -437,7 +457,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").
@@ -447,9 +468,13 @@
Using("packages").From("cxt:packages").
Using("conf").From("cxt:cfg").
Using("insecure").From("cxt:insecure").
+ Using("home").From("cxt:home").
+ Using("cache").From("cxt:forceCache").
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:forceCache").
Does(cmd.WriteYaml, "out").
Using("conf").From("cxt:cfg").
Using("filename").WithDefault("glide.yaml").From("cxt:yaml")
@@ -476,11 +501,15 @@
Using("conf").From("cxt:cfg").
Using("force").From("cxt:forceUpdate").
Using("packages").From("cxt:packages").
+ Using("home").From("cxt:home").
+ Using("cache").From("cxt:forceCache").
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:forceCache").
Does(cmd.VendoredCleanUp, "_").
Using("conf").From("cxt:cfg").
Using("update").From("cxt:updateVendoredDeps").
@@ -581,3 +610,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..05144a9 100644
--- a/glide.yaml
+++ b/glide.yaml
@@ -11,7 +11,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.