5
5
"crypto/sha1"
6
6
"encoding/hex"
7
7
"fmt"
8
- "io/fs"
9
8
"os"
10
- "path/filepath"
11
9
"runtime"
12
10
"time"
13
11
@@ -57,38 +55,38 @@ func Open(treeRoot string, clean bool, formatters map[string]*format.Formatter)
57
55
name := hex .EncodeToString (digest )
58
56
path , err := xdg .CacheFile (fmt .Sprintf ("treefmt/eval-cache/%v.db" , name ))
59
57
if err != nil {
60
- return fmt .Errorf ("%w: could not resolve local path for the cache" , err )
58
+ return fmt .Errorf ("could not resolve local path for the cache: %w " , err )
61
59
}
62
60
63
61
db , err = bolt .Open (path , 0o600 , nil )
64
62
if err != nil {
65
- return fmt .Errorf ("%w: failed to open cache" , err )
63
+ return fmt .Errorf ("failed to open cache at %v: %w" , path , err )
66
64
}
67
65
68
66
err = db .Update (func (tx * bolt.Tx ) error {
69
67
// create bucket for tracking paths
70
68
pathsBucket , err := tx .CreateBucketIfNotExists ([]byte (pathsBucket ))
71
69
if err != nil {
72
- return fmt .Errorf ("%w: failed to create paths bucket" , err )
70
+ return fmt .Errorf ("failed to create paths bucket: %w " , err )
73
71
}
74
72
75
73
// create bucket for tracking formatters
76
74
formattersBucket , err := tx .CreateBucketIfNotExists ([]byte (formattersBucket ))
77
75
if err != nil {
78
- return fmt .Errorf ("%w: failed to create formatters bucket" , err )
76
+ return fmt .Errorf ("failed to create formatters bucket: %w " , err )
79
77
}
80
78
81
79
// check for any newly configured or modified formatters
82
80
for name , formatter := range formatters {
83
81
84
82
stat , err := os .Lstat (formatter .Executable ())
85
83
if err != nil {
86
- return fmt .Errorf ("%w: failed to state formatter executable" , err )
84
+ return fmt .Errorf ("failed to stat formatter executable %v: %w" , formatter . Executable () , err )
87
85
}
88
86
89
87
entry , err := getEntry (formattersBucket , name )
90
88
if err != nil {
91
- return fmt .Errorf ("%w: failed to retrieve entry for formatter" , err )
89
+ return fmt .Errorf ("failed to retrieve cache entry for formatter %v: %w" , name , err )
92
90
}
93
91
94
92
clean = clean || entry == nil || ! (entry .Size == stat .Size () && entry .Modified == stat .ModTime ())
@@ -107,7 +105,7 @@ func Open(treeRoot string, clean bool, formatters map[string]*format.Formatter)
107
105
}
108
106
109
107
if err = putEntry (formattersBucket , name , entry ); err != nil {
110
- return fmt .Errorf ("%w: failed to write formatter entry" , err )
108
+ return fmt .Errorf ("failed to write cache entry for formatter %v: %w" , name , err )
111
109
}
112
110
}
113
111
@@ -117,22 +115,22 @@ func Open(treeRoot string, clean bool, formatters map[string]*format.Formatter)
117
115
if ! ok {
118
116
// remove the formatter entry from the cache
119
117
if err = formattersBucket .Delete (key ); err != nil {
120
- return fmt .Errorf ("%w: failed to remove formatter entry" , err )
118
+ return fmt .Errorf ("failed to remove cache entry for formatter %v: %w" , key , err )
121
119
}
122
120
// indicate a clean is required
123
121
clean = true
124
122
}
125
123
return nil
126
124
}); err != nil {
127
- return fmt .Errorf ("%w: failed to check for removed formatters" , err )
125
+ return fmt .Errorf ("failed to check cache for removed formatters: %w " , err )
128
126
}
129
127
130
128
if clean {
131
129
// remove all path entries
132
130
c := pathsBucket .Cursor ()
133
131
for k , v := c .First (); ! (k == nil && v == nil ); k , v = c .Next () {
134
132
if err = c .Delete (); err != nil {
135
- return fmt .Errorf ("%w: failed to remove path entry" , err )
133
+ return fmt .Errorf ("failed to remove path entry: %w " , err )
136
134
}
137
135
}
138
136
}
@@ -157,7 +155,7 @@ func getEntry(bucket *bolt.Bucket, path string) (*Entry, error) {
157
155
if b != nil {
158
156
var cached Entry
159
157
if err := msgpack .Unmarshal (b , & cached ); err != nil {
160
- return nil , fmt .Errorf ("%w: failed to unmarshal cache info for path '%v'" , err , path )
158
+ return nil , fmt .Errorf ("failed to unmarshal cache info for path '%v': %w " , path , err )
161
159
}
162
160
return & cached , nil
163
161
} else {
@@ -169,18 +167,18 @@ func getEntry(bucket *bolt.Bucket, path string) (*Entry, error) {
169
167
func putEntry (bucket * bolt.Bucket , path string , entry * Entry ) error {
170
168
bytes , err := msgpack .Marshal (entry )
171
169
if err != nil {
172
- return fmt .Errorf ("%w: failed to marshal cache entry" , err )
170
+ return fmt .Errorf ("failed to marshal cache path %v: %w" , path , err )
173
171
}
174
172
175
173
if err = bucket .Put ([]byte (path ), bytes ); err != nil {
176
- return fmt .Errorf ("%w: failed to put cache entry" , err )
174
+ return fmt .Errorf ("failed to put cache path %v: %w" , path , err )
177
175
}
178
176
return nil
179
177
}
180
178
181
179
// ChangeSet is used to walk a filesystem, starting at root, and outputting any new or changed paths using pathsCh.
182
180
// It determines if a path is new or has changed by comparing against cache entries.
183
- func ChangeSet (ctx context.Context , walker walk.Walker , pathsCh chan <- string ) error {
181
+ func ChangeSet (ctx context.Context , walker walk.Walker , filesCh chan <- * walk. File ) error {
184
182
start := time .Now ()
185
183
186
184
defer func () {
@@ -198,24 +196,21 @@ func ChangeSet(ctx context.Context, walker walk.Walker, pathsCh chan<- string) e
198
196
}
199
197
}()
200
198
201
- // for quick removal of tree root from paths
202
- relPathOffset := len (walker .Root ()) + 1
203
-
204
- return walker .Walk (ctx , func (path string , info fs.FileInfo , err error ) error {
199
+ return walker .Walk (ctx , func (file * walk.File , err error ) error {
205
200
select {
206
201
case <- ctx .Done ():
207
202
return ctx .Err ()
208
203
default :
209
204
if err != nil {
210
- return fmt .Errorf ("%w: failed to walk path" , err )
211
- } else if info .IsDir () {
205
+ return fmt .Errorf ("failed to walk path: %w " , err )
206
+ } else if file . Info .IsDir () {
212
207
// ignore directories
213
208
return nil
214
209
}
215
210
}
216
211
217
212
// ignore symlinks
218
- if info .Mode ()& os .ModeSymlink == os .ModeSymlink {
213
+ if file . Info .Mode ()& os .ModeSymlink == os .ModeSymlink {
219
214
return nil
220
215
}
221
216
@@ -224,18 +219,17 @@ func ChangeSet(ctx context.Context, walker walk.Walker, pathsCh chan<- string) e
224
219
if tx == nil {
225
220
tx , err = db .Begin (false )
226
221
if err != nil {
227
- return fmt .Errorf ("%w: failed to open a new read tx" , err )
222
+ return fmt .Errorf ("failed to open a new cache read tx: %w " , err )
228
223
}
229
224
bucket = tx .Bucket ([]byte (pathsBucket ))
230
225
}
231
226
232
- relPath := path [relPathOffset :]
233
- cached , err := getEntry (bucket , relPath )
227
+ cached , err := getEntry (bucket , file .RelPath )
234
228
if err != nil {
235
229
return err
236
230
}
237
231
238
- changedOrNew := cached == nil || ! (cached .Modified == info . ModTime () && cached .Size == info .Size ())
232
+ changedOrNew := cached == nil || ! (cached .Modified == file . Info . ModTime () && cached .Size == file . Info .Size ())
239
233
240
234
stats .Add (stats .Traversed , 1 )
241
235
if ! changedOrNew {
@@ -250,7 +244,7 @@ func ChangeSet(ctx context.Context, walker walk.Walker, pathsCh chan<- string) e
250
244
case <- ctx .Done ():
251
245
return ctx .Err ()
252
246
default :
253
- pathsCh <- relPath
247
+ filesCh <- file
254
248
}
255
249
256
250
// close the current tx if we have reached the batch size
@@ -266,47 +260,35 @@ func ChangeSet(ctx context.Context, walker walk.Walker, pathsCh chan<- string) e
266
260
}
267
261
268
262
// Update is used to record updated cache information for the specified list of paths.
269
- func Update (treeRoot string , paths [] string ) ( int , error ) {
263
+ func Update (files [] * walk. File ) error {
270
264
start := time .Now ()
271
265
defer func () {
272
- logger .Infof ("finished updating %v paths in %v" , len (paths ), time .Since (start ))
266
+ logger .Infof ("finished processing %v paths in %v" , len (files ), time .Since (start ))
273
267
}()
274
268
275
- if len (paths ) == 0 {
276
- return 0 , nil
269
+ if len (files ) == 0 {
270
+ return nil
277
271
}
278
272
279
- var changes int
280
-
281
- return changes , db .Update (func (tx * bolt.Tx ) error {
273
+ return db .Update (func (tx * bolt.Tx ) error {
282
274
bucket := tx .Bucket ([]byte (pathsBucket ))
283
275
284
- for _ , path := range paths {
285
- cached , err := getEntry (bucket , path )
286
- if err != nil {
287
- return err
288
- }
289
-
290
- pathInfo , err := os .Stat (filepath .Join (treeRoot , path ))
276
+ for _ , f := range files {
277
+ currentInfo , err := os .Stat (f .Path )
291
278
if err != nil {
292
279
return err
293
280
}
294
281
295
- if cached == nil || ! (cached .Modified == pathInfo .ModTime () && cached .Size == pathInfo .Size ()) {
296
- changes += 1
297
- } else {
298
- // no change to write
299
- continue
282
+ if ! (f .Info .ModTime () == currentInfo .ModTime () && f .Info .Size () == currentInfo .Size ()) {
283
+ stats .Add (stats .Formatted , 1 )
300
284
}
301
285
302
- stats .Add (stats .Formatted , 1 )
303
-
304
286
entry := Entry {
305
- Size : pathInfo .Size (),
306
- Modified : pathInfo .ModTime (),
287
+ Size : currentInfo .Size (),
288
+ Modified : currentInfo .ModTime (),
307
289
}
308
290
309
- if err = putEntry (bucket , path , & entry ); err != nil {
291
+ if err = putEntry (bucket , f . RelPath , & entry ); err != nil {
310
292
return err
311
293
}
312
294
}
0 commit comments