diff --git a/taskfile/ast/task.go b/taskfile/ast/task.go index 4e28625f..049cdc6b 100644 --- a/taskfile/ast/task.go +++ b/taskfile/ast/task.go @@ -2,6 +2,8 @@ package ast import ( "fmt" + "regexp" + "strings" "gopkg.in/yaml.v3" @@ -51,6 +53,30 @@ func (t *Task) Name() string { return t.Task } +// WildcardMatch will check if the given string matches the name of the Task and returns any wildcard values. +func (t *Task) WildcardMatch(name string) (bool, []string) { + // Convert the name into a regex string + regexStr := fmt.Sprintf("^%s$", strings.ReplaceAll(t.Task, "*", "(.*)")) + regex := regexp.MustCompile(regexStr) + wildcards := regex.FindStringSubmatch(name) + wildcardCount := strings.Count(t.Task, "*") + + // If there are no wildcards, return false + if len(wildcards) == 0 { + return false, nil + } + + // Remove the first match, which is the full string + wildcards = wildcards[1:] + + // If there are more/less wildcards than matches, return false + if len(wildcards) != wildcardCount { + return false, wildcards + } + + return true, wildcards +} + func (t *Task) UnmarshalYAML(node *yaml.Node) error { switch node.Kind { diff --git a/taskfile/ast/tasks.go b/taskfile/ast/tasks.go index 0bce50b4..a0d288db 100644 --- a/taskfile/ast/tasks.go +++ b/taskfile/ast/tasks.go @@ -14,6 +14,31 @@ type Tasks struct { omap.OrderedMap[string, *Task] } +func (t *Tasks) Get(call *Call) *Task { + if call == nil { + return nil + } + var task *Task + // If there is a direct match, return it + if task = t.OrderedMap.Get(call.Task); task != nil { + return task + } + if call.Vars == nil { + call.Vars = &Vars{} + } + // Attempt a wildcard match + // TODO: We need to add a yield func to the Range method so that we can stop looping when we find a match + // For now, we can just nil check the task before each loop + _ = t.Range(func(key string, value *Task) error { + if match, wildcards := value.WildcardMatch(call.Task); match && task == nil { + task = value + call.Vars.Set("MATCH", Var{Value: wildcards}) + } + return nil + }) + return task +} + func (t1 *Tasks) Merge(t2 Tasks, include *Include) { _ = t2.Range(func(k string, v *Task) error { // We do a deep copy of the task struct here to ensure that no data can diff --git a/testdata/wildcards/Taskfile.yml b/testdata/wildcards/Taskfile.yml new file mode 100644 index 00000000..d13f836d --- /dev/null +++ b/testdata/wildcards/Taskfile.yml @@ -0,0 +1,16 @@ +version: 3 + +tasks: + wildcard-*: + cmds: + - echo "Hello {{index .MATCH 0}}" + + '*-wildcard-*': + cmds: + - echo "Hello {{index .MATCH 0}} {{index .MATCH 1}}" + + start-*: + vars: + SERVICE: "{{index .MATCH 0}}" + cmds: + - echo "Starting {{.SERVICE}}"