Skip to content

Commit 893dd2c

Browse files
authored
prefixed output option --prefix (#120)
1 parent b8569db commit 893dd2c

3 files changed

Lines changed: 86 additions & 6 deletions

File tree

‎cmd/tsk/tsk.go‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type Options struct {
2626
init bool
2727
listTasks bool
2828
output string
29+
prefix bool
2930
pure bool
3031
taskFile string
3132
tasks []string
@@ -46,6 +47,7 @@ func main() {
4647
flag.BoolVar(&opts.init, "init", false, "create a tasks.toml file in $PWD")
4748
flag.BoolVarP(&opts.listTasks, "list", "l", false, "list tasks")
4849
flag.StringVarP(&opts.output, "output", "o", "text", fmt.Sprintf("output format (applies only to --list) (one of: %s)", output.String()))
50+
flag.BoolVar(&opts.prefix, "prefix", false, "prefix task output with the task name")
4951
flag.BoolVarP(&opts.pure, "pure", "", false, "don't inherit the parent env")
5052
flag.StringVarP(&opts.taskFile, "file", "f", "", "taskfile to use")
5153
flag.BoolVar(&opts.which, "which", false, "print the path to the found tasks.toml, or an error")
@@ -91,6 +93,7 @@ func main() {
9193
Stdin: os.Stdin,
9294
Stderr: os.Stderr,
9395
Config: cfg,
96+
Prefix: opts.prefix,
9497
}
9598

9699
if opts.listTasks {

‎internal/task/task.go‎

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,13 @@ type Task struct {
4343
}
4444

4545
type Executor struct {
46-
Stdout io.Writer
47-
Stdin io.Reader
48-
Stderr io.Writer
49-
Config *Config
46+
Stdout io.Writer
47+
Stdin io.Reader
48+
Stderr io.Writer
49+
Config *Config
50+
Prefix bool
51+
colorIndex int
52+
taskColors map[string]string
5053
}
5154

5255
// sets the top-level env
@@ -90,6 +93,26 @@ func (t *Task) CompileEnv(env []string) ([]string, error) {
9093
return env, nil
9194
}
9295

96+
func (exec *Executor) colorForTask(task string) string {
97+
if exec.taskColors == nil {
98+
exec.taskColors = make(map[string]string)
99+
}
100+
if color, ok := exec.taskColors[task]; ok {
101+
return color
102+
}
103+
color := prefixColors[exec.colorIndex%len(prefixColors)]
104+
exec.colorIndex++
105+
exec.taskColors[task] = color
106+
return color
107+
}
108+
109+
func (exec *Executor) prefixedWriter(w io.Writer, prefix string, task string) io.Writer {
110+
if exec.Prefix {
111+
return newPrefixWriter(w, prefix, exec.colorForTask(task))
112+
}
113+
return w
114+
}
115+
93116
func (exec *Executor) RunTasks(config *Config, tasks *[]string) error {
94117
// top-level env
95118
env, err := config.CompileEnv()
@@ -133,10 +156,18 @@ func (exec *Executor) RunTasks(config *Config, tasks *[]string) error {
133156
return err
134157
}
135158

159+
taskExec := &Executor{
160+
Stdout: exec.prefixedWriter(exec.Stdout, "::"+task+":: ", task),
161+
Stderr: exec.prefixedWriter(exec.Stderr, "::"+task+":: ", task),
162+
Stdin: exec.Stdin,
163+
Config: exec.Config,
164+
Prefix: exec.Prefix,
165+
}
166+
136167
// if a task contains cmds, run them
137168
if len(taskConfig.Cmds) > 0 {
138169
for _, cmd := range taskConfig.Cmds {
139-
err := exec.runCommand(cmd, taskConfig.Dir, env)
170+
err := taskExec.runCommand(cmd, taskConfig.Dir, env)
140171
if err != nil {
141172
fmt.Println(err.Error())
142173
// if the cmd exited with an error, bail immediately
@@ -146,7 +177,7 @@ func (exec *Executor) RunTasks(config *Config, tasks *[]string) error {
146177
} else {
147178
// if there are no cmds then we intend to run a script with the name name as the task
148179
script := fmt.Sprintf("%s/%s", exec.Config.ScriptDir, task)
149-
err := exec.runCommand(script, taskConfig.Dir, env)
180+
err := taskExec.runCommand(script, taskConfig.Dir, env)
150181
if err != nil {
151182
fmt.Println(err.Error())
152183
// if the cmd exited with an error, bail immediately

‎internal/task/util.go‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,58 @@ package task
33
import (
44
"bytes"
55
"fmt"
6+
"io"
67
"sort"
78
"text/template"
89

910
"github.com/joho/godotenv"
1011
)
1112

13+
// ANSI color codes for prefix coloring. These are chosen for visual distinction.
14+
var prefixColors = []string{
15+
"\033[36m", // cyan
16+
"\033[33m", // yellow
17+
"\033[35m", // magenta
18+
"\033[32m", // green
19+
"\033[34m", // blue
20+
"\033[31m", // red
21+
"\033[96m", // bright cyan
22+
"\033[93m", // bright yellow
23+
"\033[95m", // bright magenta
24+
"\033[92m", // bright green
25+
"\033[94m", // bright blue
26+
"\033[91m", // bright red
27+
}
28+
29+
const colorReset = "\033[0m"
30+
31+
type prefixWriter struct {
32+
writer io.Writer
33+
prefix string
34+
buf []byte
35+
}
36+
37+
func newPrefixWriter(w io.Writer, prefix string, color string) *prefixWriter {
38+
coloredPrefix := color + prefix + colorReset
39+
return &prefixWriter{writer: w, prefix: coloredPrefix}
40+
}
41+
42+
func (p *prefixWriter) Write(b []byte) (int, error) {
43+
p.buf = append(p.buf, b...)
44+
for {
45+
idx := bytes.IndexByte(p.buf, '\n')
46+
if idx < 0 {
47+
break
48+
}
49+
line := p.buf[:idx+1]
50+
if _, err := fmt.Fprintf(p.writer, "%s%s", p.prefix, line); err != nil {
51+
return 0, err
52+
}
53+
p.buf = p.buf[idx+1:]
54+
}
55+
return len(b), nil
56+
}
57+
1258
type Vals struct {
1359
CLI_ARGS string
1460
}

0 commit comments

Comments
 (0)