9 "github.com/charmbracelet/crush/internal/home"
12// Lookup searches for a target files or directories starting from dir
13// and walking up the directory tree until filesystem root is reached.
14// It also checks the ownership of files to ensure that the search does
15// not cross ownership boundaries. It skips ownership mismatches without
17// Returns full paths to fount targets.
18// The search includes the starting directory itself.
19func Lookup(dir string, targets ...string) ([]string, error) {
20 if len(targets) == 0 {
26 err := traverseUp(dir, func(cwd string, owner int) error {
27 for _, target := range targets {
28 fpath := filepath.Join(cwd, target)
29 err := probeEnt(fpath, owner)
31 // skip to the next file on permission denied
32 if errors.Is(err, os.ErrNotExist) ||
33 errors.Is(err, os.ErrPermission) {
38 return fmt.Errorf("error probing file %s: %w", fpath, err)
41 found = append(found, fpath)
53// LookupClosest searches for a target file or directory starting from dir
54// and walking up the directory tree until found or root or home is reached.
55// It also checks the ownership of files to ensure that the search does
56// not cross ownership boundaries.
57// Returns the full path to the target if found, empty string and false otherwise.
58// The search includes the starting directory itself.
59func LookupClosest(dir, target string) (string, bool) {
62 err := traverseUp(dir, func(cwd string, owner int) error {
63 fpath := filepath.Join(cwd, target)
65 err := probeEnt(fpath, owner)
66 if errors.Is(err, os.ErrNotExist) {
71 return fmt.Errorf("error probing file %s: %w", fpath, err)
74 if cwd == home.Dir() {
75 return filepath.SkipAll
79 return filepath.SkipAll
82 return found, err == nil && found != ""
85// traverseUp walks up from given directory up until filesystem root reached.
86// It passes absolute path of current directory and staring directory owner ID
87// to callback function. It is up to user to check ownership.
88func traverseUp(dir string, walkFn func(dir string, owner int) error) error {
89 cwd, err := filepath.Abs(dir)
91 return fmt.Errorf("cannot convert CWD to absolute path: %w", err)
94 owner, err := Owner(dir)
96 return fmt.Errorf("cannot get ownership: %w", err)
100 err := walkFn(cwd, owner)
101 if err == nil || errors.Is(err, filepath.SkipDir) {
102 parent := filepath.Dir(cwd)
111 if errors.Is(err, filepath.SkipAll) {
119// probeEnt checks if entity at given path exists and belongs to given owner
120func probeEnt(fspath string, owner int) error {
121 _, err := os.Stat(fspath)
123 return fmt.Errorf("cannot stat %s: %w", fspath, err)
126 // special case for ownership check bypass
131 fowner, err := Owner(fspath)
133 return fmt.Errorf("cannot get ownership for %s: %w", fspath, err)
137 return os.ErrPermission
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list