mirror of
https://github.com/go-task/task.git
synced 2024-12-04 10:24:45 +02:00
feat: root remote taskfiles
This commit is contained in:
parent
f00693052a
commit
cbc19d35ea
@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
@ -94,11 +93,6 @@ func run() error {
|
||||
dir = home
|
||||
}
|
||||
|
||||
if entrypoint != "" {
|
||||
dir = filepath.Dir(entrypoint)
|
||||
entrypoint = filepath.Base(entrypoint)
|
||||
}
|
||||
|
||||
var taskSorter sort.TaskSorter
|
||||
switch flags.TaskSort {
|
||||
case "none":
|
||||
|
@ -131,10 +131,6 @@ func Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if Dir != "" && Entrypoint != "" {
|
||||
return errors.New("task: You can't set both --dir and --taskfile")
|
||||
}
|
||||
|
||||
if Output.Name != "group" {
|
||||
if Output.Group.Begin != "" {
|
||||
return errors.New("task: You can't set --output-group-begin without --output=group")
|
||||
|
4
setup.go
4
setup.go
@ -54,11 +54,11 @@ func (e *Executor) Setup() error {
|
||||
}
|
||||
|
||||
func (e *Executor) getRootNode() (taskfile.Node, error) {
|
||||
node, err := taskfile.NewRootNode(e.Dir, e.Entrypoint, e.Insecure)
|
||||
node, err := taskfile.NewRootNode(e.Logger, e.Entrypoint, e.Dir, e.Insecure)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.Dir = node.BaseDir()
|
||||
e.Dir = node.Dir()
|
||||
return node, err
|
||||
}
|
||||
|
||||
|
16
task_test.go
16
task_test.go
@ -73,7 +73,7 @@ func (fct fileContentTest) Run(t *testing.T) {
|
||||
|
||||
for name, expectContent := range fct.Files {
|
||||
t.Run(fct.name(name), func(t *testing.T) {
|
||||
path := filepathext.SmartJoin(fct.Dir, name)
|
||||
path := filepathext.SmartJoin(e.Dir, name)
|
||||
b, err := os.ReadFile(path)
|
||||
require.NoError(t, err, "Error reading file")
|
||||
s := string(b)
|
||||
@ -1123,8 +1123,8 @@ func TestIncludesOptionalExplicitFalse(t *testing.T) {
|
||||
|
||||
func TestIncludesFromCustomTaskfile(t *testing.T) {
|
||||
tt := fileContentTest{
|
||||
Entrypoint: "testdata/includes_yaml/Custom.ext",
|
||||
Dir: "testdata/includes_yaml",
|
||||
Entrypoint: "Custom.ext",
|
||||
Target: "default",
|
||||
TrimSpace: true,
|
||||
Files: map[string]string{
|
||||
@ -1486,16 +1486,12 @@ func TestDotenvShouldIncludeAllEnvFiles(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDotenvShouldErrorWhenIncludingDependantDotenvs(t *testing.T) {
|
||||
const dir = "testdata/dotenv/error_included_envs"
|
||||
const entry = "Taskfile.yml"
|
||||
|
||||
var buff bytes.Buffer
|
||||
e := task.Executor{
|
||||
Dir: dir,
|
||||
Entrypoint: entry,
|
||||
Summary: true,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
Dir: "testdata/dotenv/error_included_envs",
|
||||
Summary: true,
|
||||
Stdout: &buff,
|
||||
Stderr: &buff,
|
||||
}
|
||||
|
||||
err := e.Setup()
|
||||
|
@ -2,13 +2,9 @@ package ast
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/filepathext"
|
||||
omap "github.com/go-task/task/v3/internal/omap"
|
||||
)
|
||||
|
||||
@ -22,7 +18,6 @@ type Include struct {
|
||||
Aliases []string
|
||||
AdvancedImport bool
|
||||
Vars *Vars
|
||||
BaseDir string // The directory from which the including taskfile was loaded; used to resolve relative paths
|
||||
}
|
||||
|
||||
// Includes represents information about included tasksfiles
|
||||
@ -120,39 +115,5 @@ func (include *Include) DeepCopy() *Include {
|
||||
Internal: include.Internal,
|
||||
AdvancedImport: include.AdvancedImport,
|
||||
Vars: include.Vars.DeepCopy(),
|
||||
BaseDir: include.BaseDir,
|
||||
}
|
||||
}
|
||||
|
||||
// FullTaskfilePath returns the fully qualified path to the included taskfile
|
||||
func (include *Include) FullTaskfilePath() (string, error) {
|
||||
return include.resolvePath(include.Taskfile)
|
||||
}
|
||||
|
||||
// FullDirPath returns the fully qualified path to the included taskfile's working directory
|
||||
func (include *Include) FullDirPath() (string, error) {
|
||||
return include.resolvePath(include.Dir)
|
||||
}
|
||||
|
||||
func (include *Include) resolvePath(path string) (string, error) {
|
||||
// If the file is remote, we don't need to resolve the path
|
||||
if strings.Contains(include.Taskfile, "://") {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
path, err := execext.Expand(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if filepathext.IsAbs(path) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
result, err := filepath.Abs(filepathext.SmartJoin(include.BaseDir, path))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("task: error resolving path %s relative to %s: %w", path, include.BaseDir, err)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
@ -8,20 +8,25 @@ import (
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/internal/experiments"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/taskfile/ast"
|
||||
)
|
||||
|
||||
type Node interface {
|
||||
Read(ctx context.Context) ([]byte, error)
|
||||
Parent() Node
|
||||
Location() string
|
||||
Dir() string
|
||||
Optional() bool
|
||||
Remote() bool
|
||||
BaseDir() string
|
||||
ResolveIncludeEntrypoint(include ast.Include) (string, error)
|
||||
ResolveIncludeDir(include ast.Include) (string, error)
|
||||
}
|
||||
|
||||
func NewRootNode(
|
||||
dir string,
|
||||
l *logger.Logger,
|
||||
entrypoint string,
|
||||
dir string,
|
||||
insecure bool,
|
||||
) (Node, error) {
|
||||
dir = getDefaultDir(entrypoint, dir)
|
||||
@ -30,32 +35,24 @@ func NewRootNode(
|
||||
if (stat.Mode()&os.ModeCharDevice) == 0 && stat.Size() > 0 {
|
||||
return NewStdinNode(dir)
|
||||
}
|
||||
// If no entrypoint is specified, search for a taskfile
|
||||
if entrypoint == "" {
|
||||
root, err := ExistsWalk(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewNode(root, insecure)
|
||||
}
|
||||
// Use the specified entrypoint
|
||||
uri := filepath.Join(dir, entrypoint)
|
||||
return NewNode(uri, insecure)
|
||||
return NewNode(l, entrypoint, dir, insecure)
|
||||
}
|
||||
|
||||
func NewNode(
|
||||
uri string,
|
||||
l *logger.Logger,
|
||||
entrypoint string,
|
||||
dir string,
|
||||
insecure bool,
|
||||
opts ...NodeOption,
|
||||
) (Node, error) {
|
||||
var node Node
|
||||
var err error
|
||||
switch getScheme(uri) {
|
||||
switch getScheme(entrypoint) {
|
||||
case "http", "https":
|
||||
node, err = NewHTTPNode(uri, insecure, opts...)
|
||||
node, err = NewHTTPNode(l, entrypoint, dir, insecure, opts...)
|
||||
default:
|
||||
// If no other scheme matches, we assume it's a file
|
||||
node, err = NewFileNode(uri, opts...)
|
||||
node, err = NewFileNode(l, entrypoint, dir, opts...)
|
||||
}
|
||||
if node.Remote() && !experiments.RemoteTaskfiles.Enabled {
|
||||
return nil, errors.New("task: Remote taskfiles are not enabled. You can read more about this experiment and how to enable it at https://taskfile.dev/experiments/remote-taskfiles")
|
||||
|
@ -9,6 +9,7 @@ type (
|
||||
BaseNode struct {
|
||||
parent Node
|
||||
optional bool
|
||||
dir string
|
||||
}
|
||||
)
|
||||
|
||||
@ -16,6 +17,7 @@ func NewBaseNode(opts ...NodeOption) *BaseNode {
|
||||
node := &BaseNode{
|
||||
parent: nil,
|
||||
optional: false,
|
||||
dir: "",
|
||||
}
|
||||
|
||||
// Apply options
|
||||
@ -45,3 +47,7 @@ func WithOptional(optional bool) NodeOption {
|
||||
func (node *BaseNode) Optional() bool {
|
||||
return node.optional
|
||||
}
|
||||
|
||||
func (node *BaseNode) Dir() string {
|
||||
return node.dir
|
||||
}
|
||||
|
@ -5,39 +5,36 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/filepathext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/taskfile/ast"
|
||||
)
|
||||
|
||||
// A FileNode is a node that reads a taskfile from the local filesystem.
|
||||
type FileNode struct {
|
||||
*BaseNode
|
||||
Dir string
|
||||
Entrypoint string
|
||||
}
|
||||
|
||||
func NewFileNode(uri string, opts ...NodeOption) (*FileNode, error) {
|
||||
func NewFileNode(l *logger.Logger, entrypoint, dir string, opts ...NodeOption) (*FileNode, error) {
|
||||
var err error
|
||||
base := NewBaseNode(opts...)
|
||||
if uri == "" {
|
||||
d, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uri = d
|
||||
}
|
||||
path, err := Exists(uri)
|
||||
entrypoint, dir, err = resolveFileNodeEntrypointAndDir(l, entrypoint, dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
base.dir = dir
|
||||
return &FileNode{
|
||||
BaseNode: base,
|
||||
Dir: filepath.Dir(path),
|
||||
Entrypoint: filepath.Base(path),
|
||||
Entrypoint: entrypoint,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (node *FileNode) Location() string {
|
||||
return filepathext.SmartJoin(node.Dir, node.Entrypoint)
|
||||
return node.Entrypoint
|
||||
}
|
||||
|
||||
func (node *FileNode) Remote() bool {
|
||||
@ -53,6 +50,67 @@ func (node *FileNode) Read(ctx context.Context) ([]byte, error) {
|
||||
return io.ReadAll(f)
|
||||
}
|
||||
|
||||
func (node *FileNode) BaseDir() string {
|
||||
return node.Dir
|
||||
// resolveFileNodeEntrypointAndDir resolves checks the values of entrypoint and dir and
|
||||
// populates them with default values if necessary.
|
||||
func resolveFileNodeEntrypointAndDir(l *logger.Logger, entrypoint, dir string) (string, string, error) {
|
||||
var err error
|
||||
if entrypoint != "" {
|
||||
entrypoint, err = Exists(l, 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(l, dir)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
dir = filepath.Dir(entrypoint)
|
||||
return entrypoint, dir, nil
|
||||
}
|
||||
|
||||
func (node *FileNode) ResolveIncludeEntrypoint(include ast.Include) (string, error) {
|
||||
// If the file is remote, we don't need to resolve the path
|
||||
if strings.Contains(include.Taskfile, "://") {
|
||||
return include.Taskfile, nil
|
||||
}
|
||||
|
||||
path, err := execext.Expand(include.Taskfile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if filepathext.IsAbs(path) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
|
||||
// This means that files are included relative to one another
|
||||
entrypointDir := filepath.Dir(node.Entrypoint)
|
||||
return filepathext.SmartJoin(entrypointDir, path), nil
|
||||
}
|
||||
|
||||
func (node *FileNode) ResolveIncludeDir(include ast.Include) (string, error) {
|
||||
path, err := execext.Expand(include.Dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if filepathext.IsAbs(path) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
|
||||
// This means that files are included relative to one another
|
||||
entrypointDir := filepath.Dir(node.Entrypoint)
|
||||
return filepathext.SmartJoin(entrypointDir, path), nil
|
||||
}
|
||||
|
@ -5,8 +5,13 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/go-task/task/v3/errors"
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/filepathext"
|
||||
"github.com/go-task/task/v3/internal/logger"
|
||||
"github.com/go-task/task/v3/taskfile/ast"
|
||||
)
|
||||
|
||||
// An HTTPNode is a node that reads a Taskfile from a remote location via HTTP.
|
||||
@ -15,14 +20,19 @@ type HTTPNode struct {
|
||||
URL *url.URL
|
||||
}
|
||||
|
||||
func NewHTTPNode(uri string, insecure bool, opts ...NodeOption) (*HTTPNode, error) {
|
||||
func NewHTTPNode(l *logger.Logger, entrypoint, dir string, insecure bool, opts ...NodeOption) (*HTTPNode, error) {
|
||||
base := NewBaseNode(opts...)
|
||||
url, err := url.Parse(uri)
|
||||
base.dir = dir
|
||||
url, err := url.Parse(entrypoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if url.Scheme == "http" && !insecure {
|
||||
return nil, &errors.TaskfileNotSecureError{URI: uri}
|
||||
return nil, &errors.TaskfileNotSecureError{URI: entrypoint}
|
||||
}
|
||||
url, err = RemoteExists(l, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &HTTPNode{
|
||||
BaseNode: base,
|
||||
@ -66,6 +76,26 @@ func (node *HTTPNode) Read(ctx context.Context) ([]byte, error) {
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (node *HTTPNode) BaseDir() string {
|
||||
return ""
|
||||
func (node *HTTPNode) ResolveIncludeEntrypoint(include ast.Include) (string, error) {
|
||||
ref, err := url.Parse(include.Taskfile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return node.URL.ResolveReference(ref).String(), nil
|
||||
}
|
||||
|
||||
func (node *HTTPNode) ResolveIncludeDir(include ast.Include) (string, error) {
|
||||
path, err := execext.Expand(include.Dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if filepathext.IsAbs(path) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// NOTE: Uses the directory of the entrypoint (Taskfile), not the current working directory
|
||||
// This means that files are included relative to one another
|
||||
entrypointDir := filepath.Dir(node.Dir())
|
||||
return filepathext.SmartJoin(entrypointDir, path), nil
|
||||
}
|
||||
|
@ -5,19 +5,23 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/go-task/task/v3/internal/execext"
|
||||
"github.com/go-task/task/v3/internal/filepathext"
|
||||
"github.com/go-task/task/v3/taskfile/ast"
|
||||
)
|
||||
|
||||
// A StdinNode is a node that reads a taskfile from the standard input stream.
|
||||
type StdinNode struct {
|
||||
*BaseNode
|
||||
Dir string
|
||||
}
|
||||
|
||||
func NewStdinNode(dir string) (*StdinNode, error) {
|
||||
base := NewBaseNode()
|
||||
base.dir = dir
|
||||
return &StdinNode{
|
||||
BaseNode: base,
|
||||
Dir: dir,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -41,6 +45,33 @@ func (node *StdinNode) Read(ctx context.Context) ([]byte, error) {
|
||||
return stdin, nil
|
||||
}
|
||||
|
||||
func (node *StdinNode) BaseDir() string {
|
||||
return node.Dir
|
||||
func (node *StdinNode) ResolveIncludeEntrypoint(include ast.Include) (string, error) {
|
||||
// If the file is remote, we don't need to resolve the path
|
||||
if strings.Contains(include.Taskfile, "://") {
|
||||
return include.Taskfile, nil
|
||||
}
|
||||
|
||||
path, err := execext.Expand(include.Taskfile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if filepathext.IsAbs(path) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
return filepathext.SmartJoin(node.Dir(), path), nil
|
||||
}
|
||||
|
||||
func (node *StdinNode) ResolveIncludeDir(include ast.Include) (string, error) {
|
||||
path, err := execext.Expand(include.Dir)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if filepathext.IsAbs(path) {
|
||||
return path, nil
|
||||
}
|
||||
|
||||
return filepathext.SmartJoin(node.Dir(), path), nil
|
||||
}
|
||||
|
@ -48,17 +48,6 @@ func Read(
|
||||
return nil, &errors.TaskfileVersionCheckError{URI: node.Location()}
|
||||
}
|
||||
|
||||
if dir := node.BaseDir(); dir != "" {
|
||||
_ = tf.Includes.Range(func(namespace string, include ast.Include) error {
|
||||
// Set the base directory for resolving relative paths, but only if not already set
|
||||
if include.BaseDir == "" {
|
||||
include.BaseDir = dir
|
||||
tf.Includes.Set(namespace, include)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
err = tf.Includes.Range(func(namespace string, include ast.Include) error {
|
||||
cache := &templater.Cache{Vars: tf.Vars}
|
||||
include = ast.Include{
|
||||
@ -70,18 +59,22 @@ func Read(
|
||||
Aliases: include.Aliases,
|
||||
AdvancedImport: include.AdvancedImport,
|
||||
Vars: include.Vars,
|
||||
BaseDir: include.BaseDir,
|
||||
}
|
||||
if err := cache.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
uri, err := include.FullTaskfilePath()
|
||||
entrypoint, err := node.ResolveIncludeEntrypoint(include)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
includeReaderNode, err := NewNode(uri, insecure,
|
||||
dir, err := node.ResolveIncludeDir(include)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
includeReaderNode, err := NewNode(l, entrypoint, dir, insecure,
|
||||
WithParent(node),
|
||||
WithOptional(include.Optional),
|
||||
)
|
||||
@ -109,11 +102,6 @@ func Read(
|
||||
}
|
||||
|
||||
if include.AdvancedImport {
|
||||
dir, err := include.FullDirPath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
includedTaskfile.Vars.Range(func(k string, v ast.Var) error {
|
||||
o := v
|
||||
|
@ -1,11 +1,16 @@
|
||||
package taskfile
|
||||
|
||||
import (
|
||||
"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/logger"
|
||||
"github.com/go-task/task/v3/internal/sysinfo"
|
||||
)
|
||||
|
||||
@ -23,14 +28,80 @@ var (
|
||||
"Taskfile.dist.yaml",
|
||||
"taskfile.dist.yaml",
|
||||
}
|
||||
|
||||
allowedContentTypes = []string{
|
||||
"text/plain",
|
||||
"text/yaml",
|
||||
"text/x-yaml",
|
||||
"application/yaml",
|
||||
"application/x-yaml",
|
||||
}
|
||||
)
|
||||
|
||||
// RemoteExists will check if a file at the given URL Exists. If it does, it
|
||||
// will return its URL. If it does not, it will search the search for any files
|
||||
// at the given URL 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 RemoteExists(l *logger.Logger, u *url.URL) (*url.URL, error) {
|
||||
// Create a new HEAD request for the given URL to check if the resource exists
|
||||
req, err := http.NewRequest("HEAD", u.String(), nil)
|
||||
if err != nil {
|
||||
return nil, errors.TaskfileFetchFailedError{URI: u.String()}
|
||||
}
|
||||
|
||||
// Request the given URL
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.TaskfileFetchFailedError{URI: u.String()}
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// If the request was successful and the content type is allowed, return the
|
||||
// URL The content type check is to avoid downloading files that are not
|
||||
// Taskfiles It means we can try other files instead of downloading
|
||||
// something that is definitely not a Taskfile
|
||||
contentType := resp.Header.Get("Content-Type")
|
||||
if resp.StatusCode == http.StatusOK && slices.ContainsFunc(allowedContentTypes, func(s string) bool {
|
||||
return strings.Contains(contentType, s)
|
||||
}) {
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// If the request was not successful, append the default Taskfile names to
|
||||
// the URL and return the URL of the first successful request
|
||||
for _, taskfile := range defaultTaskfiles {
|
||||
// Fixes a bug with JoinPath where a leading slash is not added to the
|
||||
// path if it is empty
|
||||
if u.Path == "" {
|
||||
u.Path = "/"
|
||||
}
|
||||
alt := u.JoinPath(taskfile)
|
||||
req.URL = alt
|
||||
|
||||
// Try the alternative URL
|
||||
resp, err = http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.TaskfileFetchFailedError{URI: u.String()}
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// If the request was successful, return the URL
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
l.VerboseOutf(logger.Magenta, "task: [%s] Not found - Using alternative (%s)\n", alt.String(), taskfile)
|
||||
return alt, nil
|
||||
}
|
||||
}
|
||||
|
||||
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 the 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) {
|
||||
// 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(l *logger.Logger, path string) (string, error) {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -42,10 +113,11 @@ func Exists(path string) (string, error) {
|
||||
return filepath.Abs(path)
|
||||
}
|
||||
|
||||
for _, n := range defaultTaskfiles {
|
||||
fpath := filepathext.SmartJoin(path, n)
|
||||
if _, err := os.Stat(fpath); err == nil {
|
||||
return filepath.Abs(fpath)
|
||||
for _, taskfile := range defaultTaskfiles {
|
||||
alt := filepathext.SmartJoin(path, taskfile)
|
||||
if _, err := os.Stat(alt); err == nil {
|
||||
l.VerboseOutf(logger.Magenta, "task: [%s] Not found - Using alternative (%s)\n", path, taskfile)
|
||||
return filepath.Abs(alt)
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,14 +129,14 @@ func Exists(path string) (string, error) {
|
||||
// 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) {
|
||||
func ExistsWalk(l *logger.Logger, path string) (string, error) {
|
||||
origPath := path
|
||||
owner, err := sysinfo.Owner(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for {
|
||||
fpath, err := Exists(path)
|
||||
fpath, err := Exists(l, path)
|
||||
if err == nil {
|
||||
return fpath, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user