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)