]> git.lizzy.rs Git - go-fscache.git/blob - cachekey.go
Initial commit
[go-fscache.git] / cachekey.go
1 package fscache
2
3 import (
4         "fmt"
5         "path/filepath"
6         "regexp"
7         "time"
8 )
9
10 // An arbitrary object that can be stringified by fmt.Sprint().
11 //
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 _.
15 //
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{}
20
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(`[\\/:\*\?\"<>\|]`)
24
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, "_")
30         }
31         return ret
32 }
33
34 // Each key but the last is treated as a directory.
35 // The last key is treated as a regular file.
36 //
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...)...)
42         return p
43 }
44
45 var invalidPath = []CacheKey{".invalid"}
46
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...)
52
53         stat, _ := cd.Stat(invKey...)
54         return stat.ModTime()
55 }
56
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.
59 //
60 // Calls UnsetInvalid if the keys are valid.
61 func (cd *CacheDir) IsValid(maxDuration time.Duration, key ...CacheKey) bool {
62         ts := cd.GetInvalid(key...)
63
64         switch {
65         case ts.IsZero():
66                 return true
67         case time.Now().Sub(ts) > maxDuration:
68                 cd.UnsetInvalid(key...)
69                 return true
70         default:
71                 return false
72         }
73 }
74
75 // Deletes the given key and caches it as invalid.
76 func (cd *CacheDir) SetInvalid(key ...CacheKey) error {
77         invKey := append(invalidPath, key...)
78
79         cd.Delete(key...)
80         return cd.Touch(invKey...)
81 }
82
83 // Removes the given key from the invalid key cache.
84 func (cd *CacheDir) UnsetInvalid(key ...CacheKey) error {
85         invKey := append(invalidPath, key...)
86
87         return cd.Delete(invKey...)
88 }