diff options
author | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
---|---|---|
committer | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
commit | 107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch) | |
tree | ca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/github.com/spf13/afero/cacheOnReadFs.go | |
parent | 844b5a68d8af4791755b8f0ad293cc99f5959183 (diff) | |
download | terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip |
Upgrade to 0.12
Diffstat (limited to 'vendor/github.com/spf13/afero/cacheOnReadFs.go')
-rw-r--r-- | vendor/github.com/spf13/afero/cacheOnReadFs.go | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/vendor/github.com/spf13/afero/cacheOnReadFs.go b/vendor/github.com/spf13/afero/cacheOnReadFs.go new file mode 100644 index 0000000..29a26c6 --- /dev/null +++ b/vendor/github.com/spf13/afero/cacheOnReadFs.go | |||
@@ -0,0 +1,290 @@ | |||
1 | package afero | ||
2 | |||
3 | import ( | ||
4 | "os" | ||
5 | "syscall" | ||
6 | "time" | ||
7 | ) | ||
8 | |||
9 | // If the cache duration is 0, cache time will be unlimited, i.e. once | ||
10 | // a file is in the layer, the base will never be read again for this file. | ||
11 | // | ||
12 | // For cache times greater than 0, the modification time of a file is | ||
13 | // checked. Note that a lot of file system implementations only allow a | ||
14 | // resolution of a second for timestamps... or as the godoc for os.Chtimes() | ||
15 | // states: "The underlying filesystem may truncate or round the values to a | ||
16 | // less precise time unit." | ||
17 | // | ||
18 | // This caching union will forward all write calls also to the base file | ||
19 | // system first. To prevent writing to the base Fs, wrap it in a read-only | ||
20 | // filter - Note: this will also make the overlay read-only, for writing files | ||
21 | // in the overlay, use the overlay Fs directly, not via the union Fs. | ||
22 | type CacheOnReadFs struct { | ||
23 | base Fs | ||
24 | layer Fs | ||
25 | cacheTime time.Duration | ||
26 | } | ||
27 | |||
28 | func NewCacheOnReadFs(base Fs, layer Fs, cacheTime time.Duration) Fs { | ||
29 | return &CacheOnReadFs{base: base, layer: layer, cacheTime: cacheTime} | ||
30 | } | ||
31 | |||
32 | type cacheState int | ||
33 | |||
34 | const ( | ||
35 | // not present in the overlay, unknown if it exists in the base: | ||
36 | cacheMiss cacheState = iota | ||
37 | // present in the overlay and in base, base file is newer: | ||
38 | cacheStale | ||
39 | // present in the overlay - with cache time == 0 it may exist in the base, | ||
40 | // with cacheTime > 0 it exists in the base and is same age or newer in the | ||
41 | // overlay | ||
42 | cacheHit | ||
43 | // happens if someone writes directly to the overlay without | ||
44 | // going through this union | ||
45 | cacheLocal | ||
46 | ) | ||
47 | |||
48 | func (u *CacheOnReadFs) cacheStatus(name string) (state cacheState, fi os.FileInfo, err error) { | ||
49 | var lfi, bfi os.FileInfo | ||
50 | lfi, err = u.layer.Stat(name) | ||
51 | if err == nil { | ||
52 | if u.cacheTime == 0 { | ||
53 | return cacheHit, lfi, nil | ||
54 | } | ||
55 | if lfi.ModTime().Add(u.cacheTime).Before(time.Now()) { | ||
56 | bfi, err = u.base.Stat(name) | ||
57 | if err != nil { | ||
58 | return cacheLocal, lfi, nil | ||
59 | } | ||
60 | if bfi.ModTime().After(lfi.ModTime()) { | ||
61 | return cacheStale, bfi, nil | ||
62 | } | ||
63 | } | ||
64 | return cacheHit, lfi, nil | ||
65 | } | ||
66 | |||
67 | if err == syscall.ENOENT || os.IsNotExist(err) { | ||
68 | return cacheMiss, nil, nil | ||
69 | } | ||
70 | |||
71 | return cacheMiss, nil, err | ||
72 | } | ||
73 | |||
74 | func (u *CacheOnReadFs) copyToLayer(name string) error { | ||
75 | return copyToLayer(u.base, u.layer, name) | ||
76 | } | ||
77 | |||
78 | func (u *CacheOnReadFs) Chtimes(name string, atime, mtime time.Time) error { | ||
79 | st, _, err := u.cacheStatus(name) | ||
80 | if err != nil { | ||
81 | return err | ||
82 | } | ||
83 | switch st { | ||
84 | case cacheLocal: | ||
85 | case cacheHit: | ||
86 | err = u.base.Chtimes(name, atime, mtime) | ||
87 | case cacheStale, cacheMiss: | ||
88 | if err := u.copyToLayer(name); err != nil { | ||
89 | return err | ||
90 | } | ||
91 | err = u.base.Chtimes(name, atime, mtime) | ||
92 | } | ||
93 | if err != nil { | ||
94 | return err | ||
95 | } | ||
96 | return u.layer.Chtimes(name, atime, mtime) | ||
97 | } | ||
98 | |||
99 | func (u *CacheOnReadFs) Chmod(name string, mode os.FileMode) error { | ||
100 | st, _, err := u.cacheStatus(name) | ||
101 | if err != nil { | ||
102 | return err | ||
103 | } | ||
104 | switch st { | ||
105 | case cacheLocal: | ||
106 | case cacheHit: | ||
107 | err = u.base.Chmod(name, mode) | ||
108 | case cacheStale, cacheMiss: | ||
109 | if err := u.copyToLayer(name); err != nil { | ||
110 | return err | ||
111 | } | ||
112 | err = u.base.Chmod(name, mode) | ||
113 | } | ||
114 | if err != nil { | ||
115 | return err | ||
116 | } | ||
117 | return u.layer.Chmod(name, mode) | ||
118 | } | ||
119 | |||
120 | func (u *CacheOnReadFs) Stat(name string) (os.FileInfo, error) { | ||
121 | st, fi, err := u.cacheStatus(name) | ||
122 | if err != nil { | ||
123 | return nil, err | ||
124 | } | ||
125 | switch st { | ||
126 | case cacheMiss: | ||
127 | return u.base.Stat(name) | ||
128 | default: // cacheStale has base, cacheHit and cacheLocal the layer os.FileInfo | ||
129 | return fi, nil | ||
130 | } | ||
131 | } | ||
132 | |||
133 | func (u *CacheOnReadFs) Rename(oldname, newname string) error { | ||
134 | st, _, err := u.cacheStatus(oldname) | ||
135 | if err != nil { | ||
136 | return err | ||
137 | } | ||
138 | switch st { | ||
139 | case cacheLocal: | ||
140 | case cacheHit: | ||
141 | err = u.base.Rename(oldname, newname) | ||
142 | case cacheStale, cacheMiss: | ||
143 | if err := u.copyToLayer(oldname); err != nil { | ||
144 | return err | ||
145 | } | ||
146 | err = u.base.Rename(oldname, newname) | ||
147 | } | ||
148 | if err != nil { | ||
149 | return err | ||
150 | } | ||
151 | return u.layer.Rename(oldname, newname) | ||
152 | } | ||
153 | |||
154 | func (u *CacheOnReadFs) Remove(name string) error { | ||
155 | st, _, err := u.cacheStatus(name) | ||
156 | if err != nil { | ||
157 | return err | ||
158 | } | ||
159 | switch st { | ||
160 | case cacheLocal: | ||
161 | case cacheHit, cacheStale, cacheMiss: | ||
162 | err = u.base.Remove(name) | ||
163 | } | ||
164 | if err != nil { | ||
165 | return err | ||
166 | } | ||
167 | return u.layer.Remove(name) | ||
168 | } | ||
169 | |||
170 | func (u *CacheOnReadFs) RemoveAll(name string) error { | ||
171 | st, _, err := u.cacheStatus(name) | ||
172 | if err != nil { | ||
173 | return err | ||
174 | } | ||
175 | switch st { | ||
176 | case cacheLocal: | ||
177 | case cacheHit, cacheStale, cacheMiss: | ||
178 | err = u.base.RemoveAll(name) | ||
179 | } | ||
180 | if err != nil { | ||
181 | return err | ||
182 | } | ||
183 | return u.layer.RemoveAll(name) | ||
184 | } | ||
185 | |||
186 | func (u *CacheOnReadFs) OpenFile(name string, flag int, perm os.FileMode) (File, error) { | ||
187 | st, _, err := u.cacheStatus(name) | ||
188 | if err != nil { | ||
189 | return nil, err | ||
190 | } | ||
191 | switch st { | ||
192 | case cacheLocal, cacheHit: | ||
193 | default: | ||
194 | if err := u.copyToLayer(name); err != nil { | ||
195 | return nil, err | ||
196 | } | ||
197 | } | ||
198 | if flag&(os.O_WRONLY|syscall.O_RDWR|os.O_APPEND|os.O_CREATE|os.O_TRUNC) != 0 { | ||
199 | bfi, err := u.base.OpenFile(name, flag, perm) | ||
200 | if err != nil { | ||
201 | return nil, err | ||
202 | } | ||
203 | lfi, err := u.layer.OpenFile(name, flag, perm) | ||
204 | if err != nil { | ||
205 | bfi.Close() // oops, what if O_TRUNC was set and file opening in the layer failed...? | ||
206 | return nil, err | ||
207 | } | ||
208 | return &UnionFile{Base: bfi, Layer: lfi}, nil | ||
209 | } | ||
210 | return u.layer.OpenFile(name, flag, perm) | ||
211 | } | ||
212 | |||
213 | func (u *CacheOnReadFs) Open(name string) (File, error) { | ||
214 | st, fi, err := u.cacheStatus(name) | ||
215 | if err != nil { | ||
216 | return nil, err | ||
217 | } | ||
218 | |||
219 | switch st { | ||
220 | case cacheLocal: | ||
221 | return u.layer.Open(name) | ||
222 | |||
223 | case cacheMiss: | ||
224 | bfi, err := u.base.Stat(name) | ||
225 | if err != nil { | ||
226 | return nil, err | ||
227 | } | ||
228 | if bfi.IsDir() { | ||
229 | return u.base.Open(name) | ||
230 | } | ||
231 | if err := u.copyToLayer(name); err != nil { | ||
232 | return nil, err | ||
233 | } | ||
234 | return u.layer.Open(name) | ||
235 | |||
236 | case cacheStale: | ||
237 | if !fi.IsDir() { | ||
238 | if err := u.copyToLayer(name); err != nil { | ||
239 | return nil, err | ||
240 | } | ||
241 | return u.layer.Open(name) | ||
242 | } | ||
243 | case cacheHit: | ||
244 | if !fi.IsDir() { | ||
245 | return u.layer.Open(name) | ||
246 | } | ||
247 | } | ||
248 | // the dirs from cacheHit, cacheStale fall down here: | ||
249 | bfile, _ := u.base.Open(name) | ||
250 | lfile, err := u.layer.Open(name) | ||
251 | if err != nil && bfile == nil { | ||
252 | return nil, err | ||
253 | } | ||
254 | return &UnionFile{Base: bfile, Layer: lfile}, nil | ||
255 | } | ||
256 | |||
257 | func (u *CacheOnReadFs) Mkdir(name string, perm os.FileMode) error { | ||
258 | err := u.base.Mkdir(name, perm) | ||
259 | if err != nil { | ||
260 | return err | ||
261 | } | ||
262 | return u.layer.MkdirAll(name, perm) // yes, MkdirAll... we cannot assume it exists in the cache | ||
263 | } | ||
264 | |||
265 | func (u *CacheOnReadFs) Name() string { | ||
266 | return "CacheOnReadFs" | ||
267 | } | ||
268 | |||
269 | func (u *CacheOnReadFs) MkdirAll(name string, perm os.FileMode) error { | ||
270 | err := u.base.MkdirAll(name, perm) | ||
271 | if err != nil { | ||
272 | return err | ||
273 | } | ||
274 | return u.layer.MkdirAll(name, perm) | ||
275 | } | ||
276 | |||
277 | func (u *CacheOnReadFs) Create(name string) (File, error) { | ||
278 | bfh, err := u.base.Create(name) | ||
279 | if err != nil { | ||
280 | return nil, err | ||
281 | } | ||
282 | lfh, err := u.layer.Create(name) | ||
283 | if err != nil { | ||
284 | // oops, see comment about OS_TRUNC above, should we remove? then we have to | ||
285 | // remember if the file did not exist before | ||
286 | bfh.Close() | ||
287 | return nil, err | ||
288 | } | ||
289 | return &UnionFile{Base: bfh, Layer: lfh}, nil | ||
290 | } | ||