Brian McGee
5711caebb9
Introduces a `--walk` flag which can be used to tell `treefmt` how to traverse the directory specified by `--tree-root`. By default, it will attempt to use `git ls-files`. If this fails, it falls back to using the filesystem. You can explicitly traverse the filesystem instead of using git by providing `--walk filesystem`. Close #1 Reviewed-on: #19 Reviewed-by: Jonas Chevalier <zimbatm@noreply.git.numtide.com> Co-authored-by: Brian McGee <brian@bmcgee.ie> Co-committed-by: Brian McGee <brian@bmcgee.ie>
70 lines
1.1 KiB
Go
70 lines
1.1 KiB
Go
package walk
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
type git struct {
|
|
root string
|
|
}
|
|
|
|
func (g *git) Root() string {
|
|
return g.root
|
|
}
|
|
|
|
func (g *git) Walk(ctx context.Context, fn filepath.WalkFunc) error {
|
|
r, w := io.Pipe()
|
|
|
|
cmd := exec.Command("git", "-C", g.root, "ls-files")
|
|
cmd.Stdout = w
|
|
cmd.Stderr = w
|
|
|
|
eg := errgroup.Group{}
|
|
|
|
eg.Go(func() error {
|
|
scanner := bufio.NewScanner(r)
|
|
|
|
for scanner.Scan() {
|
|
select {
|
|
case <-ctx.Done():
|
|
return ctx.Err()
|
|
default:
|
|
line := scanner.Text()
|
|
path := filepath.Join(g.root, line)
|
|
|
|
// stat the file
|
|
info, err := os.Lstat(path)
|
|
if err = fn(path, info, err); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
if err := w.CloseWithError(cmd.Run()); err != nil {
|
|
return err
|
|
}
|
|
|
|
return eg.Wait()
|
|
}
|
|
|
|
func NewGit(root string) (Walker, error) {
|
|
// check if we're dealing with a git repository
|
|
cmd := exec.Command("git", "-C", root, "rev-parse", "--is-inside-work-tree")
|
|
_, err := cmd.CombinedOutput()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("%w: git repo check failed", err)
|
|
}
|
|
return &git{root}, nil
|
|
}
|