2023-12-23 15:50:47 +03:00
|
|
|
package cli
|
|
|
|
|
|
|
|
import (
|
2024-01-10 18:45:57 +03:00
|
|
|
"bufio"
|
2023-12-23 15:50:47 +03:00
|
|
|
"context"
|
2024-01-03 11:08:57 +03:00
|
|
|
"errors"
|
2023-12-23 15:50:47 +03:00
|
|
|
"fmt"
|
2023-12-26 13:11:32 +03:00
|
|
|
"os"
|
|
|
|
"os/signal"
|
2024-04-25 14:16:04 +03:00
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
2024-05-06 18:05:10 +03:00
|
|
|
"runtime/pprof"
|
2024-04-25 14:16:04 +03:00
|
|
|
"strings"
|
2023-12-26 13:11:32 +03:00
|
|
|
"syscall"
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
"git.numtide.com/numtide/treefmt/format"
|
2024-05-01 13:15:39 +03:00
|
|
|
"git.numtide.com/numtide/treefmt/stats"
|
2024-04-19 12:57:41 +03:00
|
|
|
"github.com/gobwas/glob"
|
|
|
|
|
2024-02-15 12:20:01 +03:00
|
|
|
"git.numtide.com/numtide/treefmt/cache"
|
|
|
|
"git.numtide.com/numtide/treefmt/config"
|
|
|
|
"git.numtide.com/numtide/treefmt/walk"
|
2023-12-23 15:50:47 +03:00
|
|
|
|
|
|
|
"github.com/charmbracelet/log"
|
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
)
|
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
const (
|
|
|
|
BatchSize = 1024
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
globalExcludes []glob.Glob
|
|
|
|
formatters map[string]*format.Formatter
|
|
|
|
pipelines map[string]*format.Pipeline
|
2024-05-01 21:03:26 +03:00
|
|
|
filesCh chan *walk.File
|
|
|
|
processedCh chan *walk.File
|
2024-04-19 12:57:41 +03:00
|
|
|
|
|
|
|
ErrFailOnChange = errors.New("unexpected changes detected, --fail-on-change is enabled")
|
|
|
|
)
|
2024-01-03 16:10:54 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
func (f *Format) Run() (err error) {
|
2024-05-06 18:05:10 +03:00
|
|
|
// cpu profiling
|
|
|
|
if Cli.CpuProfile != "" {
|
|
|
|
cpuProfile, err := os.Create(Cli.CpuProfile)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to open file for writing cpu profile: %w", err)
|
|
|
|
} else if err = pprof.StartCPUProfile(cpuProfile); err != nil {
|
|
|
|
return fmt.Errorf("failed to start cpu profile: %w", err)
|
|
|
|
}
|
|
|
|
defer func() {
|
|
|
|
pprof.StopCPUProfile()
|
|
|
|
if err := cpuProfile.Close(); err != nil {
|
|
|
|
log.Errorf("failed to close cpu profile: %v", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2024-05-02 12:56:32 +03:00
|
|
|
// create a prefixed logger
|
2023-12-23 15:50:47 +03:00
|
|
|
l := log.WithPrefix("format")
|
|
|
|
|
2024-05-02 12:56:32 +03:00
|
|
|
// ensure cache is closed on return
|
2023-12-23 15:50:47 +03:00
|
|
|
defer func() {
|
|
|
|
if err := cache.Close(); err != nil {
|
|
|
|
l.Errorf("failed to close cache: %v", err)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
// read config
|
2024-05-02 12:56:32 +03:00
|
|
|
cfg, err := config.ReadFile(Cli.ConfigFile, Cli.Formatters)
|
2023-12-23 15:50:47 +03:00
|
|
|
if err != nil {
|
2024-05-02 13:40:49 +03:00
|
|
|
return fmt.Errorf("failed to read config file %v: %w", Cli.ConfigFile, err)
|
2023-12-23 15:50:47 +03:00
|
|
|
}
|
|
|
|
|
2024-05-02 12:56:32 +03:00
|
|
|
// compile global exclude globs
|
2024-04-19 12:57:41 +03:00
|
|
|
if globalExcludes, err = format.CompileGlobs(cfg.Global.Excludes); err != nil {
|
2024-05-02 13:40:49 +03:00
|
|
|
return fmt.Errorf("failed to compile global excludes: %w", err)
|
2023-12-25 15:26:18 +03:00
|
|
|
}
|
|
|
|
|
2024-05-02 12:56:32 +03:00
|
|
|
// initialise pipelines
|
2024-04-19 12:57:41 +03:00
|
|
|
pipelines = make(map[string]*format.Pipeline)
|
|
|
|
formatters = make(map[string]*format.Formatter)
|
2024-01-12 14:46:04 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// iterate the formatters in lexicographical order
|
2024-05-02 12:56:32 +03:00
|
|
|
for _, name := range cfg.Names {
|
2024-05-02 13:28:22 +03:00
|
|
|
// init formatter
|
2024-04-26 12:27:11 +03:00
|
|
|
formatterCfg := cfg.Formatters[name]
|
2024-04-25 14:16:04 +03:00
|
|
|
formatter, err := format.NewFormatter(name, Cli.TreeRoot, formatterCfg, globalExcludes)
|
2024-04-19 12:57:41 +03:00
|
|
|
if errors.Is(err, format.ErrCommandNotFound) && Cli.AllowMissingFormatter {
|
2023-12-23 18:00:39 +03:00
|
|
|
l.Debugf("formatter not found: %v", name)
|
2024-01-12 14:46:04 +03:00
|
|
|
continue
|
2023-12-23 18:00:39 +03:00
|
|
|
} else if err != nil {
|
2024-01-02 13:33:50 +03:00
|
|
|
return fmt.Errorf("%w: failed to initialise formatter: %v", err, name)
|
2023-12-23 15:50:47 +03:00
|
|
|
}
|
2024-01-12 14:46:04 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// store formatter by name
|
2024-01-12 14:46:04 +03:00
|
|
|
formatters[name] = formatter
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// If no pipeline is configured, we add the formatter to a nominal pipeline of size 1 with the key being the
|
|
|
|
// formatter's name. If a pipeline is configured, we add the formatter to a pipeline keyed by
|
|
|
|
// 'p:<pipeline_name>' in which it is sorted by priority.
|
2024-04-19 12:57:41 +03:00
|
|
|
if formatterCfg.Pipeline == "" {
|
|
|
|
pipeline := format.Pipeline{}
|
|
|
|
pipeline.Add(formatter)
|
|
|
|
pipelines[name] = &pipeline
|
|
|
|
} else {
|
|
|
|
key := fmt.Sprintf("p:%s", formatterCfg.Pipeline)
|
|
|
|
pipeline, ok := pipelines[key]
|
2024-01-12 14:46:04 +03:00
|
|
|
if !ok {
|
2024-04-19 12:57:41 +03:00
|
|
|
pipeline = &format.Pipeline{}
|
|
|
|
pipelines[key] = pipeline
|
2024-01-12 14:46:04 +03:00
|
|
|
}
|
2024-04-19 12:57:41 +03:00
|
|
|
pipeline.Add(formatter)
|
2024-01-12 14:46:04 +03:00
|
|
|
}
|
|
|
|
}
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
// open the cache
|
2024-01-12 14:46:04 +03:00
|
|
|
if err = cache.Open(Cli.TreeRoot, Cli.ClearCache, formatters); err != nil {
|
2023-12-23 15:50:47 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
// create an app context and listen for shutdown
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
go func() {
|
|
|
|
exit := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(exit, os.Interrupt, syscall.SIGTERM)
|
|
|
|
<-exit
|
|
|
|
cancel()
|
|
|
|
}()
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-05-02 12:56:32 +03:00
|
|
|
// initialise stats collection
|
|
|
|
stats.Init()
|
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// create an overall error group for executing high level tasks concurrently
|
2023-12-23 15:50:47 +03:00
|
|
|
eg, ctx := errgroup.WithContext(ctx)
|
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// create a channel for files needing to be processed
|
|
|
|
// we use a multiple of batch size here as a rudimentary concurrency optimization based on the host machine
|
2024-05-01 21:03:26 +03:00
|
|
|
filesCh = make(chan *walk.File, BatchSize*runtime.NumCPU())
|
2024-04-19 12:57:41 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// create a channel for files that have been processed
|
2024-05-01 21:03:26 +03:00
|
|
|
processedCh = make(chan *walk.File, cap(filesCh))
|
2024-04-19 12:57:41 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// start concurrent processing tasks in reverse order
|
2024-04-19 12:57:41 +03:00
|
|
|
eg.Go(updateCache(ctx))
|
|
|
|
eg.Go(applyFormatters(ctx))
|
|
|
|
eg.Go(walkFilesystem(ctx))
|
|
|
|
|
|
|
|
// wait for everything to complete
|
|
|
|
return eg.Wait()
|
|
|
|
}
|
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
func updateCache(ctx context.Context) func() error {
|
|
|
|
return func() error {
|
|
|
|
// used to batch updates for more efficient txs
|
|
|
|
batch := make([]*walk.File, 0, BatchSize)
|
|
|
|
|
|
|
|
// apply a batch
|
|
|
|
processBatch := func() error {
|
|
|
|
if err := cache.Update(batch); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
batch = batch[:0]
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
LOOP:
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
// detect ctx cancellation
|
|
|
|
case <-ctx.Done():
|
|
|
|
return ctx.Err()
|
|
|
|
// respond to processed files
|
|
|
|
case file, ok := <-processedCh:
|
|
|
|
if !ok {
|
|
|
|
// channel has been closed, no further files to process
|
|
|
|
break LOOP
|
|
|
|
}
|
|
|
|
// append to batch and process if we have enough
|
|
|
|
batch = append(batch, file)
|
|
|
|
if len(batch) == BatchSize {
|
|
|
|
if err := processBatch(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// final flush
|
|
|
|
if err := processBatch(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// if fail on change has been enabled, check that no files were actually formatted, throwing an error if so
|
|
|
|
if Cli.FailOnChange && stats.Value(stats.Formatted) != 0 {
|
|
|
|
return ErrFailOnChange
|
|
|
|
}
|
|
|
|
|
|
|
|
// print stats to stdout
|
|
|
|
stats.Print()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
func walkFilesystem(ctx context.Context) func() error {
|
|
|
|
return func() error {
|
2024-05-03 22:55:29 +03:00
|
|
|
eg, ctx := errgroup.WithContext(ctx)
|
|
|
|
pathsCh := make(chan string, BatchSize)
|
|
|
|
|
|
|
|
walkPaths := func() error {
|
|
|
|
defer close(pathsCh)
|
|
|
|
|
|
|
|
var idx int
|
|
|
|
for idx < len(Cli.Paths) {
|
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return ctx.Err()
|
|
|
|
default:
|
|
|
|
pathsCh <- Cli.Paths[idx]
|
|
|
|
idx += 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2024-04-19 12:57:41 +03:00
|
|
|
|
2024-05-03 22:55:29 +03:00
|
|
|
walkStdin := func() error {
|
|
|
|
defer close(pathsCh)
|
2024-04-25 14:16:04 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// determine the current working directory
|
2024-04-25 14:16:04 +03:00
|
|
|
cwd, err := os.Getwd()
|
|
|
|
if err != nil {
|
2024-05-02 13:28:22 +03:00
|
|
|
return fmt.Errorf("failed to determine current working directory: %w", err)
|
2024-04-25 14:16:04 +03:00
|
|
|
}
|
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
// read in all the paths
|
|
|
|
scanner := bufio.NewScanner(os.Stdin)
|
2024-05-03 22:55:29 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
for scanner.Scan() {
|
2024-05-03 22:55:29 +03:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return ctx.Err()
|
|
|
|
default:
|
|
|
|
path := scanner.Text()
|
|
|
|
if !strings.HasPrefix(path, "/") {
|
|
|
|
// append the cwd
|
|
|
|
path = filepath.Join(cwd, path)
|
|
|
|
}
|
|
|
|
pathsCh <- path
|
2024-04-25 14:16:04 +03:00
|
|
|
}
|
2024-04-19 12:57:41 +03:00
|
|
|
}
|
2024-05-03 22:55:29 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(Cli.Paths) > 0 {
|
|
|
|
eg.Go(walkPaths)
|
|
|
|
} else if Cli.Stdin {
|
|
|
|
eg.Go(walkStdin)
|
|
|
|
} else {
|
|
|
|
// no explicit paths to process, so we only need to process root
|
|
|
|
pathsCh <- Cli.TreeRoot
|
|
|
|
close(pathsCh)
|
2024-04-19 12:57:41 +03:00
|
|
|
}
|
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// create a filesystem walker
|
2024-05-03 22:55:29 +03:00
|
|
|
walker, err := walk.New(Cli.Walk, Cli.TreeRoot, pathsCh)
|
2024-04-19 12:57:41 +03:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to create walker: %w", err)
|
|
|
|
}
|
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// close the files channel when we're done walking the file system
|
2024-05-01 21:03:26 +03:00
|
|
|
defer close(filesCh)
|
2024-04-19 12:57:41 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// if no cache has been configured, we invoke the walker directly
|
2024-04-19 12:57:41 +03:00
|
|
|
if Cli.NoCache {
|
2024-05-01 21:03:26 +03:00
|
|
|
return walker.Walk(ctx, func(file *walk.File, err error) error {
|
2024-04-19 12:57:41 +03:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
|
|
|
return ctx.Err()
|
|
|
|
default:
|
|
|
|
// ignore symlinks and directories
|
2024-05-01 21:03:26 +03:00
|
|
|
if !(file.Info.IsDir() || file.Info.Mode()&os.ModeSymlink == os.ModeSymlink) {
|
2024-05-01 13:15:39 +03:00
|
|
|
stats.Add(stats.Traversed, 1)
|
|
|
|
stats.Add(stats.Emitted, 1)
|
2024-05-01 21:03:26 +03:00
|
|
|
filesCh <- file
|
2024-04-19 12:57:41 +03:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// otherwise we pass the walker to the cache and have it generate files for processing based on whether or not
|
|
|
|
// they have been added/changed since the last invocation
|
2024-05-01 21:03:26 +03:00
|
|
|
if err = cache.ChangeSet(ctx, walker, filesCh); err != nil {
|
2024-04-19 12:57:41 +03:00
|
|
|
return fmt.Errorf("failed to generate change set: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
func applyFormatters(ctx context.Context) func() error {
|
2024-05-02 13:28:22 +03:00
|
|
|
// create our own errgroup for concurrent formatting tasks
|
2024-04-19 12:57:41 +03:00
|
|
|
fg, ctx := errgroup.WithContext(ctx)
|
2024-05-02 13:28:22 +03:00
|
|
|
|
|
|
|
// pre-initialise batches keyed by pipeline
|
2024-05-01 21:03:26 +03:00
|
|
|
batches := make(map[string][]*walk.File)
|
2024-05-02 13:28:22 +03:00
|
|
|
for key := range pipelines {
|
|
|
|
batches[key] = make([]*walk.File, 0, BatchSize)
|
|
|
|
}
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// for a given pipeline key, add the provided file to the current batch and trigger a format if the batch size has
|
|
|
|
// been reached
|
2024-05-01 21:03:26 +03:00
|
|
|
tryApply := func(key string, file *walk.File) {
|
2024-05-02 13:28:22 +03:00
|
|
|
// append to batch
|
|
|
|
batches[key] = append(batches[key], file)
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// check if the batch is full
|
|
|
|
batch := batches[key]
|
2024-04-19 12:57:41 +03:00
|
|
|
if len(batch) == BatchSize {
|
2024-05-02 13:28:22 +03:00
|
|
|
// get the pipeline
|
2024-04-19 12:57:41 +03:00
|
|
|
pipeline := pipelines[key]
|
2024-01-12 14:46:04 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
// copy the batch
|
2024-05-01 21:03:26 +03:00
|
|
|
files := make([]*walk.File, len(batch))
|
|
|
|
copy(files, batch)
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// apply to the pipeline
|
2024-04-19 12:57:41 +03:00
|
|
|
fg.Go(func() error {
|
2024-05-01 21:03:26 +03:00
|
|
|
if err := pipeline.Apply(ctx, files); err != nil {
|
2024-04-19 12:57:41 +03:00
|
|
|
return err
|
|
|
|
}
|
2024-05-01 21:03:26 +03:00
|
|
|
for _, path := range files {
|
2024-04-19 12:57:41 +03:00
|
|
|
processedCh <- path
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2024-01-10 18:45:57 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// reset the batch
|
2024-04-19 12:57:41 +03:00
|
|
|
batches[key] = batch[:0]
|
2024-01-10 18:45:57 +03:00
|
|
|
}
|
2024-04-19 12:57:41 +03:00
|
|
|
}
|
2024-01-10 18:45:57 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// format any partial batches
|
2024-04-19 12:57:41 +03:00
|
|
|
flushBatches := func() {
|
|
|
|
for key, pipeline := range pipelines {
|
2024-01-10 18:45:57 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
batch := batches[key]
|
|
|
|
pipeline := pipeline // capture for closure
|
feat: support --no-cache
Signed-off-by: Brian McGee <brian@bmcgee.ie>
diff --git a/cli/cli.go b/cli/cli.go
index 8b23262..b370ee7 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -11,6 +11,7 @@ var Cli = Format{}
type Format struct {
AllowMissingFormatter bool `default:"false" help:"Do not exit with error if a configured formatter is missing"`
WorkingDirectory kong.ChangeDirFlag `default:"." short:"C" help:"Run as if treefmt was started in the specified working directory instead of the current working directory"`
+ NoCache bool `help:"Ignore the evaluation cache entirely. Useful for CI"`
ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough"`
ConfigFile string `type:"existingfile" default:"./treefmt.toml"`
FailOnChange bool `help:"Exit with error if any changes were made. Useful for CI."`
diff --git a/cli/format.go b/cli/format.go
index 6c46096..14ac16c 100644
--- a/cli/format.go
+++ b/cli/format.go
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
+ "io/fs"
"os"
"os/signal"
"strings"
@@ -168,6 +169,20 @@ func (f *Format) Run() error {
var changes int
+ processBatch := func() error {
+ if Cli.NoCache {
+ changes += len(batch)
+ } else {
+ count, err := cache.Update(batch)
+ if err != nil {
+ return err
+ }
+ changes += count
+ }
+ batch = batch[:0]
+ return nil
+ }
+
LOOP:
for {
select {
@@ -179,22 +194,17 @@ func (f *Format) Run() error {
}
batch = append(batch, path)
if len(batch) == batchSize {
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
- batch = batch[:0]
}
}
}
// final flush
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
if Cli.FailOnChange && changes != 0 {
return ErrFailOnChange
@@ -251,6 +261,22 @@ func (f *Format) Run() error {
}
defer close(pathsCh)
+
+ if Cli.NoCache {
+ return walker.Walk(ctx, func(path string, info fs.FileInfo, err error) error {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ // ignore symlinks and directories
+ if !(info.IsDir() || info.Mode()&os.ModeSymlink == os.ModeSymlink) {
+ pathsCh <- path
+ }
+ return nil
+ }
+ })
+ }
+
return cache.ChangeSet(ctx, walker, pathsCh)
})
diff --git a/cli/format_test.go b/cli/format_test.go
index fb389fe..2349767 100644
--- a/cli/format_test.go
+++ b/cli/format_test.go
@@ -216,6 +216,15 @@ func TestCache(t *testing.T) {
as.NoError(err)
as.Contains(string(out), "0 files changed")
+ // clear cache
+ out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "-c")
+ as.NoError(err)
+ as.Contains(string(out), fmt.Sprintf("%d files changed", 29))
+
+ out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir)
+ as.NoError(err)
+ as.Contains(string(out), "0 files changed")
+
// no cache
out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "--no-cache")
as.NoError(err)
diff --git a/nix/packages.nix b/nix/packages.nix
index 127eb08..e0f8604 100644
--- a/nix/packages.nix
+++ b/nix/packages.nix
@@ -13,7 +13,7 @@
packages = rec {
treefmt = inputs'.gomod2nix.legacyPackages.buildGoApplication rec {
pname = "treefmt";
- version = "0.0.1+dev";
+ version = "2.0.0+dev";
# ensure we are using the same version of go to build with
inherit (pkgs) go;
diff --git a/cli/cli.go b/cli/cli.go
index 8b23262..b370ee7 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -11,6 +11,7 @@ var Cli = Format{}
type Format struct {
AllowMissingFormatter bool `default:"false" help:"Do not exit with error if a configured formatter is missing"`
WorkingDirectory kong.ChangeDirFlag `default:"." short:"C" help:"Run as if treefmt was started in the specified working directory instead of the current working directory"`
+ NoCache bool `help:"Ignore the evaluation cache entirely. Useful for CI"`
ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough"`
ConfigFile string `type:"existingfile" default:"./treefmt.toml"`
FailOnChange bool `help:"Exit with error if any changes were made. Useful for CI."`
diff --git a/cli/format.go b/cli/format.go
index 6c46096..14ac16c 100644
--- a/cli/format.go
+++ b/cli/format.go
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
+ "io/fs"
"os"
"os/signal"
"strings"
@@ -168,6 +169,20 @@ func (f *Format) Run() error {
var changes int
+ processBatch := func() error {
+ if Cli.NoCache {
+ changes += len(batch)
+ } else {
+ count, err := cache.Update(batch)
+ if err != nil {
+ return err
+ }
+ changes += count
+ }
+ batch = batch[:0]
+ return nil
+ }
+
LOOP:
for {
select {
@@ -179,22 +194,17 @@ func (f *Format) Run() error {
}
batch = append(batch, path)
if len(batch) == batchSize {
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
- batch = batch[:0]
}
}
}
// final flush
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
if Cli.FailOnChange && changes != 0 {
return ErrFailOnChange
@@ -251,6 +261,22 @@ func (f *Format) Run() error {
}
defer close(pathsCh)
+
+ if Cli.NoCache {
+ return walker.Walk(ctx, func(path string, info fs.FileInfo, err error) error {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ // ignore symlinks and directories
+ if !(info.IsDir() || info.Mode()&os.ModeSymlink == os.ModeSymlink) {
+ pathsCh <- path
+ }
+ return nil
+ }
+ })
+ }
+
return cache.ChangeSet(ctx, walker, pathsCh)
})
diff --git a/nix/packages.nix b/nix/packages.nix
index 127eb08..e0f8604 100644
--- a/nix/packages.nix
+++ b/nix/packages.nix
@@ -13,7 +13,7 @@
packages = rec {
treefmt = inputs'.gomod2nix.legacyPackages.buildGoApplication rec {
pname = "treefmt";
- version = "0.0.1+dev";
+ version = "2.0.0+dev";
# ensure we are using the same version of go to build with
inherit (pkgs) go;
2024-02-15 13:37:33 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
if len(batch) > 0 {
|
|
|
|
fg.Go(func() error {
|
|
|
|
if err := pipeline.Apply(ctx, batch); err != nil {
|
2024-04-25 14:16:04 +03:00
|
|
|
return fmt.Errorf("%s failure: %w", key, err)
|
2024-04-19 12:57:41 +03:00
|
|
|
}
|
|
|
|
for _, path := range batch {
|
|
|
|
processedCh <- path
|
feat: support --no-cache
Signed-off-by: Brian McGee <brian@bmcgee.ie>
diff --git a/cli/cli.go b/cli/cli.go
index 8b23262..b370ee7 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -11,6 +11,7 @@ var Cli = Format{}
type Format struct {
AllowMissingFormatter bool `default:"false" help:"Do not exit with error if a configured formatter is missing"`
WorkingDirectory kong.ChangeDirFlag `default:"." short:"C" help:"Run as if treefmt was started in the specified working directory instead of the current working directory"`
+ NoCache bool `help:"Ignore the evaluation cache entirely. Useful for CI"`
ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough"`
ConfigFile string `type:"existingfile" default:"./treefmt.toml"`
FailOnChange bool `help:"Exit with error if any changes were made. Useful for CI."`
diff --git a/cli/format.go b/cli/format.go
index 6c46096..14ac16c 100644
--- a/cli/format.go
+++ b/cli/format.go
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
+ "io/fs"
"os"
"os/signal"
"strings"
@@ -168,6 +169,20 @@ func (f *Format) Run() error {
var changes int
+ processBatch := func() error {
+ if Cli.NoCache {
+ changes += len(batch)
+ } else {
+ count, err := cache.Update(batch)
+ if err != nil {
+ return err
+ }
+ changes += count
+ }
+ batch = batch[:0]
+ return nil
+ }
+
LOOP:
for {
select {
@@ -179,22 +194,17 @@ func (f *Format) Run() error {
}
batch = append(batch, path)
if len(batch) == batchSize {
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
- batch = batch[:0]
}
}
}
// final flush
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
if Cli.FailOnChange && changes != 0 {
return ErrFailOnChange
@@ -251,6 +261,22 @@ func (f *Format) Run() error {
}
defer close(pathsCh)
+
+ if Cli.NoCache {
+ return walker.Walk(ctx, func(path string, info fs.FileInfo, err error) error {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ // ignore symlinks and directories
+ if !(info.IsDir() || info.Mode()&os.ModeSymlink == os.ModeSymlink) {
+ pathsCh <- path
+ }
+ return nil
+ }
+ })
+ }
+
return cache.ChangeSet(ctx, walker, pathsCh)
})
diff --git a/cli/format_test.go b/cli/format_test.go
index fb389fe..2349767 100644
--- a/cli/format_test.go
+++ b/cli/format_test.go
@@ -216,6 +216,15 @@ func TestCache(t *testing.T) {
as.NoError(err)
as.Contains(string(out), "0 files changed")
+ // clear cache
+ out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "-c")
+ as.NoError(err)
+ as.Contains(string(out), fmt.Sprintf("%d files changed", 29))
+
+ out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir)
+ as.NoError(err)
+ as.Contains(string(out), "0 files changed")
+
// no cache
out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "--no-cache")
as.NoError(err)
diff --git a/nix/packages.nix b/nix/packages.nix
index 127eb08..e0f8604 100644
--- a/nix/packages.nix
+++ b/nix/packages.nix
@@ -13,7 +13,7 @@
packages = rec {
treefmt = inputs'.gomod2nix.legacyPackages.buildGoApplication rec {
pname = "treefmt";
- version = "0.0.1+dev";
+ version = "2.0.0+dev";
# ensure we are using the same version of go to build with
inherit (pkgs) go;
diff --git a/cli/cli.go b/cli/cli.go
index 8b23262..b370ee7 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -11,6 +11,7 @@ var Cli = Format{}
type Format struct {
AllowMissingFormatter bool `default:"false" help:"Do not exit with error if a configured formatter is missing"`
WorkingDirectory kong.ChangeDirFlag `default:"." short:"C" help:"Run as if treefmt was started in the specified working directory instead of the current working directory"`
+ NoCache bool `help:"Ignore the evaluation cache entirely. Useful for CI"`
ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough"`
ConfigFile string `type:"existingfile" default:"./treefmt.toml"`
FailOnChange bool `help:"Exit with error if any changes were made. Useful for CI."`
diff --git a/cli/format.go b/cli/format.go
index 6c46096..14ac16c 100644
--- a/cli/format.go
+++ b/cli/format.go
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
+ "io/fs"
"os"
"os/signal"
"strings"
@@ -168,6 +169,20 @@ func (f *Format) Run() error {
var changes int
+ processBatch := func() error {
+ if Cli.NoCache {
+ changes += len(batch)
+ } else {
+ count, err := cache.Update(batch)
+ if err != nil {
+ return err
+ }
+ changes += count
+ }
+ batch = batch[:0]
+ return nil
+ }
+
LOOP:
for {
select {
@@ -179,22 +194,17 @@ func (f *Format) Run() error {
}
batch = append(batch, path)
if len(batch) == batchSize {
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
- batch = batch[:0]
}
}
}
// final flush
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
if Cli.FailOnChange && changes != 0 {
return ErrFailOnChange
@@ -251,6 +261,22 @@ func (f *Format) Run() error {
}
defer close(pathsCh)
+
+ if Cli.NoCache {
+ return walker.Walk(ctx, func(path string, info fs.FileInfo, err error) error {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ // ignore symlinks and directories
+ if !(info.IsDir() || info.Mode()&os.ModeSymlink == os.ModeSymlink) {
+ pathsCh <- path
+ }
+ return nil
+ }
+ })
+ }
+
return cache.ChangeSet(ctx, walker, pathsCh)
})
diff --git a/nix/packages.nix b/nix/packages.nix
index 127eb08..e0f8604 100644
--- a/nix/packages.nix
+++ b/nix/packages.nix
@@ -13,7 +13,7 @@
packages = rec {
treefmt = inputs'.gomod2nix.legacyPackages.buildGoApplication rec {
pname = "treefmt";
- version = "0.0.1+dev";
+ version = "2.0.0+dev";
# ensure we are using the same version of go to build with
inherit (pkgs) go;
2024-02-15 13:37:33 +03:00
|
|
|
}
|
|
|
|
return nil
|
2024-04-19 12:57:41 +03:00
|
|
|
})
|
|
|
|
}
|
feat: support --no-cache
Signed-off-by: Brian McGee <brian@bmcgee.ie>
diff --git a/cli/cli.go b/cli/cli.go
index 8b23262..b370ee7 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -11,6 +11,7 @@ var Cli = Format{}
type Format struct {
AllowMissingFormatter bool `default:"false" help:"Do not exit with error if a configured formatter is missing"`
WorkingDirectory kong.ChangeDirFlag `default:"." short:"C" help:"Run as if treefmt was started in the specified working directory instead of the current working directory"`
+ NoCache bool `help:"Ignore the evaluation cache entirely. Useful for CI"`
ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough"`
ConfigFile string `type:"existingfile" default:"./treefmt.toml"`
FailOnChange bool `help:"Exit with error if any changes were made. Useful for CI."`
diff --git a/cli/format.go b/cli/format.go
index 6c46096..14ac16c 100644
--- a/cli/format.go
+++ b/cli/format.go
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
+ "io/fs"
"os"
"os/signal"
"strings"
@@ -168,6 +169,20 @@ func (f *Format) Run() error {
var changes int
+ processBatch := func() error {
+ if Cli.NoCache {
+ changes += len(batch)
+ } else {
+ count, err := cache.Update(batch)
+ if err != nil {
+ return err
+ }
+ changes += count
+ }
+ batch = batch[:0]
+ return nil
+ }
+
LOOP:
for {
select {
@@ -179,22 +194,17 @@ func (f *Format) Run() error {
}
batch = append(batch, path)
if len(batch) == batchSize {
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
- batch = batch[:0]
}
}
}
// final flush
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
if Cli.FailOnChange && changes != 0 {
return ErrFailOnChange
@@ -251,6 +261,22 @@ func (f *Format) Run() error {
}
defer close(pathsCh)
+
+ if Cli.NoCache {
+ return walker.Walk(ctx, func(path string, info fs.FileInfo, err error) error {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ // ignore symlinks and directories
+ if !(info.IsDir() || info.Mode()&os.ModeSymlink == os.ModeSymlink) {
+ pathsCh <- path
+ }
+ return nil
+ }
+ })
+ }
+
return cache.ChangeSet(ctx, walker, pathsCh)
})
diff --git a/cli/format_test.go b/cli/format_test.go
index fb389fe..2349767 100644
--- a/cli/format_test.go
+++ b/cli/format_test.go
@@ -216,6 +216,15 @@ func TestCache(t *testing.T) {
as.NoError(err)
as.Contains(string(out), "0 files changed")
+ // clear cache
+ out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "-c")
+ as.NoError(err)
+ as.Contains(string(out), fmt.Sprintf("%d files changed", 29))
+
+ out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir)
+ as.NoError(err)
+ as.Contains(string(out), "0 files changed")
+
// no cache
out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "--no-cache")
as.NoError(err)
diff --git a/nix/packages.nix b/nix/packages.nix
index 127eb08..e0f8604 100644
--- a/nix/packages.nix
+++ b/nix/packages.nix
@@ -13,7 +13,7 @@
packages = rec {
treefmt = inputs'.gomod2nix.legacyPackages.buildGoApplication rec {
pname = "treefmt";
- version = "0.0.1+dev";
+ version = "2.0.0+dev";
# ensure we are using the same version of go to build with
inherit (pkgs) go;
diff --git a/cli/cli.go b/cli/cli.go
index 8b23262..b370ee7 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -11,6 +11,7 @@ var Cli = Format{}
type Format struct {
AllowMissingFormatter bool `default:"false" help:"Do not exit with error if a configured formatter is missing"`
WorkingDirectory kong.ChangeDirFlag `default:"." short:"C" help:"Run as if treefmt was started in the specified working directory instead of the current working directory"`
+ NoCache bool `help:"Ignore the evaluation cache entirely. Useful for CI"`
ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough"`
ConfigFile string `type:"existingfile" default:"./treefmt.toml"`
FailOnChange bool `help:"Exit with error if any changes were made. Useful for CI."`
diff --git a/cli/format.go b/cli/format.go
index 6c46096..14ac16c 100644
--- a/cli/format.go
+++ b/cli/format.go
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
+ "io/fs"
"os"
"os/signal"
"strings"
@@ -168,6 +169,20 @@ func (f *Format) Run() error {
var changes int
+ processBatch := func() error {
+ if Cli.NoCache {
+ changes += len(batch)
+ } else {
+ count, err := cache.Update(batch)
+ if err != nil {
+ return err
+ }
+ changes += count
+ }
+ batch = batch[:0]
+ return nil
+ }
+
LOOP:
for {
select {
@@ -179,22 +194,17 @@ func (f *Format) Run() error {
}
batch = append(batch, path)
if len(batch) == batchSize {
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
- batch = batch[:0]
}
}
}
// final flush
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
if Cli.FailOnChange && changes != 0 {
return ErrFailOnChange
@@ -251,6 +261,22 @@ func (f *Format) Run() error {
}
defer close(pathsCh)
+
+ if Cli.NoCache {
+ return walker.Walk(ctx, func(path string, info fs.FileInfo, err error) error {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ // ignore symlinks and directories
+ if !(info.IsDir() || info.Mode()&os.ModeSymlink == os.ModeSymlink) {
+ pathsCh <- path
+ }
+ return nil
+ }
+ })
+ }
+
return cache.ChangeSet(ctx, walker, pathsCh)
})
diff --git a/nix/packages.nix b/nix/packages.nix
index 127eb08..e0f8604 100644
--- a/nix/packages.nix
+++ b/nix/packages.nix
@@ -13,7 +13,7 @@
packages = rec {
treefmt = inputs'.gomod2nix.legacyPackages.buildGoApplication rec {
pname = "treefmt";
- version = "0.0.1+dev";
+ version = "2.0.0+dev";
# ensure we are using the same version of go to build with
inherit (pkgs) go;
2024-02-15 13:37:33 +03:00
|
|
|
}
|
2024-04-19 12:57:41 +03:00
|
|
|
}
|
feat: support --no-cache
Signed-off-by: Brian McGee <brian@bmcgee.ie>
diff --git a/cli/cli.go b/cli/cli.go
index 8b23262..b370ee7 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -11,6 +11,7 @@ var Cli = Format{}
type Format struct {
AllowMissingFormatter bool `default:"false" help:"Do not exit with error if a configured formatter is missing"`
WorkingDirectory kong.ChangeDirFlag `default:"." short:"C" help:"Run as if treefmt was started in the specified working directory instead of the current working directory"`
+ NoCache bool `help:"Ignore the evaluation cache entirely. Useful for CI"`
ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough"`
ConfigFile string `type:"existingfile" default:"./treefmt.toml"`
FailOnChange bool `help:"Exit with error if any changes were made. Useful for CI."`
diff --git a/cli/format.go b/cli/format.go
index 6c46096..14ac16c 100644
--- a/cli/format.go
+++ b/cli/format.go
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
+ "io/fs"
"os"
"os/signal"
"strings"
@@ -168,6 +169,20 @@ func (f *Format) Run() error {
var changes int
+ processBatch := func() error {
+ if Cli.NoCache {
+ changes += len(batch)
+ } else {
+ count, err := cache.Update(batch)
+ if err != nil {
+ return err
+ }
+ changes += count
+ }
+ batch = batch[:0]
+ return nil
+ }
+
LOOP:
for {
select {
@@ -179,22 +194,17 @@ func (f *Format) Run() error {
}
batch = append(batch, path)
if len(batch) == batchSize {
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
- batch = batch[:0]
}
}
}
// final flush
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
if Cli.FailOnChange && changes != 0 {
return ErrFailOnChange
@@ -251,6 +261,22 @@ func (f *Format) Run() error {
}
defer close(pathsCh)
+
+ if Cli.NoCache {
+ return walker.Walk(ctx, func(path string, info fs.FileInfo, err error) error {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ // ignore symlinks and directories
+ if !(info.IsDir() || info.Mode()&os.ModeSymlink == os.ModeSymlink) {
+ pathsCh <- path
+ }
+ return nil
+ }
+ })
+ }
+
return cache.ChangeSet(ctx, walker, pathsCh)
})
diff --git a/cli/format_test.go b/cli/format_test.go
index fb389fe..2349767 100644
--- a/cli/format_test.go
+++ b/cli/format_test.go
@@ -216,6 +216,15 @@ func TestCache(t *testing.T) {
as.NoError(err)
as.Contains(string(out), "0 files changed")
+ // clear cache
+ out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "-c")
+ as.NoError(err)
+ as.Contains(string(out), fmt.Sprintf("%d files changed", 29))
+
+ out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir)
+ as.NoError(err)
+ as.Contains(string(out), "0 files changed")
+
// no cache
out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir, "--no-cache")
as.NoError(err)
diff --git a/nix/packages.nix b/nix/packages.nix
index 127eb08..e0f8604 100644
--- a/nix/packages.nix
+++ b/nix/packages.nix
@@ -13,7 +13,7 @@
packages = rec {
treefmt = inputs'.gomod2nix.legacyPackages.buildGoApplication rec {
pname = "treefmt";
- version = "0.0.1+dev";
+ version = "2.0.0+dev";
# ensure we are using the same version of go to build with
inherit (pkgs) go;
diff --git a/cli/cli.go b/cli/cli.go
index 8b23262..b370ee7 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -11,6 +11,7 @@ var Cli = Format{}
type Format struct {
AllowMissingFormatter bool `default:"false" help:"Do not exit with error if a configured formatter is missing"`
WorkingDirectory kong.ChangeDirFlag `default:"." short:"C" help:"Run as if treefmt was started in the specified working directory instead of the current working directory"`
+ NoCache bool `help:"Ignore the evaluation cache entirely. Useful for CI"`
ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough"`
ConfigFile string `type:"existingfile" default:"./treefmt.toml"`
FailOnChange bool `help:"Exit with error if any changes were made. Useful for CI."`
diff --git a/cli/format.go b/cli/format.go
index 6c46096..14ac16c 100644
--- a/cli/format.go
+++ b/cli/format.go
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
+ "io/fs"
"os"
"os/signal"
"strings"
@@ -168,6 +169,20 @@ func (f *Format) Run() error {
var changes int
+ processBatch := func() error {
+ if Cli.NoCache {
+ changes += len(batch)
+ } else {
+ count, err := cache.Update(batch)
+ if err != nil {
+ return err
+ }
+ changes += count
+ }
+ batch = batch[:0]
+ return nil
+ }
+
LOOP:
for {
select {
@@ -179,22 +194,17 @@ func (f *Format) Run() error {
}
batch = append(batch, path)
if len(batch) == batchSize {
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
- batch = batch[:0]
}
}
}
// final flush
- count, err := cache.Update(batch)
- if err != nil {
+ if err = processBatch(); err != nil {
return err
}
- changes += count
if Cli.FailOnChange && changes != 0 {
return ErrFailOnChange
@@ -251,6 +261,22 @@ func (f *Format) Run() error {
}
defer close(pathsCh)
+
+ if Cli.NoCache {
+ return walker.Walk(ctx, func(path string, info fs.FileInfo, err error) error {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ // ignore symlinks and directories
+ if !(info.IsDir() || info.Mode()&os.ModeSymlink == os.ModeSymlink) {
+ pathsCh <- path
+ }
+ return nil
+ }
+ })
+ }
+
return cache.ChangeSet(ctx, walker, pathsCh)
})
diff --git a/nix/packages.nix b/nix/packages.nix
index 127eb08..e0f8604 100644
--- a/nix/packages.nix
+++ b/nix/packages.nix
@@ -13,7 +13,7 @@
packages = rec {
treefmt = inputs'.gomod2nix.legacyPackages.buildGoApplication rec {
pname = "treefmt";
- version = "0.0.1+dev";
+ version = "2.0.0+dev";
# ensure we are using the same version of go to build with
inherit (pkgs) go;
2024-02-15 13:37:33 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
return func() error {
|
|
|
|
defer func() {
|
|
|
|
// close processed channel
|
|
|
|
close(processedCh)
|
|
|
|
}()
|
2023-12-23 15:50:47 +03:00
|
|
|
|
2024-05-02 13:28:22 +03:00
|
|
|
// iterate the files channel, checking if any pipeline wants it, and attempting to apply if so.
|
2024-05-01 21:03:26 +03:00
|
|
|
for file := range filesCh {
|
2024-05-01 13:15:39 +03:00
|
|
|
var matched bool
|
2024-04-19 12:57:41 +03:00
|
|
|
for key, pipeline := range pipelines {
|
2024-05-01 21:03:26 +03:00
|
|
|
if !pipeline.Wants(file) {
|
2024-04-19 12:57:41 +03:00
|
|
|
continue
|
|
|
|
}
|
2024-05-01 13:15:39 +03:00
|
|
|
matched = true
|
2024-05-01 21:03:26 +03:00
|
|
|
tryApply(key, file)
|
2024-04-19 12:57:41 +03:00
|
|
|
}
|
2024-05-01 13:15:39 +03:00
|
|
|
if matched {
|
|
|
|
stats.Add(stats.Matched, 1)
|
2024-05-01 21:03:26 +03:00
|
|
|
} else {
|
2024-05-02 13:28:22 +03:00
|
|
|
// no match, so we send it direct to the processed channel
|
2024-05-01 21:03:26 +03:00
|
|
|
processedCh <- file
|
2024-05-01 13:15:39 +03:00
|
|
|
}
|
2024-04-19 12:57:41 +03:00
|
|
|
}
|
2023-12-23 18:00:39 +03:00
|
|
|
|
2024-04-19 12:57:41 +03:00
|
|
|
// flush any partial batches which remain
|
|
|
|
flushBatches()
|
|
|
|
|
|
|
|
// wait for all outstanding formatting tasks to complete
|
|
|
|
if err := fg.Wait(); err != nil {
|
|
|
|
return fmt.Errorf("pipeline processing failure: %w", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2023-12-23 15:50:47 +03:00
|
|
|
}
|