101 lines
1.8 KiB
Go
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
|
|
}
|