mirror of
https://github.com/go-task/task.git
synced 2025-11-25 22:32:55 +02:00
refactor: check if the remote exists just before reading it (#1713)
* refactor: check if the remote exists in the read to avoid doing it in offline mode * fix: timeout error was not working * fix: use cached copy if available
This commit is contained in:
@@ -17,7 +17,9 @@ import (
|
|||||||
// An HTTPNode is a node that reads a Taskfile from a remote location via HTTP.
|
// An HTTPNode is a node that reads a Taskfile from a remote location via HTTP.
|
||||||
type HTTPNode struct {
|
type HTTPNode struct {
|
||||||
*BaseNode
|
*BaseNode
|
||||||
URL *url.URL
|
URL *url.URL
|
||||||
|
logger *logger.Logger
|
||||||
|
timeout time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHTTPNode(
|
func NewHTTPNode(
|
||||||
@@ -36,18 +38,12 @@ func NewHTTPNode(
|
|||||||
if url.Scheme == "http" && !insecure {
|
if url.Scheme == "http" && !insecure {
|
||||||
return nil, &errors.TaskfileNotSecureError{URI: entrypoint}
|
return nil, &errors.TaskfileNotSecureError{URI: entrypoint}
|
||||||
}
|
}
|
||||||
ctx, cf := context.WithTimeout(context.Background(), timeout)
|
|
||||||
defer cf()
|
|
||||||
url, err = RemoteExists(ctx, l, url)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
|
||||||
return nil, &errors.TaskfileNetworkTimeoutError{URI: url.String(), Timeout: timeout}
|
|
||||||
}
|
|
||||||
return &HTTPNode{
|
return &HTTPNode{
|
||||||
BaseNode: base,
|
BaseNode: base,
|
||||||
URL: url,
|
URL: url,
|
||||||
|
timeout: timeout,
|
||||||
|
logger: l,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +56,11 @@ func (node *HTTPNode) Remote() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (node *HTTPNode) Read(ctx context.Context) ([]byte, error) {
|
func (node *HTTPNode) Read(ctx context.Context) ([]byte, error) {
|
||||||
|
url, err := RemoteExists(ctx, node.logger, node.URL, node.timeout)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
node.URL = url
|
||||||
req, err := http.NewRequest("GET", node.URL.String(), nil)
|
req, err := http.NewRequest("GET", node.URL.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.TaskfileFetchFailedError{URI: node.URL.String()}
|
return nil, errors.TaskfileFetchFailedError{URI: node.URL.String()}
|
||||||
@@ -67,6 +68,9 @@ func (node *HTTPNode) Read(ctx context.Context) ([]byte, error) {
|
|||||||
|
|
||||||
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
|
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
|
return nil, &errors.TaskfileNetworkTimeoutError{URI: node.URL.String(), Timeout: node.timeout}
|
||||||
|
}
|
||||||
return nil, errors.TaskfileFetchFailedError{URI: node.URL.String()}
|
return nil, errors.TaskfileFetchFailedError{URI: node.URL.String()}
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|||||||
@@ -208,8 +208,9 @@ func (r *Reader) readNode(node Node) (*ast.Taskfile, error) {
|
|||||||
|
|
||||||
// Read the file
|
// Read the file
|
||||||
b, err = node.Read(ctx)
|
b, err = node.Read(ctx)
|
||||||
|
var taskfileNetworkTimeoutError *errors.TaskfileNetworkTimeoutError
|
||||||
// If we timed out then we likely have a network issue
|
// If we timed out then we likely have a network issue
|
||||||
if node.Remote() && errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
if node.Remote() && errors.As(err, &taskfileNetworkTimeoutError) {
|
||||||
// If a download was requested, then we can't use a cached copy
|
// If a download was requested, then we can't use a cached copy
|
||||||
if r.download {
|
if r.download {
|
||||||
return nil, &errors.TaskfileNetworkTimeoutError{URI: node.Location(), Timeout: r.timeout}
|
return nil, &errors.TaskfileNetworkTimeoutError{URI: node.Location(), Timeout: r.timeout}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/go-task/task/v3/errors"
|
"github.com/go-task/task/v3/errors"
|
||||||
"github.com/go-task/task/v3/internal/filepathext"
|
"github.com/go-task/task/v3/internal/filepathext"
|
||||||
@@ -40,7 +41,7 @@ var (
|
|||||||
// at the given URL with any of the default Taskfile files names. If any of
|
// 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
|
// these match a file, the first matching path will be returned. If no files are
|
||||||
// found, an error will be returned.
|
// found, an error will be returned.
|
||||||
func RemoteExists(ctx context.Context, l *logger.Logger, u *url.URL) (*url.URL, error) {
|
func RemoteExists(ctx context.Context, l *logger.Logger, u *url.URL, timeout time.Duration) (*url.URL, error) {
|
||||||
// Create a new HEAD request for the given URL to check if the resource exists
|
// Create a new HEAD request for the given URL to check if the resource exists
|
||||||
req, err := http.NewRequest("HEAD", u.String(), nil)
|
req, err := http.NewRequest("HEAD", u.String(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -50,6 +51,9 @@ func RemoteExists(ctx context.Context, l *logger.Logger, u *url.URL) (*url.URL,
|
|||||||
// Request the given URL
|
// Request the given URL
|
||||||
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
|
resp, err := http.DefaultClient.Do(req.WithContext(ctx))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
||||||
|
return nil, &errors.TaskfileNetworkTimeoutError{URI: u.String(), Timeout: timeout}
|
||||||
|
}
|
||||||
return nil, errors.TaskfileFetchFailedError{URI: u.String()}
|
return nil, errors.TaskfileFetchFailedError{URI: u.String()}
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|||||||
Reference in New Issue
Block a user