Skip to content

Commit a210155

Browse files
committed
feat: add ability to run default task
1 parent e482471 commit a210155

4 files changed

Lines changed: 143 additions & 42 deletions

File tree

cmd/ror/main.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,40 @@ func execute(io io.IO, ctx internal.Context) {
154154
return
155155
}
156156

157-
if ctx.Args.TaskName == "" || slices.Contains(ctx.Args.RorArgs, "+list") {
157+
// Handle +list flag explicitly
158+
if slices.Contains(ctx.Args.RorArgs, "+list") {
158159
commands.CmdListTasks(io, ctx)
159160
return
160161
}
161162

163+
// If no task is specified, use default task if available
164+
if ctx.Args.TaskName == "" {
165+
if ctx.Env.VerbosityLevel >= task.VerbosityDebug {
166+
fmt.Fprintf(io.Std().Stderr(), "[DEBUG] Default task: '%s'\n", ctx.Project.DefaultTask)
167+
}
168+
if ctx.Project.DefaultTask != "" {
169+
// Use the default task
170+
ctx.Args.TaskName = ctx.Project.DefaultTask
171+
// If no task args were provided and default args are defined, use them
172+
if len(ctx.Args.TaskArgs) == 0 && len(ctx.Project.DefaultArgs) > 0 {
173+
ctx.Args.TaskArgs = ctx.Project.DefaultArgs
174+
if ctx.Env.VerbosityLevel >= task.VerbosityDebug {
175+
fmt.Fprintf(io.Std().Stderr(), "[DEBUG] Using default args: %v\n", ctx.Args.TaskArgs)
176+
}
177+
}
178+
if ctx.Env.VerbosityLevel >= task.VerbosityDebug {
179+
fmt.Fprintf(io.Std().Stderr(), "[DEBUG] Using default task: '%s'\n", ctx.Args.TaskName)
180+
}
181+
} else {
182+
// No default task, list tasks
183+
commands.CmdListTasks(io, ctx)
184+
return
185+
}
186+
}
187+
188+
if ctx.Env.VerbosityLevel >= task.VerbosityDebug {
189+
fmt.Fprintf(io.Std().Stderr(), "[DEBUG] Choosen task: '%s'\n", ctx.Args.TaskName)
190+
}
162191
switch ctx.Args.TaskName {
163192
case "version":
164193
// Version command respects verbosity (silent and quiet suppress output)

internal/config/config.go

Lines changed: 108 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,56 +23,81 @@ func ParseProject(io io.IO, filename string) task.Project {
2323

2424
// Iterate over top-level nodes
2525
for _, node := range doc.Nodes {
26-
if node.Name != "task" {
27-
panic(fmt.Sprintf("unknown top-level node: %s", node.Name))
28-
}
26+
if node.Name == "default" {
27+
// Parse default node with properties: task and args
28+
for _, prop := range node.Properties {
29+
if prop.Key == "task" {
30+
config.DefaultTask = prop.Value.Value
31+
} else if prop.Key == "args" {
32+
// Split args by whitespace to get individual arguments
33+
argsStr := prop.Value.Value
34+
if argsStr != "" {
35+
// Simple split by space - could be enhanced to handle quoted strings
36+
config.DefaultArgs = splitArgs(argsStr)
37+
}
38+
}
39+
}
2940

30-
if len(node.Arguments) < 1 {
31-
panic("task node requires a name argument")
32-
}
41+
if config.DefaultTask == "" {
42+
panic("default node requires a 'task' property")
43+
}
44+
} else {
45+
// fmt.Printf("[DEBUG] Found task node: %+v\n", node.Name)
46+
// fmt.Printf("[DEBUG] Found task node: %+v\n", node)
47+
// fmt.Printf("[DEBUG] Arguments: %+v\n", node.Arguments)
48+
// fmt.Printf("[DEBUG] Children: %+v\n", node.Children)
3349

34-
taskName := node.Arguments[0].Value
50+
if node.Name != "task" {
51+
panic(fmt.Sprintf("unknown top-level node: %s", node.Name))
52+
}
3553

36-
task := task.Task{
37-
Name: taskName,
38-
DependsOn: []string{},
39-
EnvVars: make(map[string]string),
40-
}
54+
if len(node.Arguments) < 1 {
55+
panic("task node requires a name argument")
56+
}
4157

42-
if node.Children != nil {
43-
for _, child := range node.Children {
44-
switch child.Name {
45-
case "cmd":
46-
cmd, cmdTemplate := parseCmdNode(child)
47-
if cmdTemplate != nil {
48-
task.CommandTemplate = cmdTemplate
49-
} else {
50-
task.Command = cmd
51-
}
52-
case "description":
53-
if len(child.Arguments) > 0 {
54-
task.Description = child.Arguments[0].Value
55-
}
56-
case "depends":
57-
if child.Children != nil {
58-
for _, dep := range child.Children {
59-
if dep.Name == "on" && len(dep.Arguments) > 0 {
60-
task.DependsOn = append(task.DependsOn, dep.Arguments[0].Value)
58+
taskName := node.Arguments[0].Value
59+
60+
task := task.Task{
61+
Name: taskName,
62+
DependsOn: []string{},
63+
EnvVars: make(map[string]string),
64+
}
65+
66+
if node.Children != nil {
67+
for _, child := range node.Children {
68+
switch child.Name {
69+
case "cmd":
70+
cmd, cmdTemplate := parseCmdNode(child)
71+
if cmdTemplate != nil {
72+
task.CommandTemplate = cmdTemplate
73+
} else {
74+
task.Command = cmd
75+
}
76+
case "description":
77+
if len(child.Arguments) > 0 {
78+
task.Description = child.Arguments[0].Value
79+
}
80+
case "depends":
81+
if child.Children != nil {
82+
for _, dep := range child.Children {
83+
if dep.Name == "on" && len(dep.Arguments) > 0 {
84+
task.DependsOn = append(task.DependsOn, dep.Arguments[0].Value)
85+
}
6186
}
6287
}
88+
case "env":
89+
// env KEY="value" (property syntax)
90+
for _, prop := range child.Properties {
91+
task.EnvVars[prop.Key] = prop.Value.Value
92+
}
93+
default:
94+
panic(fmt.Sprintf("unknown property in task '%s': %s", taskName, child.Name))
6395
}
64-
case "env":
65-
// env KEY="value" (property syntax)
66-
for _, prop := range child.Properties {
67-
task.EnvVars[prop.Key] = prop.Value.Value
68-
}
69-
default:
70-
panic(fmt.Sprintf("unknown property in task '%s': %s", taskName, child.Name))
7196
}
7297
}
73-
}
7498

75-
config.Tasks.Set(taskName, task)
99+
config.Tasks.Set(taskName, task)
100+
}
76101
}
77102

78103
return config
@@ -180,3 +205,46 @@ func parseWhereVariable(node kdly.Node) task.WhereVariable {
180205
Children: children,
181206
}
182207
}
208+
209+
// splitArgs splits a string of arguments by whitespace
210+
// This is a simple implementation that doesn't handle quoted strings
211+
func splitArgs(argsStr string) []string {
212+
if argsStr == "" {
213+
return nil
214+
}
215+
216+
var args []string
217+
var current string
218+
inQuote := false
219+
quoteChar := rune(0)
220+
221+
for _, ch := range argsStr {
222+
if !inQuote {
223+
if ch == ' ' || ch == '\t' {
224+
if current != "" {
225+
args = append(args, current)
226+
current = ""
227+
}
228+
continue
229+
} else if ch == '"' || ch == '\'' {
230+
inQuote = true
231+
quoteChar = ch
232+
continue
233+
}
234+
} else {
235+
if ch == quoteChar {
236+
inQuote = false
237+
quoteChar = 0
238+
continue
239+
}
240+
}
241+
242+
current += string(ch)
243+
}
244+
245+
if current != "" {
246+
args = append(args, current)
247+
}
248+
249+
return args
250+
}

internal/task/models.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,7 @@ type Task struct {
4646
}
4747

4848
type Project struct {
49-
Tasks *orderedmap.OrderedMap[string, Task]
49+
Tasks *orderedmap.OrderedMap[string, Task]
50+
DefaultTask string // Task to run when no task is specified
51+
DefaultArgs []string // Arguments to pass to the default task
5052
}

ror.kdl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
default task="run" args="+list"
2+
13
task run {
24
description "Runs the application"
35

0 commit comments

Comments
 (0)