improve caching and tracking #34
30
cache/cache.go
vendored
30
cache/cache.go
vendored
@ -55,25 +55,25 @@ func Open(treeRoot string, clean bool, formatters map[string]*format.Formatter)
|
|||||||
name := hex.EncodeToString(digest)
|
name := hex.EncodeToString(digest)
|
||||||
path, err := xdg.CacheFile(fmt.Sprintf("treefmt/eval-cache/%v.db", name))
|
path, err := xdg.CacheFile(fmt.Sprintf("treefmt/eval-cache/%v.db", name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: could not resolve local path for the cache", err)
|
return fmt.Errorf("could not resolve local path for the cache: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err = bolt.Open(path, 0o600, nil)
|
db, err = bolt.Open(path, 0o600, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to open cache", err)
|
return fmt.Errorf("failed to open cache at %v: %w", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = db.Update(func(tx *bolt.Tx) error {
|
err = db.Update(func(tx *bolt.Tx) error {
|
||||||
// create bucket for tracking paths
|
// create bucket for tracking paths
|
||||||
pathsBucket, err := tx.CreateBucketIfNotExists([]byte(pathsBucket))
|
pathsBucket, err := tx.CreateBucketIfNotExists([]byte(pathsBucket))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to create paths bucket", err)
|
return fmt.Errorf("failed to create paths bucket: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create bucket for tracking formatters
|
// create bucket for tracking formatters
|
||||||
formattersBucket, err := tx.CreateBucketIfNotExists([]byte(formattersBucket))
|
formattersBucket, err := tx.CreateBucketIfNotExists([]byte(formattersBucket))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to create formatters bucket", err)
|
return fmt.Errorf("failed to create formatters bucket: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for any newly configured or modified formatters
|
// check for any newly configured or modified formatters
|
||||||
@ -81,12 +81,12 @@ func Open(treeRoot string, clean bool, formatters map[string]*format.Formatter)
|
|||||||
|
|
||||||
stat, err := os.Lstat(formatter.Executable())
|
stat, err := os.Lstat(formatter.Executable())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to state formatter executable", err)
|
return fmt.Errorf("failed to stat formatter executable %v: %w", formatter.Executable(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
entry, err := getEntry(formattersBucket, name)
|
entry, err := getEntry(formattersBucket, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to retrieve entry for formatter", err)
|
return fmt.Errorf("failed to retrieve cache entry for formatter %v: %w", name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
clean = clean || entry == nil || !(entry.Size == stat.Size() && entry.Modified == stat.ModTime())
|
clean = clean || entry == nil || !(entry.Size == stat.Size() && entry.Modified == stat.ModTime())
|
||||||
@ -105,7 +105,7 @@ func Open(treeRoot string, clean bool, formatters map[string]*format.Formatter)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = putEntry(formattersBucket, name, entry); err != nil {
|
if err = putEntry(formattersBucket, name, entry); err != nil {
|
||||||
return fmt.Errorf("%w: failed to write formatter entry", err)
|
return fmt.Errorf("failed to write cache entry for formatter %v: %w", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,14 +115,14 @@ func Open(treeRoot string, clean bool, formatters map[string]*format.Formatter)
|
|||||||
if !ok {
|
if !ok {
|
||||||
// remove the formatter entry from the cache
|
// remove the formatter entry from the cache
|
||||||
if err = formattersBucket.Delete(key); err != nil {
|
if err = formattersBucket.Delete(key); err != nil {
|
||||||
return fmt.Errorf("%w: failed to remove formatter entry", err)
|
return fmt.Errorf("failed to remove cache entry for formatter %v: %w", key, err)
|
||||||
}
|
}
|
||||||
// indicate a clean is required
|
// indicate a clean is required
|
||||||
clean = true
|
clean = true
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("%w: failed to check for removed formatters", err)
|
return fmt.Errorf("failed to check cache for removed formatters: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if clean {
|
if clean {
|
||||||
@ -130,7 +130,7 @@ func Open(treeRoot string, clean bool, formatters map[string]*format.Formatter)
|
|||||||
c := pathsBucket.Cursor()
|
c := pathsBucket.Cursor()
|
||||||
for k, v := c.First(); !(k == nil && v == nil); k, v = c.Next() {
|
for k, v := c.First(); !(k == nil && v == nil); k, v = c.Next() {
|
||||||
if err = c.Delete(); err != nil {
|
if err = c.Delete(); err != nil {
|
||||||
return fmt.Errorf("%w: failed to remove path entry", err)
|
return fmt.Errorf("failed to remove path entry: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,7 +155,7 @@ func getEntry(bucket *bolt.Bucket, path string) (*Entry, error) {
|
|||||||
if b != nil {
|
if b != nil {
|
||||||
var cached Entry
|
var cached Entry
|
||||||
if err := msgpack.Unmarshal(b, &cached); err != nil {
|
if err := msgpack.Unmarshal(b, &cached); err != nil {
|
||||||
return nil, fmt.Errorf("%w: failed to unmarshal cache info for path '%v'", err, path)
|
return nil, fmt.Errorf("failed to unmarshal cache info for path '%v': %w", path, err)
|
||||||
}
|
}
|
||||||
return &cached, nil
|
return &cached, nil
|
||||||
} else {
|
} else {
|
||||||
@ -167,11 +167,11 @@ func getEntry(bucket *bolt.Bucket, path string) (*Entry, error) {
|
|||||||
func putEntry(bucket *bolt.Bucket, path string, entry *Entry) error {
|
func putEntry(bucket *bolt.Bucket, path string, entry *Entry) error {
|
||||||
bytes, err := msgpack.Marshal(entry)
|
bytes, err := msgpack.Marshal(entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to marshal cache entry", err)
|
return fmt.Errorf("failed to marshal cache path %v: %w", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = bucket.Put([]byte(path), bytes); err != nil {
|
if err = bucket.Put([]byte(path), bytes); err != nil {
|
||||||
return fmt.Errorf("%w: failed to put cache entry", err)
|
return fmt.Errorf("failed to put cache path %v: %w", path, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -202,7 +202,7 @@ func ChangeSet(ctx context.Context, walker walk.Walker, filesCh chan<- *walk.Fil
|
|||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
default:
|
default:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to walk path", err)
|
return fmt.Errorf("failed to walk path: %w", err)
|
||||||
} else if file.Info.IsDir() {
|
} else if file.Info.IsDir() {
|
||||||
// ignore directories
|
// ignore directories
|
||||||
return nil
|
return nil
|
||||||
@ -219,7 +219,7 @@ func ChangeSet(ctx context.Context, walker walk.Walker, filesCh chan<- *walk.Fil
|
|||||||
if tx == nil {
|
if tx == nil {
|
||||||
tx, err = db.Begin(false)
|
tx, err = db.Begin(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to open a new read tx", err)
|
return fmt.Errorf("failed to open a new cache read tx: %w", err)
|
||||||
}
|
}
|
||||||
bucket = tx.Bucket([]byte(pathsBucket))
|
bucket = tx.Bucket([]byte(pathsBucket))
|
||||||
}
|
}
|
||||||
|
@ -52,12 +52,12 @@ func (f *Format) Run() (err error) {
|
|||||||
// read config
|
// read config
|
||||||
cfg, err := config.ReadFile(Cli.ConfigFile, Cli.Formatters)
|
cfg, err := config.ReadFile(Cli.ConfigFile, Cli.Formatters)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to read config file", err)
|
return fmt.Errorf("failed to read config file %v: %w", Cli.ConfigFile, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// compile global exclude globs
|
// compile global exclude globs
|
||||||
if globalExcludes, err = format.CompileGlobs(cfg.Global.Excludes); err != nil {
|
if globalExcludes, err = format.CompileGlobs(cfg.Global.Excludes); err != nil {
|
||||||
return fmt.Errorf("%w: failed to compile global globs", err)
|
return fmt.Errorf("failed to compile global excludes: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialise pipelines
|
// initialise pipelines
|
||||||
|
@ -57,12 +57,12 @@ func cmd(t *testing.T, args ...string) ([]byte, error) {
|
|||||||
|
|
||||||
// reset and read the temporary output
|
// reset and read the temporary output
|
||||||
if _, err = tempOut.Seek(0, 0); err != nil {
|
if _, err = tempOut.Seek(0, 0); err != nil {
|
||||||
return nil, fmt.Errorf("%w: failed to reset temp output for reading", err)
|
return nil, fmt.Errorf("failed to reset temp output for reading: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := io.ReadAll(tempOut)
|
out, err := io.ReadAll(tempOut)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: failed to read temp output", err)
|
return nil, fmt.Errorf("failed to read temp output: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// swap outputs back
|
// swap outputs back
|
||||||
|
@ -87,7 +87,7 @@ func (f *Formatter) Apply(ctx context.Context, files []*walk.File, filter bool)
|
|||||||
if len(out) > 0 {
|
if len(out) > 0 {
|
||||||
_, _ = fmt.Fprintf(os.Stderr, "%s error:\n%s\n", f.name, out)
|
_, _ = fmt.Fprintf(os.Stderr, "%s error:\n%s\n", f.name, out)
|
||||||
}
|
}
|
||||||
return fmt.Errorf("%w: formatter %s failed to apply", err, f.name)
|
return fmt.Errorf("formatter %s failed to apply: %w", f.name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -141,12 +141,12 @@ func NewFormatter(
|
|||||||
|
|
||||||
f.includes, err = CompileGlobs(cfg.Includes)
|
f.includes, err = CompileGlobs(cfg.Includes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: formatter '%v' includes", err, f.name)
|
return nil, fmt.Errorf("failed to compile formatter '%v' includes: %w", f.name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
f.excludes, err = CompileGlobs(cfg.Excludes)
|
f.excludes, err = CompileGlobs(cfg.Excludes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: formatter '%v' excludes", err, f.name)
|
return nil, fmt.Errorf("failed to compile formatter '%v' excludes: %w", f.name, err)
|
||||||
}
|
}
|
||||||
f.excludes = append(f.excludes, globalExcludes...)
|
f.excludes = append(f.excludes, globalExcludes...)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ func CompileGlobs(patterns []string) ([]glob.Glob, error) {
|
|||||||
for i, pattern := range patterns {
|
for i, pattern := range patterns {
|
||||||
g, err := glob.Compile(pattern)
|
g, err := glob.Compile(pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: failed to compile include pattern '%v'", err, pattern)
|
return nil, fmt.Errorf("failed to compile include pattern '%v': %w", pattern, err)
|
||||||
}
|
}
|
||||||
globs[i] = g
|
globs[i] = g
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ func (g *gitWalker) Walk(ctx context.Context, fn WalkFunc) error {
|
|||||||
|
|
||||||
idx, err := g.repo.Storer.Index()
|
idx, err := g.repo.Storer.Index()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("%w: failed to open index", err)
|
return fmt.Errorf("failed to open git index: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(g.paths) > 0 {
|
if len(g.paths) > 0 {
|
||||||
@ -102,7 +102,7 @@ func (g *gitWalker) Walk(ctx context.Context, fn WalkFunc) error {
|
|||||||
func NewGit(root string, paths []string) (Walker, error) {
|
func NewGit(root string, paths []string) (Walker, error) {
|
||||||
repo, err := git.PlainOpen(root)
|
repo, err := git.PlainOpen(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%w: failed to open git repo", err)
|
return nil, fmt.Errorf("failed to open git repo: %w", err)
|
||||||
}
|
}
|
||||||
return &gitWalker{root, paths, repo}, nil
|
return &gitWalker{root, paths, repo}, nil
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user