From 0fbae06f19d03ca50f3da50339dc94b92018ab3b Mon Sep 17 00:00:00 2001 From: Brian McGee Date: Wed, 10 Jan 2024 15:45:57 +0000 Subject: [PATCH 1/7] feat: support reading paths from stdin Signed-off-by: Brian McGee --- flake.lock | 16 ++++++ flake.nix | 2 + internal/cache/cache.go | 9 +--- internal/cli/cli.go | 21 ++++---- internal/cli/format.go | 29 ++++++++--- internal/cli/format_test.go | 100 ++++++++++++++++++++++++++++++++++++ internal/walk/filesystem.go | 25 +++++++-- internal/walk/git.go | 60 +++++++++++++++++----- internal/walk/walker.go | 14 ++--- nix/packages.nix | 9 +++- nix/treefmt.nix | 9 +++- 11 files changed, 243 insertions(+), 51 deletions(-) diff --git a/flake.lock b/flake.lock index e372a35..70c5801 100644 --- a/flake.lock +++ b/flake.lock @@ -111,6 +111,21 @@ "type": "github" } }, + "nix-filter": { + "locked": { + "lastModified": 1705332318, + "narHash": "sha256-kcw1yFeJe9N4PjQji9ZeX47jg0p9A0DuU4djKvg1a7I=", + "owner": "numtide", + "repo": "nix-filter", + "rev": "3449dc925982ad46246cfc36469baf66e1b64f17", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nix-filter", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1707689078, @@ -151,6 +166,7 @@ "flake-parts": "flake-parts", "flake-root": "flake-root", "gomod2nix": "gomod2nix", + "nix-filter": "nix-filter", "nixpkgs": "nixpkgs", "treefmt-nix": "treefmt-nix" } diff --git a/flake.nix b/flake.nix index 8a4ad1a..3fc06af 100644 --- a/flake.nix +++ b/flake.nix @@ -18,6 +18,8 @@ url = "github:nix-community/gomod2nix"; inputs.nixpkgs.follows = "nixpkgs"; }; + + nix-filter.url = "github:numtide/nix-filter"; }; outputs = inputs @ {flake-parts, ...}: diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 69ba5a3..2043619 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -173,7 +173,7 @@ func putEntry(bucket *bolt.Bucket, path string, entry *Entry) error { // ChangeSet is used to walk a filesystem, starting at root, and outputting any new or changed paths using pathsCh. // It determines if a path is new or has changed by comparing against cache entries. -func ChangeSet(ctx context.Context, root string, walkerType walk.Type, pathsCh chan<- string) error { +func ChangeSet(ctx context.Context, walker walk.Walker, pathsCh chan<- string) error { var tx *bolt.Tx var bucket *bolt.Bucket var processed int @@ -185,12 +185,7 @@ func ChangeSet(ctx context.Context, root string, walkerType walk.Type, pathsCh c } }() - w, err := walk.New(walkerType, root) - if err != nil { - return fmt.Errorf("%w: failed to create walker", err) - } - - return w.Walk(ctx, func(path string, info fs.FileInfo, err error) error { + return walker.Walk(ctx, func(path string, info fs.FileInfo, err error) error { select { case <-ctx.Done(): return ctx.Err() diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 03bbb60..4837bd5 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -6,12 +6,12 @@ import ( "github.com/charmbracelet/log" ) -var Cli = Options{} +var Cli = Format{} -type Options 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."` - ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough."` +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"` + 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."` Formatters []string `help:"Specify formatters to apply. Defaults to all formatters."` @@ -19,17 +19,16 @@ type Options struct { Walk walk.Type `enum:"auto,git,filesystem" default:"auto" help:"The method used to traverse the files within --tree-root. Currently supports 'auto', 'git' or 'filesystem'."` Verbosity int `name:"verbose" short:"v" type:"counter" default:"0" env:"LOG_LEVEL" help:"Set the verbosity of logs e.g. -vv."` - Format Format `cmd:"" default:"."` + Paths []string `name:"paths" arg:"" type:"path" optional:"" help:"Paths to format. Defaults to formatting the whole tree."` + Stdin bool `help:"Format the context passed in via stdin"` } -func (c *Options) Configure() { +func (f *Format) Configure() { log.SetReportTimestamp(false) - if c.Verbosity == 0 { - log.SetLevel(log.WarnLevel) - } else if c.Verbosity == 1 { + if f.Verbosity == 0 { log.SetLevel(log.InfoLevel) - } else if c.Verbosity >= 2 { + } else if f.Verbosity > 0 { log.SetLevel(log.DebugLevel) } } diff --git a/internal/cli/format.go b/internal/cli/format.go index 253a413..0fc4731 100644 --- a/internal/cli/format.go +++ b/internal/cli/format.go @@ -1,6 +1,7 @@ package cli import ( + "bufio" "context" "errors" "fmt" @@ -10,6 +11,8 @@ import ( "syscall" "time" + "git.numtide.com/numtide/treefmt/internal/walk" + "git.numtide.com/numtide/treefmt/internal/config" "git.numtide.com/numtide/treefmt/internal/cache" @@ -19,8 +22,6 @@ import ( "golang.org/x/sync/errgroup" ) -type Format struct{} - var ErrFailOnChange = errors.New("unexpected changes detected, --fail-on-change is enabled") func (f *Format) Run() error { @@ -201,7 +202,7 @@ func (f *Format) Run() error { return ErrFailOnChange } - fmt.Printf("%v files changed in %v", changes, time.Now().Sub(start)) + fmt.Printf("%v files changed in %v\n", changes, time.Now().Sub(start)) return nil }) @@ -235,10 +236,24 @@ func (f *Format) Run() error { return nil }) - eg.Go(func() error { - err := cache.ChangeSet(ctx, Cli.TreeRoot, Cli.Walk, pathsCh) - close(pathsCh) - return err + eg.Go(func() (err error) { + paths := Cli.Paths + + if len(paths) == 0 && Cli.Stdin { + // read in all the paths + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + paths = append(paths, scanner.Text()) + } + } + + walker, err := walk.New(Cli.Walk, Cli.TreeRoot, paths) + if err != nil { + return fmt.Errorf("%w: failed to create walker", err) + } + + defer close(pathsCh) + return cache.ChangeSet(ctx, walker, pathsCh) }) // listen for shutdown and call cancel if required diff --git a/internal/cli/format_test.go b/internal/cli/format_test.go index de8bc55..62ce5d2 100644 --- a/internal/cli/format_test.go +++ b/internal/cli/format_test.go @@ -481,3 +481,103 @@ func TestOrderingFormatters(t *testing.T) { as.NoError(err) as.Contains(string(out), "8 files changed") } + +func TestPathsArg(t *testing.T) { + as := require.New(t) + + // capture current cwd, so we can replace it after the test is finished + cwd, err := os.Getwd() + as.NoError(err) + + t.Cleanup(func() { + // return to the previous working directory + as.NoError(os.Chdir(cwd)) + }) + + tempDir := test.TempExamples(t) + configPath := filepath.Join(tempDir, "/treefmt.toml") + + // change working directory to temp root + as.NoError(os.Chdir(tempDir)) + + // basic config + cfg := config.Config{ + Formatters: map[string]*config.Formatter{ + "echo": { + Command: "echo", + Includes: []string{"*"}, + }, + }, + } + test.WriteConfig(t, configPath, cfg) + + // without any path args + out, err := cmd(t, "-C", tempDir) + as.NoError(err) + as.Contains(string(out), fmt.Sprintf("%d files changed", 29)) + + // specify some explicit paths + out, err = cmd(t, "-C", tempDir, "-c", "elm/elm.json", "haskell/Nested/Foo.hs") + as.NoError(err) + as.Contains(string(out), fmt.Sprintf("%d files changed", 2)) + + // specify a bad path + out, err = cmd(t, "-C", tempDir, "-c", "elm/elm.json", "haskell/Nested/Bar.hs") + as.ErrorContains(err, "no such file or directory") +} + +func TestStdIn(t *testing.T) { + as := require.New(t) + + // capture current cwd, so we can replace it after the test is finished + cwd, err := os.Getwd() + as.NoError(err) + + t.Cleanup(func() { + // return to the previous working directory + as.NoError(os.Chdir(cwd)) + }) + + tempDir := test.TempExamples(t) + configPath := filepath.Join(tempDir, "/treefmt.toml") + + // change working directory to temp root + as.NoError(os.Chdir(tempDir)) + + // basic config + cfg := config.Config{ + Formatters: map[string]*config.Formatter{ + "echo": { + Command: "echo", + Includes: []string{"*"}, + }, + }, + } + test.WriteConfig(t, configPath, cfg) + + // swap out stdin + prevStdIn := os.Stdin + stdin, err := os.CreateTemp("", "stdin") + as.NoError(err) + + os.Stdin = stdin + + t.Cleanup(func() { + os.Stdin = prevStdIn + _ = os.Remove(stdin.Name()) + }) + + go func() { + _, err := stdin.WriteString(`treefmt.toml +elm/elm.json +go/main.go +`) + as.NoError(err, "failed to write to stdin") + as.NoError(stdin.Sync()) + _, _ = stdin.Seek(0, 0) + }() + + out, err := cmd(t, "-C", tempDir, "--stdin") + as.NoError(err) + as.Contains(string(out), fmt.Sprintf("%d files changed", 3)) +} diff --git a/internal/walk/filesystem.go b/internal/walk/filesystem.go index bf84158..82e4faa 100644 --- a/internal/walk/filesystem.go +++ b/internal/walk/filesystem.go @@ -2,11 +2,13 @@ package walk import ( "context" + "os" "path/filepath" ) type filesystemWalker struct { - root string + root string + paths []string } func (f filesystemWalker) Root() string { @@ -14,9 +16,24 @@ func (f filesystemWalker) Root() string { } func (f filesystemWalker) Walk(_ context.Context, fn filepath.WalkFunc) error { - return filepath.Walk(f.root, fn) + if len(f.paths) == 0 { + return filepath.Walk(f.root, fn) + } + + for _, path := range f.paths { + info, err := os.Stat(path) + if err = filepath.Walk(path, fn); err != nil { + return err + } + + if err = fn(path, info, err); err != nil { + return err + } + } + + return nil } -func NewFilesystem(root string) (Walker, error) { - return filesystemWalker{root}, nil +func NewFilesystem(root string, paths []string) (Walker, error) { + return filesystemWalker{root, paths}, nil } diff --git a/internal/walk/git.go b/internal/walk/git.go index 09fd3c7..ea5dc6d 100644 --- a/internal/walk/git.go +++ b/internal/walk/git.go @@ -2,16 +2,22 @@ package walk import ( "context" + "errors" "fmt" + "io/fs" "os" "path/filepath" + "github.com/charmbracelet/log" + "github.com/go-git/go-git/v5/plumbing/format/index" + "github.com/go-git/go-git/v5" ) type gitWalker struct { - root string - repo *git.Repository + root string + paths []string + repo *git.Repository } func (g *gitWalker) Root() string { @@ -24,28 +30,56 @@ func (g *gitWalker) Walk(ctx context.Context, fn filepath.WalkFunc) error { return fmt.Errorf("%w: failed to open index", err) } - for _, entry := range idx.Entries { - select { - case <-ctx.Done(): - return ctx.Err() - default: - path := filepath.Join(g.root, entry.Name) + if len(g.paths) > 0 { + for _, path := range g.paths { - // stat the file - info, err := os.Lstat(path) - if err = fn(path, info, err); err != nil { + err = filepath.Walk(path, func(path string, info fs.FileInfo, err error) error { + if info.IsDir() { + return nil + } + + relPath, err := filepath.Rel(g.root, path) + if err != nil { + return err + } + + if _, err = idx.Entry(relPath); errors.Is(err, index.ErrEntryNotFound) { + // we skip this path as it's not staged + log.Debugf("Path not found in git index, skipping: %v, %v", relPath, path) + return nil + } + + return fn(path, info, err) + }) + if err != nil { return err } + + } + } else { + for _, entry := range idx.Entries { + select { + case <-ctx.Done(): + return ctx.Err() + default: + path := filepath.Join(g.root, entry.Name) + + // stat the file + info, err := os.Lstat(path) + if err = fn(path, info, err); err != nil { + return err + } + } } } return nil } -func NewGit(root string) (Walker, error) { +func NewGit(root string, paths []string) (Walker, error) { repo, err := git.PlainOpen(root) if err != nil { return nil, fmt.Errorf("%w: failed to open git repo", err) } - return &gitWalker{root, repo}, nil + return &gitWalker{root, paths, repo}, nil } diff --git a/internal/walk/walker.go b/internal/walk/walker.go index b00f18e..a5b5e58 100644 --- a/internal/walk/walker.go +++ b/internal/walk/walker.go @@ -19,24 +19,24 @@ type Walker interface { Walk(ctx context.Context, fn filepath.WalkFunc) error } -func New(walkerType Type, root string) (Walker, error) { +func New(walkerType Type, root string, paths []string) (Walker, error) { switch walkerType { case Git: - return NewGit(root) + return NewGit(root, paths) case Auto: - return Detect(root) + return Detect(root, paths) case Filesystem: - return NewFilesystem(root) + return NewFilesystem(root, paths) default: return nil, fmt.Errorf("unknown walker type: %v", walkerType) } } -func Detect(root string) (Walker, error) { +func Detect(root string, paths []string) (Walker, error) { // for now, we keep it simple and try git first, filesystem second - w, err := NewGit(root) + w, err := NewGit(root, paths) if err == nil { return w, err } - return NewFilesystem(root) + return NewFilesystem(root, paths) } diff --git a/nix/packages.nix b/nix/packages.nix index 7029757..127eb08 100644 --- a/nix/packages.nix +++ b/nix/packages.nix @@ -18,7 +18,14 @@ # ensure we are using the same version of go to build with inherit (pkgs) go; - src = ../.; + src = let + filter = inputs.nix-filter.lib; + in + filter { + root = ../.; + exclude = [./nix]; + }; + modules = ../gomod2nix.toml; ldflags = [ diff --git a/nix/treefmt.nix b/nix/treefmt.nix index 3d5aac6..66022ac 100644 --- a/nix/treefmt.nix +++ b/nix/treefmt.nix @@ -2,11 +2,18 @@ imports = [ inputs.treefmt-nix.flakeModule ]; - perSystem = {config, ...}: { + perSystem = { + config, + self', + ... + }: { treefmt.config = { inherit (config.flake-root) projectRootFile; flakeCheck = true; flakeFormatter = true; + + package = self'.packages.default; + programs = { alejandra.enable = true; deadnix.enable = true; From d4ab015bc6de484da25a018ba70221211622732d Mon Sep 17 00:00:00 2001 From: Brian McGee Date: Thu, 15 Feb 2024 09:20:01 +0000 Subject: [PATCH 2/7] chore: remove internal directory Signed-off-by: Brian McGee --- {internal/cache => cache}/cache.go | 4 +- {internal/cli => cli}/cli.go | 2 +- {internal/cli => cli}/format.go | 20 ++-- {internal/cli => cli}/format_test.go | 105 +++++++++++++-------- {internal/cli => cli}/helpers_test.go | 3 +- {internal/config => config}/config.go | 0 {internal/config => config}/config_test.go | 2 +- {internal/config => config}/formatter.go | 0 {internal/format => format}/context.go | 0 {internal/format => format}/formatter.go | 2 +- {internal/format => format}/glob.go | 0 main.go | 2 +- test/{ => examples}/echo.toml | 0 test/{ => examples}/treefmt.toml | 0 {internal/test => test}/temp.go | 4 +- {internal/walk => walk}/filesystem.go | 0 {internal/walk => walk}/git.go | 0 {internal/walk => walk}/walker.go | 0 18 files changed, 83 insertions(+), 61 deletions(-) rename {internal/cache => cache}/cache.go (98%) rename {internal/cli => cli}/cli.go (97%) rename {internal/cli => cli}/format.go (91%) rename {internal/cli => cli}/format_test.go (84%) rename {internal/cli => cli}/helpers_test.go (96%) rename {internal/config => config}/config.go (100%) rename {internal/config => config}/config_test.go (98%) rename {internal/config => config}/formatter.go (100%) rename {internal/format => format}/context.go (100%) rename {internal/format => format}/formatter.go (99%) rename {internal/format => format}/glob.go (100%) rename test/{ => examples}/echo.toml (100%) rename test/{ => examples}/treefmt.toml (100%) rename {internal/test => test}/temp.go (86%) rename {internal/walk => walk}/filesystem.go (100%) rename {internal/walk => walk}/git.go (100%) rename {internal/walk => walk}/walker.go (100%) diff --git a/internal/cache/cache.go b/cache/cache.go similarity index 98% rename from internal/cache/cache.go rename to cache/cache.go index 2043619..eb56d15 100644 --- a/internal/cache/cache.go +++ b/cache/cache.go @@ -9,9 +9,9 @@ import ( "os" "time" - "git.numtide.com/numtide/treefmt/internal/walk" + "git.numtide.com/numtide/treefmt/format" + "git.numtide.com/numtide/treefmt/walk" - "git.numtide.com/numtide/treefmt/internal/format" "github.com/charmbracelet/log" "github.com/adrg/xdg" diff --git a/internal/cli/cli.go b/cli/cli.go similarity index 97% rename from internal/cli/cli.go rename to cli/cli.go index 4837bd5..ae7dbf2 100644 --- a/internal/cli/cli.go +++ b/cli/cli.go @@ -1,7 +1,7 @@ package cli import ( - "git.numtide.com/numtide/treefmt/internal/walk" + "git.numtide.com/numtide/treefmt/walk" "github.com/alecthomas/kong" "github.com/charmbracelet/log" ) diff --git a/internal/cli/format.go b/cli/format.go similarity index 91% rename from internal/cli/format.go rename to cli/format.go index 0fc4731..6c46096 100644 --- a/internal/cli/format.go +++ b/cli/format.go @@ -11,12 +11,10 @@ import ( "syscall" "time" - "git.numtide.com/numtide/treefmt/internal/walk" - - "git.numtide.com/numtide/treefmt/internal/config" - - "git.numtide.com/numtide/treefmt/internal/cache" - "git.numtide.com/numtide/treefmt/internal/format" + "git.numtide.com/numtide/treefmt/cache" + "git.numtide.com/numtide/treefmt/config" + format2 "git.numtide.com/numtide/treefmt/format" + "git.numtide.com/numtide/treefmt/walk" "github.com/charmbracelet/log" "golang.org/x/sync/errgroup" @@ -47,7 +45,7 @@ func (f *Format) Run() error { return fmt.Errorf("%w: failed to read config file", err) } - globalExcludes, err := format.CompileGlobs(cfg.Global.Excludes) + globalExcludes, err := format2.CompileGlobs(cfg.Global.Excludes) // create optional formatter filter set formatterSet := make(map[string]bool) @@ -68,7 +66,7 @@ func (f *Format) Run() error { } } - formatters := make(map[string]*format.Formatter) + formatters := make(map[string]*format2.Formatter) // detect broken dependencies for name, formatterCfg := range cfg.Formatters { @@ -115,8 +113,8 @@ func (f *Format) Run() error { continue } - formatter, err := format.NewFormatter(name, formatterCfg, globalExcludes) - if errors.Is(err, format.ErrCommandNotFound) && Cli.AllowMissingFormatter { + formatter, err := format2.NewFormatter(name, formatterCfg, globalExcludes) + if errors.Is(err, format2.ErrCommandNotFound) && Cli.AllowMissingFormatter { l.Debugf("formatter not found: %v", name) continue } else if err != nil { @@ -147,7 +145,7 @@ func (f *Format) Run() error { // completedCh := make(chan string, 1024) - ctx = format.SetCompletedChannel(ctx, completedCh) + ctx = format2.SetCompletedChannel(ctx, completedCh) // eg, ctx := errgroup.WithContext(ctx) diff --git a/internal/cli/format_test.go b/cli/format_test.go similarity index 84% rename from internal/cli/format_test.go rename to cli/format_test.go index 62ce5d2..4f03231 100644 --- a/internal/cli/format_test.go +++ b/cli/format_test.go @@ -8,15 +8,15 @@ import ( "path/filepath" "testing" - "git.numtide.com/numtide/treefmt/internal/config" + config2 "git.numtide.com/numtide/treefmt/config" + "git.numtide.com/numtide/treefmt/format" + "git.numtide.com/numtide/treefmt/test" - "git.numtide.com/numtide/treefmt/internal/test" "github.com/go-git/go-billy/v5/osfs" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/cache" "github.com/go-git/go-git/v5/storage/filesystem" - "git.numtide.com/numtide/treefmt/internal/format" "github.com/stretchr/testify/require" ) @@ -26,8 +26,8 @@ func TestAllowMissingFormatter(t *testing.T) { tempDir := t.TempDir() configPath := tempDir + "/treefmt.toml" - test.WriteConfig(t, configPath, config.Config{ - Formatters: map[string]*config.Formatter{ + test.WriteConfig(t, configPath, config2.Config{ + Formatters: map[string]*config2.Formatter{ "foo-fmt": { Command: "foo-fmt", }, @@ -47,8 +47,8 @@ func TestDependencyCycle(t *testing.T) { tempDir := t.TempDir() configPath := tempDir + "/treefmt.toml" - test.WriteConfig(t, configPath, config.Config{ - Formatters: map[string]*config.Formatter{ + test.WriteConfig(t, configPath, config2.Config{ + Formatters: map[string]*config2.Formatter{ "a": {Command: "echo", Before: "b"}, "b": {Command: "echo", Before: "c"}, "c": {Command: "echo", Before: "a"}, @@ -68,8 +68,8 @@ func TestSpecifyingFormatters(t *testing.T) { tempDir := test.TempExamples(t) configPath := tempDir + "/treefmt.toml" - test.WriteConfig(t, configPath, config.Config{ - Formatters: map[string]*config.Formatter{ + test.WriteConfig(t, configPath, config2.Config{ + Formatters: map[string]*config2.Formatter{ "elm": { Command: "echo", Includes: []string{"*.elm"}, @@ -117,8 +117,8 @@ func TestIncludesAndExcludes(t *testing.T) { configPath := tempDir + "/echo.toml" // test without any excludes - cfg := config.Config{ - Formatters: map[string]*config.Formatter{ + cfg := config2.Config{ + Formatters: map[string]*config2.Formatter{ "echo": { Command: "echo", Includes: []string{"*"}, @@ -129,7 +129,7 @@ func TestIncludesAndExcludes(t *testing.T) { test.WriteConfig(t, configPath, cfg) out, err := cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir) as.NoError(err) - as.Contains(string(out), fmt.Sprintf("%d files changed", 29)) + as.Contains(string(out), fmt.Sprintf("%d files changed", 30)) // globally exclude nix files cfg.Global.Excludes = []string{"*.nix"} @@ -137,7 +137,7 @@ func TestIncludesAndExcludes(t *testing.T) { test.WriteConfig(t, configPath, cfg) out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir) as.NoError(err) - as.Contains(string(out), fmt.Sprintf("%d files changed", 28)) + as.Contains(string(out), fmt.Sprintf("%d files changed", 29)) // add haskell files to the global exclude cfg.Global.Excludes = []string{"*.nix", "*.hs"} @@ -145,7 +145,7 @@ func TestIncludesAndExcludes(t *testing.T) { test.WriteConfig(t, configPath, cfg) out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir) as.NoError(err) - as.Contains(string(out), fmt.Sprintf("%d files changed", 22)) + as.Contains(string(out), fmt.Sprintf("%d files changed", 23)) echo := cfg.Formatters["echo"] @@ -155,7 +155,7 @@ func TestIncludesAndExcludes(t *testing.T) { test.WriteConfig(t, configPath, cfg) out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir) as.NoError(err) - as.Contains(string(out), fmt.Sprintf("%d files changed", 20)) + as.Contains(string(out), fmt.Sprintf("%d files changed", 21)) // remove go files from the echo formatter echo.Excludes = []string{"*.py", "*.go"} @@ -163,7 +163,7 @@ func TestIncludesAndExcludes(t *testing.T) { test.WriteConfig(t, configPath, cfg) out, err = cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir) as.NoError(err) - as.Contains(string(out), fmt.Sprintf("%d files changed", 19)) + as.Contains(string(out), fmt.Sprintf("%d files changed", 20)) // adjust the includes for echo to only include elm files echo.Includes = []string{"*.elm"} @@ -189,8 +189,8 @@ func TestCache(t *testing.T) { configPath := tempDir + "/echo.toml" // test without any excludes - cfg := config.Config{ - Formatters: map[string]*config.Formatter{ + cfg := config2.Config{ + Formatters: map[string]*config2.Formatter{ "echo": { Command: "echo", Includes: []string{"*"}, @@ -201,11 +201,34 @@ func TestCache(t *testing.T) { test.WriteConfig(t, configPath, cfg) out, err := cmd(t, "--config-file", configPath, "--tree-root", tempDir) as.NoError(err) - as.Contains(string(out), fmt.Sprintf("%d files changed", 29)) + as.Contains(string(out), fmt.Sprintf("%d files changed", 30)) out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir) 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", 30)) + + out, err = cmd(t, "--config-file", configPath, "--tree-root", tempDir) + 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", 30)) + + 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) + as.Contains(string(out), fmt.Sprintf("%d files changed", 30)) } func TestChangeWorkingDirectory(t *testing.T) { @@ -224,8 +247,8 @@ func TestChangeWorkingDirectory(t *testing.T) { configPath := tempDir + "/treefmt.toml" // test without any excludes - cfg := config.Config{ - Formatters: map[string]*config.Formatter{ + cfg := config2.Config{ + Formatters: map[string]*config2.Formatter{ "echo": { Command: "echo", Includes: []string{"*"}, @@ -239,7 +262,7 @@ func TestChangeWorkingDirectory(t *testing.T) { // this should fail if the working directory hasn't been changed first out, err := cmd(t, "-C", tempDir) as.NoError(err) - as.Contains(string(out), fmt.Sprintf("%d files changed", 29)) + as.Contains(string(out), fmt.Sprintf("%d files changed", 30)) } func TestFailOnChange(t *testing.T) { @@ -249,8 +272,8 @@ func TestFailOnChange(t *testing.T) { configPath := tempDir + "/echo.toml" // test without any excludes - cfg := config.Config{ - Formatters: map[string]*config.Formatter{ + cfg := config2.Config{ + Formatters: map[string]*config2.Formatter{ "echo": { Command: "echo", Includes: []string{"*"}, @@ -285,8 +308,8 @@ func TestBustCacheOnFormatterChange(t *testing.T) { as.NoError(os.Setenv("PATH", binPath+":"+os.Getenv("PATH"))) // start with 2 formatters - cfg := config.Config{ - Formatters: map[string]*config.Formatter{ + cfg := config2.Config{ + Formatters: map[string]*config2.Formatter{ "python": { Command: "black", Includes: []string{"*.py"}, @@ -330,7 +353,7 @@ func TestBustCacheOnFormatterChange(t *testing.T) { as.Contains(string(out), "0 files changed") // add go formatter - cfg.Formatters["go"] = &config.Formatter{ + cfg.Formatters["go"] = &config2.Formatter{ Command: "gofmt", Options: []string{"-w"}, Includes: []string{"*.go"}, @@ -380,8 +403,8 @@ func TestGitWorktree(t *testing.T) { configPath := filepath.Join(tempDir, "/treefmt.toml") // basic config - cfg := config.Config{ - Formatters: map[string]*config.Formatter{ + cfg := config2.Config{ + Formatters: map[string]*config2.Formatter{ "echo": { Command: "echo", Includes: []string{"*"}, @@ -416,16 +439,16 @@ func TestGitWorktree(t *testing.T) { // add everything to the worktree as.NoError(wt.AddGlob(".")) as.NoError(err) - run(29) + run(30) // remove python directory as.NoError(wt.RemoveGlob("python/*")) - run(26) + run(27) // walk with filesystem instead of git out, err := cmd(t, "-c", "--config-file", configPath, "--tree-root", tempDir, "--walk", "filesystem") as.NoError(err) - as.Contains(string(out), fmt.Sprintf("%d files changed", 55)) + as.Contains(string(out), fmt.Sprintf("%d files changed", 57)) } func TestOrderingFormatters(t *testing.T) { @@ -435,8 +458,8 @@ func TestOrderingFormatters(t *testing.T) { configPath := path.Join(tempDir, "treefmt.toml") // missing child - test.WriteConfig(t, configPath, config.Config{ - Formatters: map[string]*config.Formatter{ + test.WriteConfig(t, configPath, config2.Config{ + Formatters: map[string]*config2.Formatter{ "hs-a": { Command: "echo", Includes: []string{"*.hs"}, @@ -449,8 +472,8 @@ func TestOrderingFormatters(t *testing.T) { as.ErrorContains(err, "formatter hs-a is before hs-b but config for hs-b was not found") // multiple roots - test.WriteConfig(t, configPath, config.Config{ - Formatters: map[string]*config.Formatter{ + test.WriteConfig(t, configPath, config2.Config{ + Formatters: map[string]*config2.Formatter{ "hs-a": { Command: "echo", Includes: []string{"*.hs"}, @@ -501,8 +524,8 @@ func TestPathsArg(t *testing.T) { as.NoError(os.Chdir(tempDir)) // basic config - cfg := config.Config{ - Formatters: map[string]*config.Formatter{ + cfg := config2.Config{ + Formatters: map[string]*config2.Formatter{ "echo": { Command: "echo", Includes: []string{"*"}, @@ -514,7 +537,7 @@ func TestPathsArg(t *testing.T) { // without any path args out, err := cmd(t, "-C", tempDir) as.NoError(err) - as.Contains(string(out), fmt.Sprintf("%d files changed", 29)) + as.Contains(string(out), fmt.Sprintf("%d files changed", 30)) // specify some explicit paths out, err = cmd(t, "-C", tempDir, "-c", "elm/elm.json", "haskell/Nested/Foo.hs") @@ -545,8 +568,8 @@ func TestStdIn(t *testing.T) { as.NoError(os.Chdir(tempDir)) // basic config - cfg := config.Config{ - Formatters: map[string]*config.Formatter{ + cfg := config2.Config{ + Formatters: map[string]*config2.Formatter{ "echo": { Command: "echo", Includes: []string{"*"}, diff --git a/internal/cli/helpers_test.go b/cli/helpers_test.go similarity index 96% rename from internal/cli/helpers_test.go rename to cli/helpers_test.go index 7268d23..920c757 100644 --- a/internal/cli/helpers_test.go +++ b/cli/helpers_test.go @@ -7,7 +7,8 @@ import ( "path/filepath" "testing" - "git.numtide.com/numtide/treefmt/internal/test" + "git.numtide.com/numtide/treefmt/test" + "github.com/alecthomas/kong" "github.com/stretchr/testify/require" ) diff --git a/internal/config/config.go b/config/config.go similarity index 100% rename from internal/config/config.go rename to config/config.go diff --git a/internal/config/config_test.go b/config/config_test.go similarity index 98% rename from internal/config/config_test.go rename to config/config_test.go index 611fc04..6ab6a08 100644 --- a/internal/config/config_test.go +++ b/config/config_test.go @@ -9,7 +9,7 @@ import ( func TestReadConfigFile(t *testing.T) { as := require.New(t) - cfg, err := ReadFile("../../test/treefmt.toml") + cfg, err := ReadFile("../test/examples/treefmt.toml") as.NoError(err, "failed to read config file") as.NotNil(cfg) diff --git a/internal/config/formatter.go b/config/formatter.go similarity index 100% rename from internal/config/formatter.go rename to config/formatter.go diff --git a/internal/format/context.go b/format/context.go similarity index 100% rename from internal/format/context.go rename to format/context.go diff --git a/internal/format/formatter.go b/format/formatter.go similarity index 99% rename from internal/format/formatter.go rename to format/formatter.go index a2654dd..434addf 100644 --- a/internal/format/formatter.go +++ b/format/formatter.go @@ -7,7 +7,7 @@ import ( "os/exec" "time" - "git.numtide.com/numtide/treefmt/internal/config" + "git.numtide.com/numtide/treefmt/config" "github.com/charmbracelet/log" "github.com/gobwas/glob" diff --git a/internal/format/glob.go b/format/glob.go similarity index 100% rename from internal/format/glob.go rename to format/glob.go diff --git a/main.go b/main.go index 72d162e..35a2685 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,7 @@ package main import ( - "git.numtide.com/numtide/treefmt/internal/cli" + "git.numtide.com/numtide/treefmt/cli" "github.com/alecthomas/kong" ) diff --git a/test/echo.toml b/test/examples/echo.toml similarity index 100% rename from test/echo.toml rename to test/examples/echo.toml diff --git a/test/treefmt.toml b/test/examples/treefmt.toml similarity index 100% rename from test/treefmt.toml rename to test/examples/treefmt.toml diff --git a/internal/test/temp.go b/test/temp.go similarity index 86% rename from internal/test/temp.go rename to test/temp.go index 2324d1c..dbe6f50 100644 --- a/internal/test/temp.go +++ b/test/temp.go @@ -4,7 +4,7 @@ import ( "os" "testing" - "git.numtide.com/numtide/treefmt/internal/config" + "git.numtide.com/numtide/treefmt/config" "github.com/BurntSushi/toml" cp "github.com/otiai10/copy" @@ -25,7 +25,7 @@ func WriteConfig(t *testing.T, path string, cfg config.Config) { func TempExamples(t *testing.T) string { tempDir := t.TempDir() - require.NoError(t, cp.Copy("../../test/examples", tempDir), "failed to copy test data to temp dir") + require.NoError(t, cp.Copy("../test/examples", tempDir), "failed to copy test data to temp dir") return tempDir } diff --git a/internal/walk/filesystem.go b/walk/filesystem.go similarity index 100% rename from internal/walk/filesystem.go rename to walk/filesystem.go diff --git a/internal/walk/git.go b/walk/git.go similarity index 100% rename from internal/walk/git.go rename to walk/git.go diff --git a/internal/walk/walker.go b/walk/walker.go similarity index 100% rename from internal/walk/walker.go rename to walk/walker.go From d53f98ea051105f2456fc951109ab1ccfc2da611 Mon Sep 17 00:00:00 2001 From: Brian McGee Date: Thu, 15 Feb 2024 09:43:16 +0000 Subject: [PATCH 3/7] feat: support --version Signed-off-by: Brian McGee --- build/build.go | 6 ++++++ cli/cli.go | 1 + main.go | 15 +++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 build/build.go diff --git a/build/build.go b/build/build.go new file mode 100644 index 0000000..bd1c65e --- /dev/null +++ b/build/build.go @@ -0,0 +1,6 @@ +package build + +var ( + Name = "treefmt" + Version = "v0.0.1+dev" +) diff --git a/cli/cli.go b/cli/cli.go index ae7dbf2..8b23262 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -18,6 +18,7 @@ type Format struct { TreeRoot string `type:"existingdir" default:"."` Walk walk.Type `enum:"auto,git,filesystem" default:"auto" help:"The method used to traverse the files within --tree-root. Currently supports 'auto', 'git' or 'filesystem'."` Verbosity int `name:"verbose" short:"v" type:"counter" default:"0" env:"LOG_LEVEL" help:"Set the verbosity of logs e.g. -vv."` + Version bool `name:"version" short:"V" help:"Print version"` Paths []string `name:"paths" arg:"" type:"path" optional:"" help:"Paths to format. Defaults to formatting the whole tree."` Stdin bool `help:"Format the context passed in via stdin"` diff --git a/main.go b/main.go index 35a2685..714a4af 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,26 @@ package main import ( + "fmt" + "os" + + "git.numtide.com/numtide/treefmt/build" "git.numtide.com/numtide/treefmt/cli" "github.com/alecthomas/kong" ) func main() { + // This is to maintain compatibility with 1.0.0 which allows specifying the version with a `treefmt --version` flag + // on the 'default' command. With Kong it would be better to have `treefmt version` so it would be treated as a + // separate command. As it is, we would need to weaken some of the `existingdir` and `existingfile` checks kong is + // doing for us in the default format command. + for _, arg := range os.Args { + if arg == "--version" || arg == "-V" { + fmt.Printf("%s %s\n", build.Name, build.Version) + return + } + } + ctx := kong.Parse(&cli.Cli) ctx.FatalIfErrorf(ctx.Run()) } From da82b80f29beb85b0beeeeedcb1fdace2c2857d3 Mon Sep 17 00:00:00 2001 From: Brian McGee Date: Thu, 15 Feb 2024 10:37:33 +0000 Subject: [PATCH 4/7] feat: support --no-cache Signed-off-by: Brian McGee 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; --- cli/cli.go | 1 + cli/format.go | 40 +++++++++++++++++++++++++++++++++------- nix/packages.nix | 2 +- 3 files changed, 35 insertions(+), 8 deletions(-) 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; From cb8565d68365b1a548c4c1bd59385346a80aaa01 Mon Sep 17 00:00:00 2001 From: Brian McGee Date: Thu, 15 Feb 2024 10:48:03 +0000 Subject: [PATCH 5/7] fix: reduce log verbosity Signed-off-by: Brian McGee --- cli/cli.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/cli.go b/cli/cli.go index b370ee7..e1ed3a6 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -29,8 +29,10 @@ func (f *Format) Configure() { log.SetReportTimestamp(false) if f.Verbosity == 0 { + log.SetLevel(log.WarnLevel) + } else if f.Verbosity == 1 { log.SetLevel(log.InfoLevel) - } else if f.Verbosity > 0 { + } else if f.Verbosity > 1 { log.SetLevel(log.DebugLevel) } } From f4700c4e63f6981cad48f372143570d07f9b49a0 Mon Sep 17 00:00:00 2001 From: Brian McGee Date: Thu, 15 Feb 2024 14:00:47 +0000 Subject: [PATCH 6/7] doc: update licence copyright year Signed-off-by: Brian McGee --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index 919790d..d8ade38 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Treefmt Contributors +Copyright (c) 2024 Treefmt Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 2b49923bf7d01e78cb9a4b57b1095756e265c6ad Mon Sep 17 00:00:00 2001 From: Brian McGee Date: Thu, 15 Feb 2024 14:17:16 +0000 Subject: [PATCH 7/7] feat: add an example of 'before' Signed-off-by: Brian McGee --- config/config_test.go | 14 +++++++------- nix/formatters.nix | 2 ++ test/examples/treefmt.toml | 8 +++++++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/config/config_test.go b/config/config_test.go index 6ab6a08..f50e6c7 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -52,13 +52,13 @@ func TestReadConfigFile(t *testing.T) { as.Equal([]string{"*.hs"}, haskell.Includes) as.Equal([]string{"examples/haskell/"}, haskell.Excludes) - // nix - nix, ok := cfg.Formatters["nix"] - as.True(ok, "nix formatter not found") - as.Equal("alejandra", nix.Command) - as.Nil(nix.Options) - as.Equal([]string{"*.nix"}, nix.Includes) - as.Equal([]string{"examples/nix/sources.nix"}, nix.Excludes) + // alejandra + alejandra, ok := cfg.Formatters["alejandra"] + as.True(ok, "alejandra formatter not found") + as.Equal("alejandra", alejandra.Command) + as.Nil(alejandra.Options) + as.Equal([]string{"*.nix"}, alejandra.Includes) + as.Equal([]string{"examples/nix/sources.nix"}, alejandra.Excludes) // ruby ruby, ok := cfg.Formatters["ruby"] diff --git a/nix/formatters.nix b/nix/formatters.nix index 0d968de..9788f7f 100644 --- a/nix/formatters.nix +++ b/nix/formatters.nix @@ -12,5 +12,7 @@ with pkgs; [ rustfmt shellcheck shfmt + statix + deadnix terraform ] diff --git a/test/examples/treefmt.toml b/test/examples/treefmt.toml index c78bd78..699665a 100644 --- a/test/examples/treefmt.toml +++ b/test/examples/treefmt.toml @@ -26,11 +26,17 @@ options = [ includes = ["*.hs"] excludes = ["examples/haskell/"] -[formatter.nix] +[formatter.alejandra] command = "alejandra" includes = ["*.nix"] # Act as an example on how to exclude specific files excludes = ["examples/nix/sources.nix"] +# Make this run before deadnix +# Note this formatter determines the file set for any 'downstream' formatters +before = "deadnix" + +[formatter.deadnix] +command = "deadnix" [formatter.ruby] command = "rufo"