Skip to content

Commit

Permalink
cli: search for the tree root by default
Browse files Browse the repository at this point in the history
Restore the treefmt 1.x behaviour where it would search for the tree
root by recursively searching for the treefmt.toml file up the
filesystem, starting from the current directory.

The `--tree-root-file` option will be useful to remove this bash wrapper: https://github.com/numtide/treefmt-nix/blob/2fba33a182602b9d49f0b2440513e5ee091d838b/module-options.nix#L116-L135

Fixes #308
  • Loading branch information
zimbatm committed May 30, 2024
1 parent 0223983 commit bd32d36
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 2 deletions.
5 changes: 3 additions & 2 deletions cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@ type Format struct {
WorkingDirectory kong.ChangeDirFlag `default:"." short:"C" help:"Run as if treefmt was started in the specified working directory instead of the current working directory."`
NoCache bool `help:"Ignore the evaluation cache entirely. Useful for CI."`
ClearCache bool `short:"c" help:"Reset the evaluation cache. Use in case the cache is not precise enough."`
ConfigFile string `type:"existingfile" default:"./treefmt.toml" help:"The config file to use."`
ConfigFile string `type:"path" help:"Load the config file from the given path (defaults to finding treefmt.toml up)."`
FailOnChange bool `help:"Exit with error if any changes were made. Useful for CI."`
Formatters []string `short:"f" help:"Specify formatters to apply. Defaults to all formatters."`
TreeRoot string `type:"existingdir" default:"." help:"The root directory from which treefmt will start walking the filesystem."`
TreeRoot string `type:"path" help:"The root directory from which treefmt will start walking the filesystem (defaults to the directory containing the config file)."`
TreeRootFile string `type:"path" help:"File to search for to find the project root (if --tree-root is not passed)."`
Walk walk.Type `enum:"auto,git,filesystem" default:"auto" help:"The method used to traverse the files within --tree-root. Currently supports 'auto', 'git' or 'filesystem'."`
Verbosity int `name:"verbose" short:"v" type:"counter" default:"0" env:"LOG_LEVEL" help:"Set the verbosity of logs e.g. -vv."`
Version bool `name:"version" short:"V" help:"Print version."`
Expand Down
87 changes: 87 additions & 0 deletions cli/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,40 @@ func (f *Format) Run() (err error) {
}
}()

// find the config file unless specified
if Cli.ConfigFile == "" {
pwd, err := os.Getwd()
if err != nil {
return err
}
Cli.ConfigFile, _, err = findUp(pwd, "treefmt.toml")
if err != nil {
return err
}
}

// search for the project root unless specified
if Cli.TreeRoot == "" {
// use the location of the treefmt.toml file by default
dir := filepath.Dir(Cli.ConfigFile)

// search using the --tree-root-file if specified
if Cli.TreeRootFile != "" {
pwd, err := os.Getwd()
if err != nil {
return err
}
_, dir, err = findUp(pwd, Cli.TreeRootFile)
if err != nil {
return err
}
}

Cli.TreeRoot = dir
}

log.Debugf("config-file=%s tree-root=%s", Cli.ConfigFile, Cli.TreeRoot)

// read config
cfg, err := config.ReadFile(Cli.ConfigFile, Cli.Formatters)
if err != nil {
Expand Down Expand Up @@ -384,3 +418,56 @@ func applyFormatters(ctx context.Context) func() error {
return nil
}
}

func findUp(searchDir string, fileName string) (path string, dir string, err error) {
for _, dir := range eachDir(searchDir) {
path := filepath.Join(dir, fileName)
if fileExists(path) {
return path, dir, nil
}
}
return "", "", fmt.Errorf("could not find %s in %s", fileName, searchDir)
}

func eachDir(path string) (paths []string) {
path, err := filepath.Abs(path)
if err != nil {
return
}

paths = []string{path}

if path == "/" {
return
}

for i := len(path) - 1; i >= 0; i-- {
if path[i] == os.PathSeparator {
path = path[:i]
if path == "" {
path = "/"
}
paths = append(paths, path)
}
}

return
}

func fileExists(path string) bool {
// Some broken filesystems like SSHFS return file information on stat() but
// then cannot open the file. So we use os.Open.
f, err := os.Open(path)
if err != nil {
return false
}
defer f.Close()

// Next, check that the file is a regular file.
fi, err := f.Stat()
if err != nil {
return false
}

return fi.Mode().IsRegular()
}

0 comments on commit bd32d36

Please sign in to comment.