| package cache | 
 |  | 
 | import ( | 
 | 	"sync" | 
 |  | 
 | 	"github.com/Masterminds/glide/msg" | 
 | 	"github.com/Masterminds/semver" | 
 | ) | 
 |  | 
 | // Provide an in memory cache of imported project information. | 
 |  | 
 | var defaultMemCache = newMemCache() | 
 |  | 
 | // MemPut put a version into the in memory cache for a name. | 
 | // This will silently ignore non-semver and make sure the latest | 
 | // is stored. | 
 | func MemPut(name, version string) { | 
 | 	defaultMemCache.put(name, version) | 
 | } | 
 |  | 
 | // MemTouched returns true if the cache was touched for a name. | 
 | func MemTouched(name string) bool { | 
 | 	return defaultMemCache.touched(name) | 
 | } | 
 |  | 
 | // MemTouch notes if a name has been looked at. | 
 | func MemTouch(name string) { | 
 | 	defaultMemCache.touch(name) | 
 | } | 
 |  | 
 | // MemLatest returns the latest, that is most recent, semver release. This | 
 | // may be a blank string if no put value | 
 | func MemLatest(name string) string { | 
 | 	return defaultMemCache.getLatest(name) | 
 | } | 
 |  | 
 | // MemSetCurrent is used to set the current version in use. | 
 | func MemSetCurrent(name, version string) { | 
 | 	defaultMemCache.setCurrent(name, version) | 
 | } | 
 |  | 
 | // MemCurrent is used to get the current version in use. | 
 | func MemCurrent(name string) string { | 
 | 	return defaultMemCache.current(name) | 
 | } | 
 |  | 
 | // An in memory cache. | 
 | type memCache struct { | 
 | 	sync.RWMutex | 
 | 	latest   map[string]string | 
 | 	t        map[string]bool | 
 | 	versions map[string][]string | 
 | 	c        map[string]string | 
 | } | 
 |  | 
 | func newMemCache() *memCache { | 
 | 	return &memCache{ | 
 | 		latest:   make(map[string]string), | 
 | 		t:        make(map[string]bool), | 
 | 		versions: make(map[string][]string), | 
 | 		c:        make(map[string]string), | 
 | 	} | 
 | } | 
 |  | 
 | func (m *memCache) setCurrent(name, version string) { | 
 | 	m.Lock() | 
 | 	defer m.Unlock() | 
 |  | 
 | 	if m.c[name] == "" { | 
 | 		m.c[name] = version | 
 | 	} else { | 
 | 		// If we already have a version try to see if the new or old one is | 
 | 		// semver and use that one. | 
 | 		_, err := semver.NewVersion(m.c[name]) | 
 | 		if err != nil { | 
 | 			_, err2 := semver.NewVersion(version) | 
 | 			if err2 == nil { | 
 | 				m.c[name] = version | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func (m *memCache) current(name string) string { | 
 | 	m.RLock() | 
 | 	defer m.RUnlock() | 
 | 	return m.c[name] | 
 | } | 
 |  | 
 | func (m *memCache) put(name, version string) { | 
 | 	m.Lock() | 
 | 	defer m.Unlock() | 
 | 	m.t[name] = true | 
 | 	sv, err := semver.NewVersion(version) | 
 | 	if err != nil { | 
 | 		msg.Debug("Ignoring %s version %s: %s", name, version, err) | 
 | 		return | 
 | 	} | 
 |  | 
 | 	latest, found := m.latest[name] | 
 | 	if found { | 
 | 		lv, err := semver.NewVersion(latest) | 
 | 		if err == nil { | 
 | 			if sv.GreaterThan(lv) { | 
 | 				m.latest[name] = version | 
 | 			} | 
 | 		} | 
 | 	} else { | 
 | 		m.latest[name] = version | 
 | 	} | 
 |  | 
 | 	found = false | 
 | 	for _, v := range m.versions[name] { | 
 | 		if v == version { | 
 | 			found = true | 
 | 		} | 
 | 	} | 
 | 	if !found { | 
 | 		m.versions[name] = append(m.versions[name], version) | 
 | 	} | 
 | } | 
 |  | 
 | func (m *memCache) touch(name string) { | 
 | 	m.Lock() | 
 | 	defer m.Unlock() | 
 | 	m.t[name] = true | 
 | } | 
 |  | 
 | func (m *memCache) touched(name string) bool { | 
 | 	m.RLock() | 
 | 	defer m.RUnlock() | 
 | 	return m.t[name] | 
 | } | 
 |  | 
 | func (m *memCache) getLatest(name string) string { | 
 | 	m.RLock() | 
 | 	defer m.RUnlock() | 
 | 	return m.latest[name] | 
 | } |