From 1a5cd4f99fb6e778fe592c245a9f0a975f0ffe77 Mon Sep 17 00:00:00 2001 From: Pete Davison Date: Tue, 15 Sep 2026 16:07:15 +0000 Subject: [PATCH 1/2] refactor: return concrete struct instead of interface and merge node base and reader functional options for certificates --- executor.go | 74 +++++++++++++++++++++---------------------- setup.go | 6 ++-- taskfile/node_base.go | 50 ++++++++++++++--------------- taskfile/reader.go | 58 +++++++++++++++++++-------------- taskfile/snippet.go | 8 ++--- taskrc/reader.go | 2 +- 6 files changed, 104 insertions(+), 94 deletions(-) diff --git a/executor.go b/executor.go index 2ed4463beb..022a136134 100644 --- a/executor.go +++ b/executor.go @@ -135,7 +135,7 @@ func (e *Executor) fingerprinter() *fingerprint.Fingerprinter { // WithDir sets the working directory of the [Executor]. By default, the // directory is set to the user's current working directory. -func WithDir(dir string) ExecutorOption { +func WithDir(dir string) *dirOption { return &dirOption{dir} } @@ -150,7 +150,7 @@ func (o *dirOption) ApplyToExecutor(e *Executor) { // WithEntrypoint sets the entrypoint (main Taskfile) of the [Executor]. By // default, Task will search for one of the default Taskfiles in the given // directory. -func WithEntrypoint(entrypoint string) ExecutorOption { +func WithEntrypoint(entrypoint string) *entrypointOption { return &entrypointOption{entrypoint} } @@ -165,7 +165,7 @@ func (o *entrypointOption) ApplyToExecutor(e *Executor) { // WithTempDir sets the temporary directory that will be used by [Executor] for // storing temporary files like checksums and cached remote files. By default, // the temporary directory is set to the user's temporary directory. -func WithTempDir(tempDir TempDir) ExecutorOption { +func WithTempDir(tempDir TempDir) *tempDirOption { return &tempDirOption{tempDir} } @@ -181,7 +181,7 @@ func (o *tempDirOption) ApplyToExecutor(e *Executor) { // during [Executor.Setup]. Relative paths are resolved from the root Taskfile // directory. Use [WithTempDir] when the remote and fingerprint directories have // already been resolved. -func WithTempDirPath(path string) ExecutorOption { +func WithTempDirPath(path string) *tempDirPathOption { return &tempDirPathOption{path: path} } @@ -195,7 +195,7 @@ func (o *tempDirPathOption) ApplyToExecutor(e *Executor) { // WithForce ensures that the [Executor] always runs a task, even when // fingerprinting or prompts would normally stop it. -func WithForce(force bool) ExecutorOption { +func WithForce(force bool) *forceOption { return &forceOption{force} } @@ -209,7 +209,7 @@ func (o *forceOption) ApplyToExecutor(e *Executor) { // WithForceAll ensures that the [Executor] always runs all tasks (including // subtasks), even when fingerprinting or prompts would normally stop them. -func WithForceAll(forceAll bool) ExecutorOption { +func WithForceAll(forceAll bool) *forceAllOption { return &forceAllOption{forceAll} } @@ -223,7 +223,7 @@ func (o *forceAllOption) ApplyToExecutor(e *Executor) { // WithInsecure allows the [Executor] to make insecure connections when reading // remote taskfiles. By default, insecure connections are rejected. -func WithInsecure(insecure bool) ExecutorOption { +func WithInsecure(insecure bool) *insecureOption { return &insecureOption{insecure} } @@ -237,7 +237,7 @@ func (o *insecureOption) ApplyToExecutor(e *Executor) { // WithDownload forces the [Executor] to download a fresh copy of the taskfile // from the remote source. -func WithDownload(download bool) ExecutorOption { +func WithDownload(download bool) *downloadOption { return &downloadOption{download} } @@ -251,7 +251,7 @@ func (o *downloadOption) ApplyToExecutor(e *Executor) { // WithOffline stops the [Executor] from being able to make network connections. // It will still be able to read local files and cached copies of remote files. -func WithOffline(offline bool) ExecutorOption { +func WithOffline(offline bool) *offlineOption { return &offlineOption{offline} } @@ -265,7 +265,7 @@ func (o *offlineOption) ApplyToExecutor(e *Executor) { // WithTrustedHosts configures the [Executor] with a list of trusted hosts for remote // Taskfiles. Hosts in this list will not prompt for user confirmation. -func WithTrustedHosts(trustedHosts []string) ExecutorOption { +func WithTrustedHosts(trustedHosts []string) *trustedHostsOption { return &trustedHostsOption{trustedHosts} } @@ -279,7 +279,7 @@ func (o *trustedHostsOption) ApplyToExecutor(e *Executor) { // WithTimeout sets the [Executor]'s timeout for fetching remote taskfiles. By // default, the timeout is set to 10 seconds. -func WithTimeout(timeout time.Duration) ExecutorOption { +func WithTimeout(timeout time.Duration) *timeoutOption { return &timeoutOption{timeout} } @@ -293,7 +293,7 @@ func (o *timeoutOption) ApplyToExecutor(e *Executor) { // WithCacheExpiryDuration sets the duration after which the cache is considered // expired. By default, the cache is 0 (disabled). -func WithCacheExpiryDuration(duration time.Duration) ExecutorOption { +func WithCacheExpiryDuration(duration time.Duration) *cacheExpiryDurationOption { return &cacheExpiryDurationOption{duration: duration} } @@ -306,7 +306,7 @@ func (o *cacheExpiryDurationOption) ApplyToExecutor(r *Executor) { } // WithRemoteCacheDir sets the directory where remote taskfiles are cached. -func WithRemoteCacheDir(dir string) ExecutorOption { +func WithRemoteCacheDir(dir string) *remoteCacheDirOption { return &remoteCacheDirOption{dir: dir} } @@ -319,7 +319,7 @@ func (o *remoteCacheDirOption) ApplyToExecutor(e *Executor) { } // WithCACert sets the path to a custom CA certificate for TLS connections. -func WithCACert(caCert string) ExecutorOption { +func WithCACert(caCert string) *caCertOption { return &caCertOption{caCert: caCert} } @@ -332,7 +332,7 @@ func (o *caCertOption) ApplyToExecutor(e *Executor) { } // WithCert sets the path to a client certificate for TLS connections. -func WithCert(cert string) ExecutorOption { +func WithCert(cert string) *certOption { return &certOption{cert: cert} } @@ -345,7 +345,7 @@ func (o *certOption) ApplyToExecutor(e *Executor) { } // WithCertKey sets the path to a client certificate key for TLS connections. -func WithCertKey(certKey string) ExecutorOption { +func WithCertKey(certKey string) *certKeyOption { return &certKeyOption{certKey: certKey} } @@ -360,7 +360,7 @@ func (o *certKeyOption) ApplyToExecutor(e *Executor) { // 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. -func WithWatch(watch bool) ExecutorOption { +func WithWatch(watch bool) *watchOption { return &watchOption{watch} } @@ -374,7 +374,7 @@ func (o *watchOption) ApplyToExecutor(e *Executor) { // WithVerbose tells the [Executor] to output more information about the tasks // that are run. -func WithVerbose(verbose bool) ExecutorOption { +func WithVerbose(verbose bool) *verboseOption { return &verboseOption{verbose} } @@ -388,7 +388,7 @@ func (o *verboseOption) ApplyToExecutor(e *Executor) { // WithSilent tells the [Executor] to suppress all output except for the output // of the tasks that are run. -func WithSilent(silent bool) ExecutorOption { +func WithSilent(silent bool) *silentOption { return &silentOption{silent} } @@ -401,7 +401,7 @@ func (o *silentOption) ApplyToExecutor(e *Executor) { } // WithDisableFuzzy tells the [Executor] to disable fuzzy matching for task names. -func WithDisableFuzzy(disableFuzzy bool) ExecutorOption { +func WithDisableFuzzy(disableFuzzy bool) *disableFuzzyOption { return &disableFuzzyOption{disableFuzzy} } @@ -414,7 +414,7 @@ func (o *disableFuzzyOption) ApplyToExecutor(e *Executor) { } // WithAssumeYes tells the [Executor] to assume "yes" for all prompts. -func WithAssumeYes(assumeYes bool) ExecutorOption { +func WithAssumeYes(assumeYes bool) *assumeYesOption { return &assumeYesOption{assumeYes} } @@ -427,7 +427,7 @@ func (o *assumeYesOption) ApplyToExecutor(e *Executor) { } // WithAssumeTerm is used for testing purposes to simulate a terminal. -func WithAssumeTerm(assumeTerm bool) ExecutorOption { +func WithAssumeTerm(assumeTerm bool) *assumeTermOption { return &assumeTermOption{assumeTerm} } @@ -440,7 +440,7 @@ func (o *assumeTermOption) ApplyToExecutor(e *Executor) { } // WithInteractive tells the [Executor] to prompt for missing required variables. -func WithInteractive(interactive bool) ExecutorOption { +func WithInteractive(interactive bool) *interactiveOption { return &interactiveOption{interactive} } @@ -454,7 +454,7 @@ func (o *interactiveOption) ApplyToExecutor(e *Executor) { // WithDry tells the [Executor] to output the commands that would be run without // actually running them. -func WithDry(dry bool) ExecutorOption { +func WithDry(dry bool) *dryOption { return &dryOption{dry} } @@ -468,7 +468,7 @@ func (o *dryOption) ApplyToExecutor(e *Executor) { // WithSummary tells the [Executor] to output a summary of the given tasks // instead of running them. -func WithSummary(summary bool) ExecutorOption { +func WithSummary(summary bool) *summaryOption { return &summaryOption{summary} } @@ -482,7 +482,7 @@ func (o *summaryOption) ApplyToExecutor(e *Executor) { // WithParallel tells the [Executor] to run tasks given in the same call in // parallel. -func WithParallel(parallel bool) ExecutorOption { +func WithParallel(parallel bool) *parallelOption { return ¶llelOption{parallel} } @@ -496,7 +496,7 @@ func (o *parallelOption) ApplyToExecutor(e *Executor) { // WithColor tells the [Executor] whether or not to output using colorized // strings. -func WithColor(color bool) ExecutorOption { +func WithColor(color bool) *colorOption { return &colorOption{color} } @@ -510,7 +510,7 @@ func (o *colorOption) ApplyToExecutor(e *Executor) { // WithConcurrency sets the maximum number of tasks that the [Executor] can run // in parallel. -func WithConcurrency(concurrency int) ExecutorOption { +func WithConcurrency(concurrency int) *concurrencyOption { return &concurrencyOption{concurrency} } @@ -524,7 +524,7 @@ func (o *concurrencyOption) ApplyToExecutor(e *Executor) { // WithInterval sets the interval at which the [Executor] will wait for // duplicated events before running a task. -func WithInterval(interval time.Duration) ExecutorOption { +func WithInterval(interval time.Duration) *intervalOption { return &intervalOption{interval} } @@ -538,7 +538,7 @@ func (o *intervalOption) ApplyToExecutor(e *Executor) { // WithOutputStyle sets the output style of the [Executor]. By default, the // output style is set to the style defined in the Taskfile. -func WithOutputStyle(outputStyle ast.Output) ExecutorOption { +func WithOutputStyle(outputStyle ast.Output) *outputStyleOption { return &outputStyleOption{outputStyle} } @@ -553,7 +553,7 @@ func (o *outputStyleOption) ApplyToExecutor(e *Executor) { // WithTaskSorter sets the sorter that the [Executor] will use to sort tasks. By // default, the sorter is set to sort tasks alphabetically, but with tasks with // no namespace (in the root Taskfile) first. -func WithTaskSorter(sorter sort.Sorter) ExecutorOption { +func WithTaskSorter(sorter sort.Sorter) *taskSorterOption { return &taskSorterOption{sorter} } @@ -566,7 +566,7 @@ func (o *taskSorterOption) ApplyToExecutor(e *Executor) { } // WithStdin sets the [Executor]'s standard input [io.Reader]. -func WithStdin(stdin io.Reader) ExecutorOption { +func WithStdin(stdin io.Reader) *stdinOption { return &stdinOption{stdin} } @@ -579,7 +579,7 @@ func (o *stdinOption) ApplyToExecutor(e *Executor) { } // WithStdout sets the [Executor]'s standard output [io.Writer]. -func WithStdout(stdout io.Writer) ExecutorOption { +func WithStdout(stdout io.Writer) *stdoutOption { return &stdoutOption{stdout} } @@ -592,7 +592,7 @@ func (o *stdoutOption) ApplyToExecutor(e *Executor) { } // WithStderr sets the [Executor]'s standard error [io.Writer]. -func WithStderr(stderr io.Writer) ExecutorOption { +func WithStderr(stderr io.Writer) *stderrOption { return &stderrOption{stderr} } @@ -606,7 +606,7 @@ func (o *stderrOption) ApplyToExecutor(e *Executor) { // WithIO sets the [Executor]'s standard input, output, and error to the same // [io.ReadWriter]. -func WithIO(rw io.ReadWriter) ExecutorOption { +func WithIO(rw io.ReadWriter) *ioOption { return &ioOption{rw} } @@ -622,7 +622,7 @@ func (o *ioOption) ApplyToExecutor(e *Executor) { // WithVersionCheck tells the [Executor] whether or not to check the schema // version of the Taskfile before running. -func WithVersionCheck(enableVersionCheck bool) ExecutorOption { +func WithVersionCheck(enableVersionCheck bool) *versionCheckOption { return &versionCheckOption{enableVersionCheck} } @@ -636,7 +636,7 @@ func (o *versionCheckOption) ApplyToExecutor(e *Executor) { // WithFailfast tells the [Executor] to stop running tasks as soon as any task // returns an error. -func WithFailfast(failfast bool) ExecutorOption { +func WithFailfast(failfast bool) *failfastOption { return &failfastOption{failfast} } diff --git a/setup.go b/setup.go index e92848417a..aea1d9d82d 100644 --- a/setup.go +++ b/setup.go @@ -87,9 +87,9 @@ func (e *Executor) readTaskfile(node taskfile.Node) error { taskfile.WithTrustedHosts(e.TrustedHosts), taskfile.WithTempDir(e.TempDir.Remote), taskfile.WithCacheExpiryDuration(e.CacheExpiryDuration), - taskfile.WithReaderCACert(e.CACert), - taskfile.WithReaderCert(e.Cert), - taskfile.WithReaderCertKey(e.CertKey), + taskfile.WithCACert(e.CACert), + taskfile.WithCert(e.Cert), + taskfile.WithCertKey(e.CertKey), taskfile.WithDebugFunc(debugFunc), taskfile.WithPromptFunc(promptFunc), ) diff --git a/taskfile/node_base.go b/taskfile/node_base.go index 2d81dded51..f00bad9611 100644 --- a/taskfile/node_base.go +++ b/taskfile/node_base.go @@ -1,7 +1,9 @@ package taskfile type ( - NodeOption func(*baseNode) + NodeOption interface { + ApplyToBaseNode(n *baseNode) + } // baseNode is a generic node that implements the Parent() methods of the // NodeReader interface. It does not implement the Read() method and it // designed to be embedded in other node types so that this boilerplate code @@ -24,24 +26,12 @@ func NewBaseNode(dir string, opts ...NodeOption) *baseNode { // Apply options for _, opt := range opts { - opt(node) + opt.ApplyToBaseNode(node) } return node } -func WithParent(parent Node) NodeOption { - return func(node *baseNode) { - node.parent = parent - } -} - -func WithChecksum(checksum string) NodeOption { - return func(node *baseNode) { - node.checksum = checksum - } -} - func (node *baseNode) Parent() Node { return node.parent } @@ -58,20 +48,28 @@ func (node *baseNode) Verify(checksum string) bool { return node.checksum == "" || node.checksum == checksum } -func WithCACert(caCert string) NodeOption { - return func(node *baseNode) { - node.caCert = caCert - } +// WithParent sets the parent node for the node base. +func WithParent(parent Node) *parentOption { + return &parentOption{parent: parent} } -func WithCert(cert string) NodeOption { - return func(node *baseNode) { - node.cert = cert - } +type parentOption struct { + parent Node } -func WithCertKey(certKey string) NodeOption { - return func(node *baseNode) { - node.certKey = certKey - } +func (o *parentOption) ApplyToBaseNode(n *baseNode) { + n.parent = o.parent +} + +// WithChecksum sets the checksum for the node base. +func WithChecksum(checksum string) *checksumOption { + return &checksumOption{checksum: checksum} +} + +type checksumOption struct { + checksum string +} + +func (o *checksumOption) ApplyToBaseNode(n *baseNode) { + n.checksum = o.checksum } diff --git a/taskfile/reader.go b/taskfile/reader.go index fc5d6d30af..382100b611 100644 --- a/taskfile/reader.go +++ b/taskfile/reader.go @@ -86,7 +86,7 @@ func (r *Reader) Options(opts ...ReaderOption) { // WithInsecure allows the [Reader] to make insecure connections when reading // remote taskfiles. By default, insecure connections are rejected. -func WithInsecure(insecure bool) ReaderOption { +func WithInsecure(insecure bool) *insecureOption { return &insecureOption{insecure: insecure} } @@ -100,7 +100,7 @@ func (o *insecureOption) ApplyToReader(r *Reader) { // WithDownload forces the [Reader] to download a fresh copy of the taskfile // from the remote source. -func WithDownload(download bool) ReaderOption { +func WithDownload(download bool) *downloadOption { return &downloadOption{download: download} } @@ -114,7 +114,7 @@ func (o *downloadOption) ApplyToReader(r *Reader) { // WithOffline stops the [Reader] from being able to make network connections. // It will still be able to read local files and cached copies of remote files. -func WithOffline(offline bool) ReaderOption { +func WithOffline(offline bool) *offlineOption { return &offlineOption{offline: offline} } @@ -128,7 +128,7 @@ func (o *offlineOption) ApplyToReader(r *Reader) { // WithTrustedHosts configures the [Reader] with a list of trusted hosts for remote // Taskfiles. Hosts in this list will not prompt for user confirmation. -func WithTrustedHosts(trustedHosts []string) ReaderOption { +func WithTrustedHosts(trustedHosts []string) *trustedHostsOption { return &trustedHostsOption{trustedHosts: trustedHosts} } @@ -142,7 +142,7 @@ func (o *trustedHostsOption) ApplyToReader(r *Reader) { // WithTempDir sets the temporary directory that will be used by the [Reader]. // By default, the reader uses [os.TempDir]. -func WithTempDir(tempDir string) ReaderOption { +func WithTempDir(tempDir string) *tempDirOption { return &tempDirOption{tempDir: tempDir} } @@ -156,7 +156,7 @@ func (o *tempDirOption) ApplyToReader(r *Reader) { // WithCacheExpiryDuration sets the duration after which the cache is considered // expired. By default, the cache is considered expired after 24 hours. -func WithCacheExpiryDuration(duration time.Duration) ReaderOption { +func WithCacheExpiryDuration(duration time.Duration) *cacheExpiryDurationOption { return &cacheExpiryDurationOption{duration: duration} } @@ -172,7 +172,7 @@ func (o *cacheExpiryDurationOption) ApplyToReader(r *Reader) { // this function will be called with debug messages. This can be useful if the // caller wants to log debug messages from the [Reader]. By default, no debug // function is set and the logs are not written. -func WithDebugFunc(debugFunc DebugFunc) ReaderOption { +func WithDebugFunc(debugFunc DebugFunc) *debugFuncOption { return &debugFuncOption{debugFunc: debugFunc} } @@ -191,7 +191,7 @@ func (o *debugFuncOption) ApplyToReader(r *Reader) { // error which describes why the prompt was rejected. This can then be caught // and used later when calling the [Reader.Read] method. By default, no prompt // function is set and all prompts are automatically accepted. -func WithPromptFunc(promptFunc PromptFunc) ReaderOption { +func WithPromptFunc(promptFunc PromptFunc) *promptFuncOption { return &promptFuncOption{promptFunc: promptFunc} } @@ -203,45 +203,57 @@ func (o *promptFuncOption) ApplyToReader(r *Reader) { r.promptFunc = o.promptFunc } -// WithReaderCACert sets the path to a custom CA certificate for TLS connections. -func WithReaderCACert(caCert string) ReaderOption { - return &readerCACertOption{caCert: caCert} +// WithCACert sets the path to a custom CA certificate for TLS connections. +func WithCACert(caCert string) *caCertOption { + return &caCertOption{caCert: caCert} } -type readerCACertOption struct { +type caCertOption struct { caCert string } -func (o *readerCACertOption) ApplyToReader(r *Reader) { +func (o *caCertOption) ApplyToReader(r *Reader) { r.caCert = o.caCert } -// WithReaderCert sets the path to a client certificate for TLS connections. -func WithReaderCert(cert string) ReaderOption { - return &readerCertOption{cert: cert} +func (o *caCertOption) ApplyToBaseNode(n *baseNode) { + n.caCert = o.caCert } -type readerCertOption struct { +// WithCert sets the path to a client certificate for TLS connections. +func WithCert(cert string) *certOption { + return &certOption{cert: cert} +} + +type certOption struct { cert string } -func (o *readerCertOption) ApplyToReader(r *Reader) { +func (o *certOption) ApplyToReader(r *Reader) { r.cert = o.cert } -// WithReaderCertKey sets the path to a client certificate key for TLS connections. -func WithReaderCertKey(certKey string) ReaderOption { - return &readerCertKeyOption{certKey: certKey} +func (o *certOption) ApplyToBaseNode(n *baseNode) { + n.cert = o.cert +} + +// WithCertKey sets the path to a client certificate key for TLS connections. +func WithCertKey(certKey string) *certKeyOption { + return &certKeyOption{certKey: certKey} } -type readerCertKeyOption struct { +type certKeyOption struct { certKey string } -func (o *readerCertKeyOption) ApplyToReader(r *Reader) { +func (o *certKeyOption) ApplyToReader(r *Reader) { r.certKey = o.certKey } +func (o *certKeyOption) ApplyToBaseNode(n *baseNode) { + n.certKey = o.certKey +} + // Read will read the Taskfile defined by the [Reader]'s [Node] and recurse // through any [ast.Includes] it finds, reading each included Taskfile and // building an [ast.TaskfileGraph] as it goes. If any errors occur, they will be diff --git a/taskfile/snippet.go b/taskfile/snippet.go index 332b61aef5..397e41e812 100644 --- a/taskfile/snippet.go +++ b/taskfile/snippet.go @@ -86,7 +86,7 @@ func (s *Snippet) Options(opts ...SnippetOption) { // WithLine specifies the line number that the [Snippet] should center around // and point to. -func WithLine(line int) SnippetOption { +func WithLine(line int) *lineOption { return &lineOption{line: line} } @@ -99,7 +99,7 @@ func (o *lineOption) ApplyToSnippet(s *Snippet) { } // WithColumn specifies the column number that the [Snippet] should point to. -func WithColumn(column int) SnippetOption { +func WithColumn(column int) *columnOption { return &columnOption{column: column} } @@ -113,7 +113,7 @@ func (o *columnOption) ApplyToSnippet(s *Snippet) { // WithPadding specifies the number of lines to include before and after the // selected line in the [Snippet]. -func WithPadding(padding int) SnippetOption { +func WithPadding(padding int) *paddingOption { return &paddingOption{padding: padding} } @@ -127,7 +127,7 @@ func (o *paddingOption) ApplyToSnippet(s *Snippet) { // WithNoIndicators specifies that the [Snippet] should not include line or // column indicators. -func WithNoIndicators() SnippetOption { +func WithNoIndicators() *noIndicatorsOption { return &noIndicatorsOption{} } diff --git a/taskrc/reader.go b/taskrc/reader.go index 0caebfe3a5..8d929e2cdc 100644 --- a/taskrc/reader.go +++ b/taskrc/reader.go @@ -44,7 +44,7 @@ func (r *Reader) Options(opts ...ReaderOption) { // this function will be called with debug messages. This can be useful if the // caller wants to log debug messages from the [Reader]. By default, no debug // function is set and the logs are not written. -func WithDebugFunc(debugFunc DebugFunc) ReaderOption { +func WithDebugFunc(debugFunc DebugFunc) *debugFuncOption { return &debugFuncOption{debugFunc: debugFunc} } From 5b3c370d6167344081ee682adaecbe4d9be761f9 Mon Sep 17 00:00:00 2001 From: Pete Davison Date: Tue, 15 Sep 2026 23:49:00 +0000 Subject: [PATCH 2/2] refactor: move the options into their own files This allows the reader/node etc files to focus on actual functionality and not the functional options boilerplate. Since some options can be applied to more than one struct it doesn't make sense to put them in other files. --- taskfile/node_base.go | 26 ----- taskfile/options.go | 251 ++++++++++++++++++++++++++++++++++++++++++ taskfile/reader.go | 170 ---------------------------- taskfile/snippet.go | 53 --------- 4 files changed, 251 insertions(+), 249 deletions(-) create mode 100644 taskfile/options.go diff --git a/taskfile/node_base.go b/taskfile/node_base.go index f00bad9611..25349243ae 100644 --- a/taskfile/node_base.go +++ b/taskfile/node_base.go @@ -47,29 +47,3 @@ func (node *baseNode) Checksum() string { func (node *baseNode) Verify(checksum string) bool { return node.checksum == "" || node.checksum == checksum } - -// WithParent sets the parent node for the node base. -func WithParent(parent Node) *parentOption { - return &parentOption{parent: parent} -} - -type parentOption struct { - parent Node -} - -func (o *parentOption) ApplyToBaseNode(n *baseNode) { - n.parent = o.parent -} - -// WithChecksum sets the checksum for the node base. -func WithChecksum(checksum string) *checksumOption { - return &checksumOption{checksum: checksum} -} - -type checksumOption struct { - checksum string -} - -func (o *checksumOption) ApplyToBaseNode(n *baseNode) { - n.checksum = o.checksum -} diff --git a/taskfile/options.go b/taskfile/options.go new file mode 100644 index 0000000000..df8134ae58 --- /dev/null +++ b/taskfile/options.go @@ -0,0 +1,251 @@ +package taskfile + +import "time" + +// WithInsecure allows the [Reader] to make insecure connections when reading +// remote taskfiles. By default, insecure connections are rejected. +func WithInsecure(insecure bool) *insecureOption { + return &insecureOption{insecure: insecure} +} + +type insecureOption struct { + insecure bool +} + +func (o *insecureOption) ApplyToReader(r *Reader) { + r.insecure = o.insecure +} + +// WithDownload forces the [Reader] to download a fresh copy of the taskfile +// from the remote source. +func WithDownload(download bool) *downloadOption { + return &downloadOption{download: download} +} + +type downloadOption struct { + download bool +} + +func (o *downloadOption) ApplyToReader(r *Reader) { + r.download = o.download +} + +// WithOffline stops the [Reader] from being able to make network connections. +// It will still be able to read local files and cached copies of remote files. +func WithOffline(offline bool) *offlineOption { + return &offlineOption{offline: offline} +} + +type offlineOption struct { + offline bool +} + +func (o *offlineOption) ApplyToReader(r *Reader) { + r.offline = o.offline +} + +// WithTrustedHosts configures the [Reader] with a list of trusted hosts for remote +// Taskfiles. Hosts in this list will not prompt for user confirmation. +func WithTrustedHosts(trustedHosts []string) *trustedHostsOption { + return &trustedHostsOption{trustedHosts: trustedHosts} +} + +type trustedHostsOption struct { + trustedHosts []string +} + +func (o *trustedHostsOption) ApplyToReader(r *Reader) { + r.trustedHosts = o.trustedHosts +} + +// WithTempDir sets the temporary directory that will be used by the [Reader]. +// By default, the reader uses [os.TempDir]. +func WithTempDir(tempDir string) *tempDirOption { + return &tempDirOption{tempDir: tempDir} +} + +type tempDirOption struct { + tempDir string +} + +func (o *tempDirOption) ApplyToReader(r *Reader) { + r.tempDir = o.tempDir +} + +// WithCacheExpiryDuration sets the duration after which the cache is considered +// expired. By default, the cache is considered expired after 24 hours. +func WithCacheExpiryDuration(duration time.Duration) *cacheExpiryDurationOption { + return &cacheExpiryDurationOption{duration: duration} +} + +type cacheExpiryDurationOption struct { + duration time.Duration +} + +func (o *cacheExpiryDurationOption) ApplyToReader(r *Reader) { + r.cacheExpiryDuration = o.duration +} + +// WithDebugFunc sets the debug function to be used by the [Reader]. If set, +// this function will be called with debug messages. This can be useful if the +// caller wants to log debug messages from the [Reader]. By default, no debug +// function is set and the logs are not written. +func WithDebugFunc(debugFunc DebugFunc) *debugFuncOption { + return &debugFuncOption{debugFunc: debugFunc} +} + +type debugFuncOption struct { + debugFunc DebugFunc +} + +func (o *debugFuncOption) ApplyToReader(r *Reader) { + r.debugFunc = o.debugFunc +} + +// WithPromptFunc sets the prompt function to be used by the [Reader]. If set, +// this function will be called with prompt messages. The function should +// optionally log the message to the user and return nil if the prompt is +// accepted and the execution should continue. Otherwise, it should return an +// error which describes why the prompt was rejected. This can then be caught +// and used later when calling the [Reader.Read] method. By default, no prompt +// function is set and all prompts are automatically accepted. +func WithPromptFunc(promptFunc PromptFunc) *promptFuncOption { + return &promptFuncOption{promptFunc: promptFunc} +} + +type promptFuncOption struct { + promptFunc PromptFunc +} + +func (o *promptFuncOption) ApplyToReader(r *Reader) { + r.promptFunc = o.promptFunc +} + +// WithCACert sets the path to a custom CA certificate for TLS connections. +func WithCACert(caCert string) *caCertOption { + return &caCertOption{caCert: caCert} +} + +type caCertOption struct { + caCert string +} + +func (o *caCertOption) ApplyToReader(r *Reader) { + r.caCert = o.caCert +} + +func (o *caCertOption) ApplyToBaseNode(n *baseNode) { + n.caCert = o.caCert +} + +// WithCert sets the path to a client certificate for TLS connections. +func WithCert(cert string) *certOption { + return &certOption{cert: cert} +} + +type certOption struct { + cert string +} + +func (o *certOption) ApplyToReader(r *Reader) { + r.cert = o.cert +} + +func (o *certOption) ApplyToBaseNode(n *baseNode) { + n.cert = o.cert +} + +// WithCertKey sets the path to a client certificate key for TLS connections. +func WithCertKey(certKey string) *certKeyOption { + return &certKeyOption{certKey: certKey} +} + +type certKeyOption struct { + certKey string +} + +func (o *certKeyOption) ApplyToReader(r *Reader) { + r.certKey = o.certKey +} + +func (o *certKeyOption) ApplyToBaseNode(n *baseNode) { + n.certKey = o.certKey +} + +// WithParent sets the parent node for the node base. +func WithParent(parent Node) *parentOption { + return &parentOption{parent: parent} +} + +type parentOption struct { + parent Node +} + +func (o *parentOption) ApplyToBaseNode(n *baseNode) { + n.parent = o.parent +} + +// WithChecksum sets the checksum for the node base. +func WithChecksum(checksum string) *checksumOption { + return &checksumOption{checksum: checksum} +} + +type checksumOption struct { + checksum string +} + +func (o *checksumOption) ApplyToBaseNode(n *baseNode) { + n.checksum = o.checksum +} +// WithLine specifies the line number that the [Snippet] should center around +// and point to. +func WithLine(line int) *lineOption { + return &lineOption{line: line} +} + +type lineOption struct { + line int +} + +func (o *lineOption) ApplyToSnippet(s *Snippet) { + s.line = o.line +} + +// WithColumn specifies the column number that the [Snippet] should point to. +func WithColumn(column int) *columnOption { + return &columnOption{column: column} +} + +type columnOption struct { + column int +} + +func (o *columnOption) ApplyToSnippet(s *Snippet) { + s.column = o.column +} + +// WithPadding specifies the number of lines to include before and after the +// selected line in the [Snippet]. +func WithPadding(padding int) *paddingOption { + return &paddingOption{padding: padding} +} + +type paddingOption struct { + padding int +} + +func (o *paddingOption) ApplyToSnippet(s *Snippet) { + s.padding = o.padding +} + +// WithNoIndicators specifies that the [Snippet] should not include line or +// column indicators. +func WithNoIndicators() *noIndicatorsOption { + return &noIndicatorsOption{} +} + +type noIndicatorsOption struct{} + +func (o *noIndicatorsOption) ApplyToSnippet(s *Snippet) { + s.noIndicators = true +} diff --git a/taskfile/reader.go b/taskfile/reader.go index 382100b611..c76c9891ed 100644 --- a/taskfile/reader.go +++ b/taskfile/reader.go @@ -84,176 +84,6 @@ func (r *Reader) Options(opts ...ReaderOption) { } } -// WithInsecure allows the [Reader] to make insecure connections when reading -// remote taskfiles. By default, insecure connections are rejected. -func WithInsecure(insecure bool) *insecureOption { - return &insecureOption{insecure: insecure} -} - -type insecureOption struct { - insecure bool -} - -func (o *insecureOption) ApplyToReader(r *Reader) { - r.insecure = o.insecure -} - -// WithDownload forces the [Reader] to download a fresh copy of the taskfile -// from the remote source. -func WithDownload(download bool) *downloadOption { - return &downloadOption{download: download} -} - -type downloadOption struct { - download bool -} - -func (o *downloadOption) ApplyToReader(r *Reader) { - r.download = o.download -} - -// WithOffline stops the [Reader] from being able to make network connections. -// It will still be able to read local files and cached copies of remote files. -func WithOffline(offline bool) *offlineOption { - return &offlineOption{offline: offline} -} - -type offlineOption struct { - offline bool -} - -func (o *offlineOption) ApplyToReader(r *Reader) { - r.offline = o.offline -} - -// WithTrustedHosts configures the [Reader] with a list of trusted hosts for remote -// Taskfiles. Hosts in this list will not prompt for user confirmation. -func WithTrustedHosts(trustedHosts []string) *trustedHostsOption { - return &trustedHostsOption{trustedHosts: trustedHosts} -} - -type trustedHostsOption struct { - trustedHosts []string -} - -func (o *trustedHostsOption) ApplyToReader(r *Reader) { - r.trustedHosts = o.trustedHosts -} - -// WithTempDir sets the temporary directory that will be used by the [Reader]. -// By default, the reader uses [os.TempDir]. -func WithTempDir(tempDir string) *tempDirOption { - return &tempDirOption{tempDir: tempDir} -} - -type tempDirOption struct { - tempDir string -} - -func (o *tempDirOption) ApplyToReader(r *Reader) { - r.tempDir = o.tempDir -} - -// WithCacheExpiryDuration sets the duration after which the cache is considered -// expired. By default, the cache is considered expired after 24 hours. -func WithCacheExpiryDuration(duration time.Duration) *cacheExpiryDurationOption { - return &cacheExpiryDurationOption{duration: duration} -} - -type cacheExpiryDurationOption struct { - duration time.Duration -} - -func (o *cacheExpiryDurationOption) ApplyToReader(r *Reader) { - r.cacheExpiryDuration = o.duration -} - -// WithDebugFunc sets the debug function to be used by the [Reader]. If set, -// this function will be called with debug messages. This can be useful if the -// caller wants to log debug messages from the [Reader]. By default, no debug -// function is set and the logs are not written. -func WithDebugFunc(debugFunc DebugFunc) *debugFuncOption { - return &debugFuncOption{debugFunc: debugFunc} -} - -type debugFuncOption struct { - debugFunc DebugFunc -} - -func (o *debugFuncOption) ApplyToReader(r *Reader) { - r.debugFunc = o.debugFunc -} - -// WithPromptFunc sets the prompt function to be used by the [Reader]. If set, -// this function will be called with prompt messages. The function should -// optionally log the message to the user and return nil if the prompt is -// accepted and the execution should continue. Otherwise, it should return an -// error which describes why the prompt was rejected. This can then be caught -// and used later when calling the [Reader.Read] method. By default, no prompt -// function is set and all prompts are automatically accepted. -func WithPromptFunc(promptFunc PromptFunc) *promptFuncOption { - return &promptFuncOption{promptFunc: promptFunc} -} - -type promptFuncOption struct { - promptFunc PromptFunc -} - -func (o *promptFuncOption) ApplyToReader(r *Reader) { - r.promptFunc = o.promptFunc -} - -// WithCACert sets the path to a custom CA certificate for TLS connections. -func WithCACert(caCert string) *caCertOption { - return &caCertOption{caCert: caCert} -} - -type caCertOption struct { - caCert string -} - -func (o *caCertOption) ApplyToReader(r *Reader) { - r.caCert = o.caCert -} - -func (o *caCertOption) ApplyToBaseNode(n *baseNode) { - n.caCert = o.caCert -} - -// WithCert sets the path to a client certificate for TLS connections. -func WithCert(cert string) *certOption { - return &certOption{cert: cert} -} - -type certOption struct { - cert string -} - -func (o *certOption) ApplyToReader(r *Reader) { - r.cert = o.cert -} - -func (o *certOption) ApplyToBaseNode(n *baseNode) { - n.cert = o.cert -} - -// WithCertKey sets the path to a client certificate key for TLS connections. -func WithCertKey(certKey string) *certKeyOption { - return &certKeyOption{certKey: certKey} -} - -type certKeyOption struct { - certKey string -} - -func (o *certKeyOption) ApplyToReader(r *Reader) { - r.certKey = o.certKey -} - -func (o *certKeyOption) ApplyToBaseNode(n *baseNode) { - n.certKey = o.certKey -} - // Read will read the Taskfile defined by the [Reader]'s [Node] and recurse // through any [ast.Includes] it finds, reading each included Taskfile and // building an [ast.TaskfileGraph] as it goes. If any errors occur, they will be diff --git a/taskfile/snippet.go b/taskfile/snippet.go index 397e41e812..746a25d106 100644 --- a/taskfile/snippet.go +++ b/taskfile/snippet.go @@ -84,59 +84,6 @@ func (s *Snippet) Options(opts ...SnippetOption) { } } -// WithLine specifies the line number that the [Snippet] should center around -// and point to. -func WithLine(line int) *lineOption { - return &lineOption{line: line} -} - -type lineOption struct { - line int -} - -func (o *lineOption) ApplyToSnippet(s *Snippet) { - s.line = o.line -} - -// WithColumn specifies the column number that the [Snippet] should point to. -func WithColumn(column int) *columnOption { - return &columnOption{column: column} -} - -type columnOption struct { - column int -} - -func (o *columnOption) ApplyToSnippet(s *Snippet) { - s.column = o.column -} - -// WithPadding specifies the number of lines to include before and after the -// selected line in the [Snippet]. -func WithPadding(padding int) *paddingOption { - return &paddingOption{padding: padding} -} - -type paddingOption struct { - padding int -} - -func (o *paddingOption) ApplyToSnippet(s *Snippet) { - s.padding = o.padding -} - -// WithNoIndicators specifies that the [Snippet] should not include line or -// column indicators. -func WithNoIndicators() *noIndicatorsOption { - return &noIndicatorsOption{} -} - -type noIndicatorsOption struct{} - -func (o *noIndicatorsOption) ApplyToSnippet(s *Snippet) { - s.noIndicators = true -} - func (s *Snippet) String() string { buf := &bytes.Buffer{}