10 // An arbitrary object that can be stringified by fmt.Sprint().
12 // The stringification is filtered to ensure it doesn't contain characters
13 // that are invalid on Windows, which has the most restrictive filesystem.
14 // The "bad" characters (\, /, :, *, ?, ", <, >, |) are replaced with _.
16 // On a list of CacheKeys, the last component is taken to represent a file
17 // and all the other components represent the intermediary directories.
18 // This means that it's not possible to have subkeys of an existing file key.
19 type CacheKey interface{}
21 // All "bad characters" that can't go in Windows paths.
22 // It's a superset of the "bad characters" on other OSes, so this works.
23 var badPath = regexp.MustCompile(`[\\/:\*\?\"<>\|]`)
25 func stringify(stuff ...CacheKey) []string {
26 ret := make([]string, len(stuff))
27 for i := range stuff {
28 s := fmt.Sprint(stuff[i])
29 ret[i] = badPath.ReplaceAllLiteralString(s, "_")
34 // Each key but the last is treated as a directory.
35 // The last key is treated as a regular file.
37 // This also means that cache keys that are file-backed
38 // cannot have subkeys.
39 func (cd *CacheDir) cachePath(key ...CacheKey) string {
40 parts := append([]string{cd.GetCacheDir()}, stringify(key...)...)
41 p := filepath.Join(filterDots(parts...)...)
45 var invalidPath = []CacheKey{".invalid"}
47 // Returns the time the given key was marked as invalid.
48 // If the key is valid, then calling IsZero() on the returned
49 // time will return true.
50 func (cd *CacheDir) GetInvalid(key ...CacheKey) (ts time.Time) {
51 invKey := append(invalidPath, key...)
53 stat, _ := cd.Stat(invKey...)
57 // Checks if the given key is not marked as invalid, or if it is,
58 // checks if it was marked more than maxDuration time ago.
60 // Calls UnsetInvalid if the keys are valid.
61 func (cd *CacheDir) IsValid(maxDuration time.Duration, key ...CacheKey) bool {
62 ts := cd.GetInvalid(key...)
67 case time.Now().Sub(ts) > maxDuration:
68 cd.UnsetInvalid(key...)
75 // Deletes the given key and caches it as invalid.
76 func (cd *CacheDir) SetInvalid(key ...CacheKey) error {
77 invKey := append(invalidPath, key...)
80 return cd.Touch(invKey...)
83 // Removes the given key from the invalid key cache.
84 func (cd *CacheDir) UnsetInvalid(key ...CacheKey) error {
85 invKey := append(invalidPath, key...)
87 return cd.Delete(invKey...)