mirror of
https://github.com/go-task/task.git
synced 2026-06-11 09:51:50 +00:00
feat: recursive config search (#2166)
* refactor: experiments flags * refactor: args.Parse * feat: recursive search for taskrc files * feat: consolidate some code into new fsext package * feat: add tests for search and default dir * fix: linting issues
This commit is contained in:
@@ -2,8 +2,6 @@ package taskfile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -11,6 +9,7 @@ import (
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/internal/experiments"
|
||||
"github.com/go-task/task/v3/internal/fsext"
|
||||
)
|
||||
|
||||
type Node interface {
|
||||
@@ -34,7 +33,7 @@ func NewRootNode(
|
||||
insecure bool,
|
||||
timeout time.Duration,
|
||||
) (Node, error) {
|
||||
dir = getDefaultDir(entrypoint, dir)
|
||||
dir = fsext.DefaultDir(entrypoint, dir)
|
||||
// If the entrypoint is "-", we read from stdin
|
||||
if entrypoint == "-" {
|
||||
return NewStdinNode(dir)
|
||||
@@ -87,26 +86,3 @@ func getScheme(uri string) (string, error) {
|
||||
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func getDefaultDir(entrypoint, dir string) string {
|
||||
// If the entrypoint and dir are empty, we default the directory to the current working directory
|
||||
if dir == "" {
|
||||
if entrypoint == "" {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
dir = wd
|
||||
}
|
||||
return dir
|
||||
}
|
||||
|
||||
// If the directory is set, ensure it is an absolute path
|
||||
var err error
|
||||
dir, err = filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return dir
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/filepathext"
|
||||
"github.com/go-task/task/v3/internal/fsext"
|
||||
)
|
||||
|
||||
// A FileNode is a node that reads a taskfile from the local filesystem.
|
||||
@@ -19,7 +20,7 @@ type FileNode struct {
|
||||
func NewFileNode(entrypoint, dir string, opts ...NodeOption) (*FileNode, error) {
|
||||
var err error
|
||||
base := NewBaseNode(dir, opts...)
|
||||
entrypoint, base.dir, err = resolveFileNodeEntrypointAndDir(entrypoint, base.dir)
|
||||
entrypoint, base.dir, err = fsext.Search(entrypoint, base.dir, defaultTaskfiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -42,34 +43,6 @@ func (node *FileNode) Read() ([]byte, error) {
|
||||
return io.ReadAll(f)
|
||||
}
|
||||
|
||||
// resolveFileNodeEntrypointAndDir resolves checks the values of entrypoint and dir and
|
||||
// populates them with default values if necessary.
|
||||
func resolveFileNodeEntrypointAndDir(entrypoint, dir string) (string, string, error) {
|
||||
var err error
|
||||
if entrypoint != "" {
|
||||
entrypoint, err = Exists(entrypoint)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
if dir == "" {
|
||||
dir = filepath.Dir(entrypoint)
|
||||
}
|
||||
return entrypoint, dir, nil
|
||||
}
|
||||
if dir == "" {
|
||||
dir, err = os.Getwd()
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
}
|
||||
entrypoint, err = ExistsWalk(dir)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
dir = filepath.Dir(entrypoint)
|
||||
return entrypoint, dir, nil
|
||||
}
|
||||
|
||||
func (node *FileNode) ResolveEntrypoint(entrypoint string) (string, error) {
|
||||
// If the file is remote, we don't need to resolve the path
|
||||
if strings.Contains(entrypoint, "://") {
|
||||
|
||||
@@ -5,14 +5,10 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/internal/filepathext"
|
||||
"github.com/go-task/task/v3/internal/sysinfo"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -94,65 +90,3 @@ func RemoteExists(ctx context.Context, u *url.URL) (*url.URL, error) {
|
||||
|
||||
return nil, errors.TaskfileNotFoundError{URI: u.String(), Walk: false}
|
||||
}
|
||||
|
||||
// Exists will check if a file at the given path Exists. If it does, it will
|
||||
// return the path to it. If it does not, it will search for any files at the
|
||||
// given path with any of the default Taskfile files names. If any of these
|
||||
// match a file, the first matching path will be returned. If no files are
|
||||
// found, an error will be returned.
|
||||
func Exists(path string) (string, error) {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if fi.Mode().IsRegular() ||
|
||||
fi.Mode()&os.ModeDevice != 0 ||
|
||||
fi.Mode()&os.ModeSymlink != 0 ||
|
||||
fi.Mode()&os.ModeNamedPipe != 0 {
|
||||
return filepath.Abs(path)
|
||||
}
|
||||
|
||||
for _, taskfile := range defaultTaskfiles {
|
||||
alt := filepathext.SmartJoin(path, taskfile)
|
||||
if _, err := os.Stat(alt); err == nil {
|
||||
return filepath.Abs(alt)
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.TaskfileNotFoundError{URI: path, Walk: false}
|
||||
}
|
||||
|
||||
// ExistsWalk will check if a file at the given path exists by calling the
|
||||
// exists function. If a file is not found, it will walk up the directory tree
|
||||
// calling the exists function until it finds a file or reaches the root
|
||||
// directory. On supported operating systems, it will also check if the user ID
|
||||
// of the directory changes and abort if it does.
|
||||
func ExistsWalk(path string) (string, error) {
|
||||
origPath := path
|
||||
owner, err := sysinfo.Owner(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for {
|
||||
fpath, err := Exists(path)
|
||||
if err == nil {
|
||||
return fpath, nil
|
||||
}
|
||||
|
||||
// Get the parent path/user id
|
||||
parentPath := filepath.Dir(path)
|
||||
parentOwner, err := sysinfo.Owner(parentPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Error if we reached the root directory and still haven't found a file
|
||||
// OR if the user id of the directory changes
|
||||
if path == parentPath || (parentOwner != owner) {
|
||||
return "", errors.TaskfileNotFoundError{URI: origPath, Walk: false}
|
||||
}
|
||||
|
||||
owner = parentOwner
|
||||
path = parentPath
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user