Files
config/directory.go
T
end f2b6c07ff7 fix: validate config after PostLoad hooks
Re-run validator after PostLoad, return errors from RootDir, and add Config
alias for C(). Hooks receive *T instead of *Manager.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 18:00:31 -07:00

62 lines
1.3 KiB
Go

package config
import (
"fmt"
"os"
"path/filepath"
)
// RootDir walks from the working directory upward, looking for searchName as a
// regular file. depth limits how many parent directories are checked (0 = CWD only).
func RootDir(searchName string, depth ...int) (string, error) {
cwd, err := os.Getwd()
if err != nil {
return "", err
}
depthVal := 0
if len(depth) > 0 {
depthVal = depth[0]
}
path, err := walkRootDir(searchName, cwd, depthVal)
if err != nil {
return "", err
}
if path == "" {
return "", fmt.Errorf("RootDir checked %d directories, no '%s' file found", depthVal+1, searchName)
}
return filepath.Abs(path)
}
// MustRootDir is like [RootDir] but panics on error.
func MustRootDir(searchName string, depth ...int) string {
dir, err := RootDir(searchName, depth...)
if err != nil {
panic(err)
}
return dir
}
func walkRootDir(searchName, path string, reverseDepth int) (string, error) {
candidate := filepath.Join(path, searchName)
info, err := os.Stat(candidate)
if err == nil {
if info.IsDir() {
return "", fmt.Errorf("RootDir found directory %q, expected a regular file", candidate)
}
return path, nil
}
if reverseDepth > 0 {
parent := filepath.Dir(path)
if parent == path {
return "", nil
}
return walkRootDir(searchName, parent, reverseDepth-1)
}
return "", nil
}