This repository has been archived on 2024-05-03. You can view files and clone it, but cannot push or open issues or pull requests.
treefmt/walk/git.go
Brian McGee 6d9ce65f6c
feat: use go-walk
Signed-off-by: Brian McGee <brian@bmcgee.ie>
2024-02-28 09:40:54 +00:00

101 lines
1.8 KiB
Go

package walk
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"github.com/opencoff/go-walk"
"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
paths []string
repo *git.Repository
}
func (g *gitWalker) Root() string {
return g.root
}
func (g *gitWalker) Walk(ctx context.Context, fn filepath.WalkFunc) error {
idx, err := g.repo.Storer.Index()
if err != nil {
return fmt.Errorf("%w: failed to open index", err)
}
if len(g.paths) > 0 {
walkOpts := walk.Options{
OneFS: true,
Type: walk.FILE,
FollowSymlinks: false,
}
ch, errCh := walk.Walk(g.paths, &walkOpts)
for {
select {
case <-ctx.Done():
return ctx.Err()
case err := <-errCh:
if err != nil {
return err
}
case file, ok := <-ch:
if !ok {
return nil
}
relPath, err := filepath.Rel(g.root, file.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, file.Path)
return nil
} else if err = fn(file.Path, file.Stat, err); 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, 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, paths, repo}, nil
}