|  | package main | 
|  |  | 
|  | import ( | 
|  | "sync" | 
|  |  | 
|  | "github.com/FiloSottile/gvt/gbvendor" | 
|  | ) | 
|  |  | 
|  | type cacheKey struct { | 
|  | url, repoType         string | 
|  | branch, tag, revision string | 
|  | } | 
|  |  | 
|  | type cacheEntry struct { | 
|  | wg  sync.WaitGroup | 
|  | v   vendor.WorkingCopy | 
|  | err error | 
|  | } | 
|  |  | 
|  | // Downloader acts as a cache for downloaded repositories | 
|  | type Downloader struct { | 
|  | mu sync.Mutex | 
|  | m  map[cacheKey]*cacheEntry | 
|  | } | 
|  |  | 
|  | var GlobalDownloader = Downloader{} | 
|  |  | 
|  | func init() { | 
|  | GlobalDownloader.m = make(map[cacheKey]*cacheEntry) | 
|  | } | 
|  |  | 
|  | // Get returns a cached WorkingCopy, or runs RemoteRepo.Checkout | 
|  | func (d *Downloader) Get(repo vendor.RemoteRepo, branch, tag, revision string) (vendor.WorkingCopy, error) { | 
|  | key := cacheKey{ | 
|  | url: repo.URL(), repoType: repo.Type(), | 
|  | branch: branch, tag: tag, revision: revision, | 
|  | } | 
|  | d.mu.Lock() | 
|  | if entry, ok := d.m[key]; ok { | 
|  | d.mu.Unlock() | 
|  | entry.wg.Wait() | 
|  | return entry.v, entry.err | 
|  | } | 
|  |  | 
|  | entry := &cacheEntry{} | 
|  | entry.wg.Add(1) | 
|  | d.m[key] = entry | 
|  | d.mu.Unlock() | 
|  |  | 
|  | entry.v, entry.err = repo.Checkout(branch, tag, revision) | 
|  | entry.wg.Done() | 
|  | return entry.v, entry.err | 
|  | } | 
|  |  | 
|  | func (d *Downloader) Flush() error { | 
|  | d.mu.Lock() | 
|  | defer d.mu.Unlock() | 
|  |  | 
|  | for _, entry := range d.m { | 
|  | entry.wg.Wait() | 
|  | if entry.err != nil { | 
|  | continue | 
|  | } | 
|  | if err := entry.v.Destroy(); err != nil { | 
|  | return err | 
|  | } | 
|  | } | 
|  | return nil | 
|  | } |