1
0
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:
Valentin Maerten
2024-09-07 21:54:05 +02:00
committed by GitHub
parent a233b52c65
commit c77c8a419b
3 changed files with 21 additions and 12 deletions

View File

@@ -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()

View File

@@ -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}

View File

@@ -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()