diff --git a/CHANGELOG.md b/CHANGELOG.md index a6c089220d..9fd6550a79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,8 @@ variable (#2577, #2479 by @semihbkgr). - Fixed false positive "property 'for' is not allowed" warnings in IntelliJ when using `for` loops in Taskfiles (#2576 by @vmaerten). +- Added `--remote-cache-dir` flag and `remote.cache-dir` taskrc option to + customize the cache directory for Remote Taskfiles (#2572 by @vmaerten). ## v3.45.5 - 2025-11-11 diff --git a/completion/bash/task.bash b/completion/bash/task.bash index 0b19329eb1..77617c7231 100644 --- a/completion/bash/task.bash +++ b/completion/bash/task.bash @@ -22,7 +22,7 @@ function _task() # Handle special arguments of options. case "$prev" in - -d|--dir) + -d|--dir|--remote-cache-dir) _filedir -d return $? ;; diff --git a/completion/fish/task.fish b/completion/fish/task.fish index 325be7210a..8e7782f7ac 100644 --- a/completion/fish/task.fish +++ b/completion/fish/task.fish @@ -106,9 +106,10 @@ complete -c $GO_TASK_PROGNAME -s y -l yes -d 'assume yes t complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled GENTLE_FORCE" -l force-all -d 'force execution of task and all dependencies' # RemoteTaskfiles experiment - Options -complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l offline -d 'use only local or cached Taskfiles' -complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l timeout -d 'timeout for remote Taskfile downloads' -complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l expiry -d 'cache expiry duration' +complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l offline -d 'use only local or cached Taskfiles' +complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l timeout -d 'timeout for remote Taskfile downloads' +complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l expiry -d 'cache expiry duration' +complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l remote-cache-dir -d 'directory to cache remote Taskfiles' -xa "(__fish_complete_directories)" # RemoteTaskfiles experiment - Operations complete -c $GO_TASK_PROGNAME -n "__task_is_experiment_enabled REMOTE_TASKFILES" -l download -d 'download remote Taskfile' diff --git a/completion/ps/task.ps1 b/completion/ps/task.ps1 index 941c1d48c4..46ef7bea9b 100644 --- a/completion/ps/task.ps1 +++ b/completion/ps/task.ps1 @@ -75,6 +75,7 @@ Register-ArgumentCompleter -CommandName task -ScriptBlock { $completions += [CompletionResult]::new('--offline', '--offline', [CompletionResultType]::ParameterName, 'use cached Taskfiles') $completions += [CompletionResult]::new('--timeout', '--timeout', [CompletionResultType]::ParameterName, 'download timeout') $completions += [CompletionResult]::new('--expiry', '--expiry', [CompletionResultType]::ParameterName, 'cache expiry') + $completions += [CompletionResult]::new('--remote-cache-dir', '--remote-cache-dir', [CompletionResultType]::ParameterName, 'cache directory') # Operations $completions += [CompletionResult]::new('--download', '--download', [CompletionResultType]::ParameterName, 'download remote Taskfile') $completions += [CompletionResult]::new('--clear-cache', '--clear-cache', [CompletionResultType]::ParameterName, 'clear cache') diff --git a/completion/zsh/_task b/completion/zsh/_task index a33ca1d557..4b70aaccfd 100755 --- a/completion/zsh/_task +++ b/completion/zsh/_task @@ -100,6 +100,7 @@ _task() { '(--offline --download)--offline[use only local or cached Taskfiles]' '(--timeout)--timeout[timeout for remote Taskfile downloads]:duration: ' '(--expiry)--expiry[cache expiry duration]:duration: ' + '(--remote-cache-dir)--remote-cache-dir[directory to cache remote Taskfiles]:cache dir:_dirs' ) fi diff --git a/executor.go b/executor.go index 3ca5fbcf66..03b951a166 100644 --- a/executor.go +++ b/executor.go @@ -37,6 +37,7 @@ type ( TrustedHosts []string Timeout time.Duration CacheExpiryDuration time.Duration + RemoteCacheDir string Watch bool Verbose bool Silent bool @@ -271,6 +272,19 @@ func (o *cacheExpiryDurationOption) ApplyToExecutor(r *Executor) { r.CacheExpiryDuration = o.duration } +// WithRemoteCacheDir sets the directory where remote taskfiles are cached. +func WithRemoteCacheDir(dir string) ExecutorOption { + return &remoteCacheDirOption{dir: dir} +} + +type remoteCacheDirOption struct { + dir string +} + +func (o *remoteCacheDirOption) ApplyToExecutor(e *Executor) { + e.RemoteCacheDir = o.dir +} + // WithWatch tells the [Executor] to keep running in the background and watch // for changes to the fingerprint of the tasks that are run. When changes are // detected, a new task run is triggered. diff --git a/internal/flags/flags.go b/internal/flags/flags.go index eb5930dc10..656e250f08 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -12,6 +12,7 @@ import ( "github.com/go-task/task/v3" "github.com/go-task/task/v3/errors" "github.com/go-task/task/v3/experiments" + "github.com/go-task/task/v3/internal/env" "github.com/go-task/task/v3/internal/sort" "github.com/go-task/task/v3/taskfile/ast" "github.com/go-task/task/v3/taskrc" @@ -79,6 +80,7 @@ var ( ClearCache bool Timeout time.Duration CacheExpiryDuration time.Duration + RemoteCacheDir string ) func init() { @@ -157,10 +159,11 @@ func init() { if experiments.RemoteTaskfiles.Enabled() { pflag.BoolVar(&Download, "download", false, "Downloads a cached version of a remote Taskfile.") pflag.BoolVar(&Offline, "offline", getConfig(config, func() *bool { return config.Remote.Offline }, false), "Forces Task to only use local or cached Taskfiles.") - pflag.StringSliceVar(&TrustedHosts, "trusted-hosts", config.Remote.TrustedHosts, "List of trusted hosts for remote Taskfiles (comma-separated).") + pflag.StringSliceVar(&TrustedHosts, "trusted-hosts", getConfig(config, func() *[]string { return &config.Remote.TrustedHosts }, nil), "List of trusted hosts for remote Taskfiles (comma-separated).") pflag.DurationVar(&Timeout, "timeout", getConfig(config, func() *time.Duration { return config.Remote.Timeout }, time.Second*10), "Timeout for downloading remote Taskfiles.") pflag.BoolVar(&ClearCache, "clear-cache", false, "Clear the remote cache.") pflag.DurationVar(&CacheExpiryDuration, "expiry", getConfig(config, func() *time.Duration { return config.Remote.CacheExpiry }, 0), "Expiry duration for cached remote Taskfiles.") + pflag.StringVar(&RemoteCacheDir, "remote-cache-dir", getConfig(config, func() *string { return config.Remote.CacheDir }, env.GetTaskEnv("REMOTE_DIR")), "Directory to cache remote Taskfiles.") } pflag.Parse() } @@ -247,6 +250,7 @@ func (o *flagsOption) ApplyToExecutor(e *task.Executor) { task.WithTrustedHosts(TrustedHosts), task.WithTimeout(Timeout), task.WithCacheExpiryDuration(CacheExpiryDuration), + task.WithRemoteCacheDir(RemoteCacheDir), task.WithWatch(Watch), task.WithVerbose(Verbose), task.WithSilent(Silent), diff --git a/setup.go b/setup.go index 2fc3a6bf1e..47c3c7b7c1 100644 --- a/setup.go +++ b/setup.go @@ -153,16 +153,16 @@ func (e *Executor) setupTempDir() error { } } - remoteDir := env.GetTaskEnv("REMOTE_DIR") - if remoteDir != "" { - if filepath.IsAbs(remoteDir) || strings.HasPrefix(remoteDir, "~") { - remoteTempDir, err := execext.ExpandLiteral(remoteDir) + // RemoteCacheDir from taskrc/env can override the remote cache directory + if e.RemoteCacheDir != "" { + if filepath.IsAbs(e.RemoteCacheDir) || strings.HasPrefix(e.RemoteCacheDir, "~") { + remoteCacheDir, err := execext.ExpandLiteral(e.RemoteCacheDir) if err != nil { return err } - e.TempDir.Remote = remoteTempDir + e.TempDir.Remote = remoteCacheDir } else { - e.TempDir.Remote = filepathext.SmartJoin(e.Dir, ".task") + e.TempDir.Remote = filepathext.SmartJoin(e.Dir, e.RemoteCacheDir) } } diff --git a/taskrc/ast/taskrc.go b/taskrc/ast/taskrc.go index 8952315d62..5e9acbb097 100644 --- a/taskrc/ast/taskrc.go +++ b/taskrc/ast/taskrc.go @@ -24,6 +24,7 @@ type Remote struct { Offline *bool `yaml:"offline"` Timeout *time.Duration `yaml:"timeout"` CacheExpiry *time.Duration `yaml:"cache-expiry"` + CacheDir *string `yaml:"cache-dir"` TrustedHosts []string `yaml:"trusted-hosts"` } @@ -46,7 +47,7 @@ func (t *TaskRC) Merge(other *TaskRC) { t.Remote.Offline = cmp.Or(other.Remote.Offline, t.Remote.Offline) t.Remote.Timeout = cmp.Or(other.Remote.Timeout, t.Remote.Timeout) t.Remote.CacheExpiry = cmp.Or(other.Remote.CacheExpiry, t.Remote.CacheExpiry) - + t.Remote.CacheDir = cmp.Or(other.Remote.CacheDir, t.Remote.CacheDir) if len(other.Remote.TrustedHosts) > 0 { merged := slices.Concat(other.Remote.TrustedHosts, t.Remote.TrustedHosts) slices.Sort(merged) diff --git a/website/src/docs/experiments/remote-taskfiles.md b/website/src/docs/experiments/remote-taskfiles.md index 066cc855c9..8e8a34c75d 100644 --- a/website/src/docs/experiments/remote-taskfiles.md +++ b/website/src/docs/experiments/remote-taskfiles.md @@ -284,10 +284,11 @@ and look for a cached copy instead. This timeout can be configured by setting the `--timeout` flag and specifying a duration. For example, `--timeout 5s` will set the timeout to 5 seconds. -By default, the cache is stored in the Task temp directory, represented by the -`TASK_TEMP_DIR` environment variable. You can override the location of the cache -by setting the `TASK_REMOTE_DIR` environment variable. This way, you can share -the cache between different projects. +By default, the cache is stored in the Task temp directory (`.task`). You can +override the location of the cache by using the `--remote-cache-dir` flag, the +`remote.cache-dir` option in your [configuration file](#cache-dir), or the +`TASK_REMOTE_DIR` environment variable. This way, you can share the cache +between different projects. You can force Task to ignore the cache and download the latest version by using the `--download` flag. @@ -308,6 +309,7 @@ remote: offline: false timeout: "30s" cache-expiry: "24h" + cache-dir: ~/.task trusted-hosts: - github.com - gitlab.com @@ -360,6 +362,20 @@ remote: cache-expiry: "6h" ``` +#### `cache-dir` + +- **Type**: `string` +- **Default**: `.task` +- **Description**: Directory where remote Taskfiles are cached. Can be an + absolute path (e.g., `/var/cache/task`) or relative to the Taskfile directory. +- **CLI equivalent**: `--remote-cache-dir` +- **Environment variable**: `TASK_REMOTE_DIR` (lowest priority) + +```yaml +remote: + cache-dir: ~/.task +``` + #### `trusted-hosts` - **Type**: `array of strings`