Don't depend on working directory in folders.FindDirWithLeaf (#54)

This is plumbing for allowing a configurable root that doesn't depend on
the working directory.
This commit is contained in:
Pieter Noordhuis 2022-09-14 15:08:55 +02:00 committed by GitHub
parent 14a45e701e
commit 281f25a627
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 18 deletions

View File

@ -2,30 +2,33 @@ package folders
import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
)
func FindDirWithLeaf(leaf string) (string, error) {
dir, err := os.Getwd()
if err != nil {
return "", fmt.Errorf("cannot find $PWD: %s", err)
}
// FindDirWithLeaf returns the first directory that holds `leaf`,
// traversing up to the root of the filesystem, starting at `dir`.
func FindDirWithLeaf(dir string, leaf string) (string, error) {
for {
_, err = os.Stat(fmt.Sprintf("%s/%s", dir, leaf))
_, err := os.Stat(filepath.Join(dir, leaf))
// No error means we found the leaf in dir.
if err == nil {
return dir, nil
}
// ErrNotExist means we continue traversal up the tree.
if errors.Is(err, os.ErrNotExist) {
// TODO: test on windows
next := path.Dir(dir)
if dir == next { // or stop at $HOME?..
return "", fmt.Errorf("cannot find %s anywhere", leaf)
next := filepath.Dir(dir)
if dir == next {
// Return if we cannot continue traversal.
return "", err
}
dir = next
continue
}
if err != nil {
return "", err
}
return dir, nil
return "", err
}
}

38
folders/folders_test.go Normal file
View File

@ -0,0 +1,38 @@
package folders
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFindDirWithLeaf(t *testing.T) {
wd, err := os.Getwd()
require.NoError(t, err)
root := filepath.Join(wd, "..")
// Find from working directory should work.
{
out, err := FindDirWithLeaf(wd, ".git")
assert.NoError(t, err)
assert.Equal(t, out, root)
}
// Find from project root itself should work.
{
out, err := FindDirWithLeaf(root, ".git")
assert.NoError(t, err)
assert.Equal(t, out, root)
}
// Find for something that doesn't exist should work.
{
out, err := FindDirWithLeaf(root, "this-leaf-doesnt-exist-anywhere")
assert.ErrorIs(t, err, os.ErrNotExist)
assert.Equal(t, out, "")
}
}

View File

@ -3,6 +3,7 @@ package git
import (
"fmt"
"net/url"
"os"
"path"
"strings"
@ -12,7 +13,11 @@ import (
)
func Root() (string, error) {
return folders.FindDirWithLeaf(".git")
wd, err := os.Getwd()
if err != nil {
return "", err
}
return folders.FindDirWithLeaf(wd, ".git")
}
// Origin finds the git repository the project is cloned from, so that

View File

@ -1,6 +1,7 @@
package project
import (
"errors"
"fmt"
"io"
"os"
@ -104,5 +105,15 @@ func validateAndApplyProjectDefaults(prj Project) (Project, error) {
}
func findProjectRoot() (string, error) {
return folders.FindDirWithLeaf(ConfigFile)
wd, err := os.Getwd()
if err != nil {
return "", err
}
dir, err := folders.FindDirWithLeaf(wd, ConfigFile)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return "", fmt.Errorf("cannot find %s anywhere", ConfigFile)
}
}
return dir, nil
}