Expose the cache API
diff --git a/cache/cache.go b/cache/cache.go
index 5f4732f..355c468 100644
--- a/cache/cache.go
+++ b/cache/cache.go
@@ -2,12 +2,169 @@
package cache
import (
+ "encoding/json"
+ "errors"
+ "io/ioutil"
+ "net/url"
+ "os"
"path/filepath"
+ "regexp"
+ "strings"
+ "sync"
+ "time"
+ "github.com/Masterminds/glide/msg"
gpath "github.com/Masterminds/glide/path"
)
+// Enabled sets if the cache is globally enabled. Defaults to true.
+var Enabled = true
+
+// ErrCacheDisabled is returned with the cache is disabled.
+var ErrCacheDisabled = errors.New("Cache disabled")
+
+var isSetup bool
+
+var setupMutex sync.Mutex
+
+func setup() error {
+ setupMutex.Lock()
+ defer setupMutex.Unlock()
+
+ if isSetup {
+ return nil
+ }
+ msg.Debug("Setting up the cache directory")
+ pths := []string{
+ "cache",
+ filepath.Join("cache", "src"),
+ filepath.Join("cache", "info"),
+ }
+
+ for _, l := range pths {
+ err := os.MkdirAll(filepath.Join(gpath.Home(), l), 0755)
+ if err != nil {
+ return err
+ }
+ }
+
+ isSetup = true
+ return nil
+}
+
// Location returns the location of the cache.
-func Location() string {
- return filepath.Join(gpath.Home(), "cache")
+func Location() (string, error) {
+ p := filepath.Join(gpath.Home(), "cache")
+ err := setup()
+
+ return p, err
+}
+
+// scpSyntaxRe matches the SCP-like addresses used to access repos over SSH.
+var scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
+
+// Key generates a cache key based on a url or scp string. The key is file
+// system safe.
+func Key(repo string) (string, error) {
+
+ var u *url.URL
+ var err error
+ var strip bool
+ if m := scpSyntaxRe.FindStringSubmatch(repo); m != nil {
+ // Match SCP-like syntax and convert it to a URL.
+ // Eg, "git@github.com:user/repo" becomes
+ // "ssh://git@github.com/user/repo".
+ u = &url.URL{
+ Scheme: "ssh",
+ User: url.User(m[1]),
+ Host: m[2],
+ Path: "/" + m[3],
+ }
+ strip = true
+ } else {
+ u, err = url.Parse(repo)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ if strip {
+ 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
+}
+
+// RepoInfo holds information about a repo.
+type RepoInfo struct {
+ DefaultBranch string `json:"default-branch"`
+ LastUpdate string `json:"last-update"`
+}
+
+// SaveRepoData stores data about a repo in the Glide cache
+func SaveRepoData(key string, data RepoInfo) error {
+ if !Enabled {
+ return ErrCacheDisabled
+ }
+ location, err := Location()
+ if err != nil {
+ return err
+ }
+ data.LastUpdate = time.Now().String()
+ d, err := json.Marshal(data)
+ if err != nil {
+ return err
+ }
+
+ pp := filepath.Join(location, "info")
+ err = os.MkdirAll(pp, 0755)
+ if err != nil {
+ return err
+ }
+
+ p := filepath.Join(pp, key+".json")
+ f, err := os.Create(p)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ _, err = f.Write(d)
+ return err
+}
+
+// RepoData retrieves cached information about a repo.
+func RepoData(key string) (*RepoInfo, error) {
+ if !Enabled {
+ return &RepoInfo{}, ErrCacheDisabled
+ }
+ location, err := Location()
+ if err != nil {
+ return &RepoInfo{}, err
+ }
+ c := &RepoInfo{}
+ p := filepath.Join(location, "info", key+".json")
+ f, err := ioutil.ReadFile(p)
+ if err != nil {
+ return &RepoInfo{}, err
+ }
+ err = json.Unmarshal(f, c)
+ if err != nil {
+ return &RepoInfo{}, err
+ }
+ return c, nil
}
diff --git a/cache/cache_test.go b/cache/cache_test.go
new file mode 100644
index 0000000..ce6f5f5
--- /dev/null
+++ b/cache/cache_test.go
@@ -0,0 +1,22 @@
+package cache
+
+import "testing"
+
+func TestKey(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",
+ "https://github.com:123/foo/bar": "https-github.com-123-foo-bar",
+ }
+
+ for k, v := range tests {
+ key, err := Key(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/repo/cache.go b/repo/cache.go
deleted file mode 100644
index babd1c2..0000000
--- a/repo/cache.go
+++ /dev/null
@@ -1,128 +0,0 @@
-package repo
-
-import (
- "encoding/json"
- "errors"
- "io/ioutil"
- "net/url"
- "os"
- "path/filepath"
- "regexp"
- "strings"
- "time"
- //"github.com/Masterminds/glide/msg"
-)
-
-var cacheEnabled = true
-
-var errCacheDisabled = errors.New("Cache disabled")
-
-// 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 == "" {
- cacheEnabled = false
- msg.Warn("Unable to locate home directory")
- return false, nil
- }
- err := os.MkdirAll(filepath.Join(home, "cache", "info"), os.ModeDir|os.ModePerm)
- if err != nil {
- cacheEnabled = false
- Warn("Error creating Glide directory %s", home)
- }
- return false, nil
-}
-*/
-
-// scpSyntaxRe matches the SCP-like addresses used to access repos over SSH.
-var scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
-
-// Pass in a repo location and get a cache key from it.
-func cacheCreateKey(repo string) (string, error) {
-
- var u *url.URL
- var err error
- var strip bool
- if m := scpSyntaxRe.FindStringSubmatch(repo); m != nil {
- // Match SCP-like syntax and convert it to a URL.
- // Eg, "git@github.com:user/repo" becomes
- // "ssh://git@github.com/user/repo".
- u = &url.URL{
- Scheme: "ssh",
- User: url.User(m[1]),
- Host: m[2],
- Path: "/" + m[3],
- }
- strip = true
- } else {
- u, err = url.Parse(repo)
- if err != nil {
- return "", err
- }
- }
-
- if strip {
- 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 {
- if !cacheEnabled {
- return errCacheDisabled
- }
- 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) {
- if !cacheEnabled {
- return &cacheRepoInfo{}, errCacheDisabled
- }
- 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/repo/cache_test.go b/repo/cache_test.go
deleted file mode 100644
index d5e1c1d..0000000
--- a/repo/cache_test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package repo
-
-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/repo/vcs.go b/repo/vcs.go
index 16c4382..a808aa7 100644
--- a/repo/vcs.go
+++ b/repo/vcs.go
@@ -13,6 +13,7 @@
"sort"
"strings"
+ cp "github.com/Masterminds/glide/cache"
"github.com/Masterminds/glide/cfg"
"github.com/Masterminds/glide/msg"
gpath "github.com/Masterminds/glide/path"
@@ -345,12 +346,12 @@
} else {
loc = "https://" + dep.Name
}
- key, err := cacheCreateKey(loc)
+ key, err := cp.Key(loc)
if err == nil {
msg.Debug("Saving default branch for %s", repo.Remote())
- c := cacheRepoInfo{DefaultBranch: branch}
- err = saveCacheRepoData(key, c, home)
- if msg.Default.IsDebugging && err == errCacheDisabled {
+ c := cp.RepoInfo{DefaultBranch: branch}
+ err = cp.SaveRepoData(key, c)
+ if msg.Default.IsDebugging && err == cp.ErrCacheDisabled {
msg.Debug("Unable to cache default branch because caching is disabled")
}
}
@@ -376,9 +377,13 @@
} else {
loc = "https://" + dep.Name
}
- key, err := cacheCreateKey(loc)
+ key, err := cp.Key(loc)
if err == nil {
- d := filepath.Join(home, "cache", "src", key)
+ location, err := cp.Location()
+ if err != nil {
+ return err
+ }
+ d := filepath.Join(location, "src", key)
repo, err := dep.GetRepo(d)
if err != nil {
@@ -400,12 +405,12 @@
} else {
loc = "https://" + dep.Name
}
- key, err := cacheCreateKey(loc)
+ key, err := cp.Key(loc)
if err == nil {
msg.Debug("Saving default branch for %s", repo.Remote())
- c := cacheRepoInfo{DefaultBranch: branch}
- err = saveCacheRepoData(key, c, home)
- if err == errCacheDisabled {
+ c := cp.RepoInfo{DefaultBranch: branch}
+ err = cp.SaveRepoData(key, c)
+ if err == cp.ErrCacheDisabled {
msg.Debug("Unable to cache default branch because caching is disabled")
} else if err != nil {
msg.Debug("Error saving %s to cache. Error: %s", repo.Remote(), err)
@@ -451,12 +456,12 @@
} else {
loc = "https://" + dep.Name
}
- key, err := cacheCreateKey(loc)
+ key, err := cp.Key(loc)
if err == nil {
msg.Debug("Saving default branch for %s", repo.Remote())
- c := cacheRepoInfo{DefaultBranch: branch}
- err = saveCacheRepoData(key, c, home)
- if err == errCacheDisabled {
+ c := cp.RepoInfo{DefaultBranch: branch}
+ err = cp.SaveRepoData(key, c)
+ if err == cp.ErrCacheDisabled {
msg.Debug("Unable to cache default branch because caching is disabled")
} else if err != nil {
msg.Debug("Error saving %s to cache - Error: %s", repo.Remote(), err)
@@ -528,10 +533,10 @@
}
// Check the cache for a value.
- key, kerr := cacheCreateKey(repo.Remote())
- var d cacheRepoInfo
+ key, kerr := cp.Key(repo.Remote())
+ var d cp.RepoInfo
if kerr == nil {
- d, err := cacheRepoData(key, home)
+ d, err := cp.RepoData(key)
if err == nil {
if d.DefaultBranch != "" {
return d.DefaultBranch
@@ -579,8 +584,8 @@
db := gh["default_branch"].(string)
if kerr == nil {
d.DefaultBranch = db
- err := saveCacheRepoData(key, d, home)
- if err == errCacheDisabled {
+ err := cp.SaveRepoData(key, d)
+ if err == cp.ErrCacheDisabled {
msg.Debug("Unable to cache default branch because caching is disabled")
} else if err != nil {
msg.Debug("Error saving %s to cache. Error: %s", repo.Remote(), err)
@@ -613,8 +618,8 @@
db := bb["name"].(string)
if kerr == nil {
d.DefaultBranch = db
- err := saveCacheRepoData(key, d, home)
- if err == errCacheDisabled {
+ err := cp.SaveRepoData(key, d)
+ if err == cp.ErrCacheDisabled {
msg.Debug("Unable to cache default branch because caching is disabled")
} else if err != nil {
msg.Debug("Error saving %s to cache. Error: %s", repo.Remote(), err)