]> git.lizzy.rs Git - go-fscache.git/blob - cachekey.go
Replace obsolete lock package
[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 //
20 // NOTE: when running on Windows, directories that start with a '.' get the
21 // '.' replaced by a '_'. This is because regular Windows tools can't deal
22 // with directories starting with a dot.
23 type CacheKey interface{}
24
25 // All "bad characters" that can't go in Windows paths.
26 // It's a superset of the "bad characters" on other OSes, so this works.
27 var badPath = regexp.MustCompile(`[\\/:\*\?\"<>\|]`)
28
29 func Stringify(stuff ...CacheKey) []string {
30         ret := make([]string, len(stuff))
31         for i := range stuff {
32                 s := fmt.Sprint(stuff[i])
33                 ret[i] = badPath.ReplaceAllLiteralString(s, "_")
34         }
35         return ret
36 }
37
38 // Each key but the last is treated as a directory.
39 // The last key is treated as a regular file.
40 //
41 // This also means that cache keys that are file-backed
42 // cannot have subkeys.
43 func (cd *CacheDir) cachePath(key ...CacheKey) string {
44         parts := append([]string{cd.GetCacheDir()}, Stringify(key...)...)
45         p := filepath.Join(filterDots(parts...)...)
46         return p
47 }
48
49 var invalidPath = []CacheKey{".invalid"}
50
51 // Returns the time the given key was marked as invalid.
52 // If the key is valid, then calling IsZero() on the returned
53 // time will return true.
54 func (cd *CacheDir) GetInvalid(key ...CacheKey) (ts time.Time) {
55         invKey := append(invalidPath, key...)
56
57         if stat, err := cd.Stat(invKey...); err == nil {
58                 ts = stat.ModTime()
59         }
60         return
61 }
62
63 // Checks if the given key is not marked as invalid, or if it is,
64 // checks if it was marked more than maxDuration time ago.
65 //
66 // Calls UnsetInvalid if the keys are valid.
67 func (cd *CacheDir) IsValid(maxDuration time.Duration, key ...CacheKey) bool {
68         ts := cd.GetInvalid(key...)
69
70         switch {
71         case ts.IsZero():
72                 return true
73         case time.Now().Sub(ts) > maxDuration:
74                 cd.UnsetInvalid(key...)
75                 return true
76         default:
77                 return false
78         }
79 }
80
81 // Deletes the given key and caches it as invalid.
82 func (cd *CacheDir) SetInvalid(key ...CacheKey) error {
83         invKey := append(invalidPath, key...)
84
85         cd.Delete(key...)
86         return cd.Touch(invKey...)
87 }
88
89 // Removes the given key from the invalid key cache.
90 func (cd *CacheDir) UnsetInvalid(key ...CacheKey) error {
91         invKey := append(invalidPath, key...)
92
93         return cd.Delete(invKey...)
94 }