|
4 | 4 | // "bytes" |
5 | 5 | "context" |
6 | 6 | "fmt" |
7 | | - "io" |
8 | 7 | "os" |
9 | 8 | "os/exec" |
10 | 9 | "path/filepath" |
@@ -58,230 +57,74 @@ type CreateCommandGroupArgs struct { |
58 | 57 | Runfile *types.ParsedRunfile |
59 | 58 | Task *types.ParsedTask |
60 | 59 |
|
61 | | - Prefix string |
| 60 | + Trail []string |
62 | 61 |
|
63 | | - Stdout io.Writer |
64 | | - Stderr io.Writer |
| 62 | + Stdout *LogWriter |
| 63 | + Stderr *LogWriter |
65 | 64 | } |
66 | 65 |
|
67 | | -func createCommandGroups(ctx Context, prf *types.ParsedRunfile, pt *types.ParsedTask, stdout *LogWriter, stderr *LogWriter) ([]executor.CommandGroup, error) { |
| 66 | +func createCommandGroups(ctx Context, args CreateCommandGroupArgs) ([]executor.CommandGroup, error) { |
68 | 67 | var cmds []executor.CommandGroup |
69 | 68 |
|
70 | | - for _, cmd := range pt.Commands { |
| 69 | + for _, cmd := range args.Task.Commands { |
71 | 70 | switch { |
72 | 71 | case cmd.Run != nil: |
73 | 72 | { |
74 | | - rt, ok := prf.Tasks[*cmd.Run] |
| 73 | + rt, ok := args.Runfile.Tasks[*cmd.Run] |
75 | 74 | if !ok { |
76 | 75 | return nil, fmt.Errorf("invalid run target") |
77 | 76 | } |
78 | 77 |
|
79 | | - rtp, err := parser.ParseTask(ctx, prf, rt) |
| 78 | + rtp, err := parser.ParseTask(ctx, args.Runfile, rt) |
80 | 79 | if err != nil { |
81 | | - return nil, errors.WithErr(err).KV("env-vars", prf.Env) |
| 80 | + return nil, errors.WithErr(err).KV("env-vars", args.Runfile.Env) |
82 | 81 | } |
83 | 82 |
|
84 | | - rtCommands, err := createCommandGroups(ctx, prf, rtp, stdout, stderr) |
| 83 | + rtCommands, err := createCommandGroups(ctx, CreateCommandGroupArgs{ |
| 84 | + Runfile: args.Runfile, |
| 85 | + Task: rtp, |
| 86 | + Trail: append(append([]string{}, args.Trail...), rtp.Name), |
| 87 | + Stdout: args.Stdout, |
| 88 | + Stderr: args.Stderr, |
| 89 | + }) |
85 | 90 | if err != nil { |
86 | | - return nil, errors.WithErr(err).KV("env-vars", prf.Env) |
| 91 | + return nil, errors.WithErr(err).KV("env-vars", args.Runfile.Env) |
87 | 92 | } |
88 | 93 |
|
89 | 94 | cg := executor.CommandGroup{ |
90 | 95 | Groups: rtCommands, |
91 | 96 | Parallel: rtp.Parallel, |
92 | 97 | } |
93 | | - // |
94 | | - // logger := ctx.With("run", *cmd.Run) |
95 | | - // logger.Info("got", "len(cg.Commands)", len(cg.Commands), "len(cg.Groups)", len(cg.Groups)) |
96 | | - cmds = append(cmds, cg) |
97 | 98 |
|
98 | | - // cmds = append(cmds, rtCommands...) |
99 | | - |
100 | | - // ctx.Debug("HERE", "commands", len(cg.Commands), "run", *cmd.Run) |
101 | | - // cg.Parallel = rtp.Parallel |
| 99 | + cmds = append(cmds, cg) |
102 | 100 | } |
103 | 101 |
|
104 | 102 | case cmd.Command != nil: |
105 | 103 | { |
106 | | - cg := executor.CommandGroup{Parallel: pt.Parallel} |
| 104 | + cg := executor.CommandGroup{Parallel: args.Task.Parallel} |
107 | 105 |
|
108 | 106 | cg.Commands = append(cg.Commands, func(c context.Context) *exec.Cmd { |
109 | 107 | return CreateCommand(ctx, CmdArgs{ |
110 | | - Shell: pt.Shell, |
111 | | - Env: fn.ToEnviron(pt.Env), |
| 108 | + Shell: args.Task.Shell, |
| 109 | + Env: fn.ToEnviron(args.Task.Env), |
112 | 110 | Cmd: *cmd.Command, |
113 | | - WorkingDir: pt.WorkingDir, |
114 | | - interactive: pt.Interactive, |
115 | | - Stdout: stdout.WithPrefix(pt.Name), |
116 | | - Stderr: stdout.WithPrefix(pt.Name), |
| 111 | + WorkingDir: args.Task.WorkingDir, |
| 112 | + interactive: args.Task.Interactive, |
| 113 | + Stdout: args.Stdout.WithPrefix(strings.Join(args.Trail, "/")), |
| 114 | + Stderr: args.Stderr.WithPrefix(strings.Join(args.Trail, "/")), |
117 | 115 | }) |
118 | 116 | }) |
119 | 117 |
|
120 | | - ctx.Debug("HERE", "cmd", *cmd.Command, "parallel", pt.Parallel) |
| 118 | + ctx.Debug("HERE", "cmd", *cmd.Command, "parallel", args.Task.Parallel) |
121 | 119 |
|
122 | 120 | cmds = append(cmds, cg) |
123 | 121 | } |
124 | 122 | } |
125 | | - |
126 | | - // cmds = append(cmds, cg) |
127 | 123 | } |
128 | 124 |
|
129 | 125 | return cmds, nil |
130 | 126 | } |
131 | 127 |
|
132 | | -// func runCommand(ctx Context, prf *types.ParsedRunfile, pt *types.ParsedTask, args runTaskArgs, command types.ParsedCommandJson) error { |
133 | | -// ctx.Debug("running command task", "command.run", command.Runs, "parent.task", args.taskName) |
134 | | -// if command.If != nil && !*command.If { |
135 | | -// ctx.Debug("skipping execution for failed `if`", "command", command.Runs) |
136 | | -// return nil |
137 | | -// } |
138 | | -// |
139 | | -// if command.Runs != nil { |
140 | | -// for _, run := range command.Runs { |
141 | | -// rt, ok := prf.Tasks[run] |
142 | | -// if !ok { |
143 | | -// return fmt.Errorf("invalid run target") |
144 | | -// } |
145 | | -// |
146 | | -// rtp, err := parser.ParseTask(ctx, prf, rt) |
147 | | -// if err != nil { |
148 | | -// return errors.WithErr(err).KV("env-vars", prf.Env) |
149 | | -// } |
150 | | -// |
151 | | -// if err := runTaskCommands(ctx, prf, rtp, args); err != nil { |
152 | | -// return errors.WithErr(err).KV("env-vars", prf.Env) |
153 | | -// } |
154 | | -// return nil |
155 | | -// } |
156 | | -// } |
157 | | -// |
158 | | -// // stdoutR, stdoutW := io.Pipe() |
159 | | -// // stderrR, stderrW := io.Pipe() |
160 | | -// |
161 | | -// // wg := sync.WaitGroup{} |
162 | | -// |
163 | | -// // [snippet source](https://rderik.com/blog/identify-if-output-goes-to-the-terminal-or-is-being-redirected-in-golang/) |
164 | | -// // stdout, _ := os.Stdout.Stat() |
165 | | -// // stderr, _ := os.Stderr.Stat() |
166 | | -// // isTTY := ((stdout.Mode() & os.ModeCharDevice) == os.ModeCharDevice) && ((stderr.Mode() & os.ModeCharDevice) == os.ModeCharDevice) |
167 | | -// // |
168 | | -// // if isTTY { |
169 | | -// // go func() { |
170 | | -// // defer wg.Done() |
171 | | -// // logPrefix := fmt.Sprintf("%s ", ctx.theme.TaskPrefixStyle.Render(fmt.Sprintf("[%s]", strings.Join(trail, "/")))) |
172 | | -// // processOutput(os.Stdout, stdoutR, &logPrefix) |
173 | | -// // |
174 | | -// // stderrPrefix := fmt.Sprintf("%s ", ctx.theme.TaskPrefixStyle.Render(fmt.Sprintf("[%s/stderr]", strings.Join(trail, "/")))) |
175 | | -// // processOutput(os.Stderr, stderrR, &stderrPrefix) |
176 | | -// // }() |
177 | | -// // } else { |
178 | | -// // wg.Add(1) |
179 | | -// // go func() { |
180 | | -// // defer wg.Done() |
181 | | -// // logPrefix := fmt.Sprintf("%s ", ctx.theme.TaskPrefixStyle.Render(fmt.Sprintf("[%s]", strings.Join(trail, "/")))) |
182 | | -// // processOutput(os.Stdout, stdoutR, &logPrefix) |
183 | | -// // // if pt.Interactive { |
184 | | -// // // processOutput(os.Stdout, stdoutR, &logPrefix) |
185 | | -// // // return |
186 | | -// // // } |
187 | | -// // // processOutputLineByLine(os.Stdout, stdoutR, &logPrefix) |
188 | | -// // }() |
189 | | -// // |
190 | | -// // wg.Add(1) |
191 | | -// // go func() { |
192 | | -// // defer wg.Done() |
193 | | -// // logPrefix := fmt.Sprintf("%s ", ctx.theme.TaskPrefixStyle.Render(fmt.Sprintf("[%s/stderr]", strings.Join(trail, "/")))) |
194 | | -// // processOutput(os.Stderr, stderrR, &logPrefix) |
195 | | -// // // if pt.Interactive { |
196 | | -// // // processOutput(os.Stderr, stderrR, &logPrefix) |
197 | | -// // // return |
198 | | -// // // } |
199 | | -// // // processOutputLineByLine(os.Stderr, stderrR, &logPrefix) |
200 | | -// // }() |
201 | | -// // } |
202 | | -// |
203 | | -// if isTTY() { |
204 | | -// borderColor := "#4388cc" |
205 | | -// if !isDarkTheme() { |
206 | | -// borderColor = "#3d5485" |
207 | | -// } |
208 | | -// s := lipgloss.NewStyle().BorderForeground(lipgloss.Color(borderColor)).PaddingLeft(1).PaddingRight(1).Border(lipgloss.RoundedBorder(), true, true, true, true) |
209 | | -// // labelStyle := lipgloss.NewStyle().Foreground(lipgloss.Color(borderColor)).Blink(true) |
210 | | -// |
211 | | -// if args.DebugEnv { |
212 | | -// fmt.Printf("%s\n", s.Render(padString(fmt.Sprintf("%+v", prf.Env), "DEBUG: env"))) |
213 | | -// } |
214 | | -// |
215 | | -// hlCode := new(bytes.Buffer) |
216 | | -// // choose colorschemes from `https://swapoff.org/chroma/playground/` |
217 | | -// colorscheme := "catppuccin-macchiato" |
218 | | -// if !isDarkTheme() { |
219 | | -// colorscheme = "monokailight" |
220 | | -// } |
221 | | -// // quick.Highlight(hlCode, strings.TrimSpace(command.Command), "bash", "terminal16m", colorscheme) |
222 | | -// |
223 | | -// for i := range command.Commands { |
224 | | -// cmdStr := strings.TrimSpace(command.Commands[i]) |
225 | | -// |
226 | | -// quick.Highlight(hlCode, cmdStr, "bash", "terminal16m", colorscheme) |
227 | | -// // cst := styles.Get("gruvbox") |
228 | | -// // fmt.Println("cst: ", cst.Name, styles.Fallback.Name, styles.Names()) |
229 | | -// |
230 | | -// // fmt.Printf("%s\n", s.Render(args.taskName+" | "+hlCode.String())) |
231 | | -// fmt.Printf("%s\n", s.Render(padString(hlCode.String(), args.taskName))) |
232 | | -// } |
233 | | -// } |
234 | | -// |
235 | | -// // logger2 := logging.New(logging.Options{ |
236 | | -// // Prefix: "[runfile]", |
237 | | -// // Writer: os.Stderr, |
238 | | -// // SlogKeyAsPrefix: "task", |
239 | | -// // }) |
240 | | -// |
241 | | -// // ex := executor.NewCmdExecutor(ctx, executor.CmdExecutorArgs{ |
242 | | -// // Logger: logger2, |
243 | | -// // Interactive: pt.Interactive, |
244 | | -// // Commands: func(c context.Context) []*exec.Cmd { |
245 | | -// // commands := make([]*exec.Cmd, 0, len(command.Commands)) |
246 | | -// // for i := range command.Commands { |
247 | | -// // commands = append(commands, CreateCommand(c, CmdArgs{ |
248 | | -// // Shell: pt.Shell, |
249 | | -// // Env: fn.ToEnviron(pt.Env), |
250 | | -// // Cmd: command.Commands[i], |
251 | | -// // WorkingDir: pt.WorkingDir, |
252 | | -// // interactive: pt.Interactive, |
253 | | -// // Stdout: os.Stdout, |
254 | | -// // Stderr: os.Stderr, |
255 | | -// // })) |
256 | | -// // } |
257 | | -// // return commands |
258 | | -// // }, |
259 | | -// // }) |
260 | | -// // |
261 | | -// // wg.Add(1) |
262 | | -// // go func() { |
263 | | -// // defer wg.Done() |
264 | | -// // <-ctx.Done() |
265 | | -// // ex.Stop() |
266 | | -// // }() |
267 | | -// // |
268 | | -// // if err := ex.Start(); err != nil { |
269 | | -// // return errors.ErrTaskFailed.Wrap(err).KV("task", args.taskName) |
270 | | -// // } |
271 | | -// |
272 | | -// return nil |
273 | | -// } |
274 | | - |
275 | | -// func runTaskCommands(ctx Context, prf *types.ParsedRunfile, pt *types.ParsedTask, args runTaskArgs) error { |
276 | | -// for _, command := range pt.Commands { |
277 | | -// if err := runCommand(ctx, prf, pt, args, command); err != nil { |
278 | | -// return err |
279 | | -// } |
280 | | -// } |
281 | | -// |
282 | | -// return nil |
283 | | -// } |
284 | | - |
285 | 128 | func runTask(ctx Context, prf *types.ParsedRunfile, args runTaskArgs) error { |
286 | 129 | runfilePath := prf.Metadata.RunfilePath |
287 | 130 | task := prf.Tasks[args.taskName] |
@@ -309,7 +152,13 @@ func runTask(ctx Context, prf *types.ParsedRunfile, args runTaskArgs) error { |
309 | 152 |
|
310 | 153 | logStdout := &LogWriter{w: os.Stdout} |
311 | 154 |
|
312 | | - execCommands, err := createCommandGroups(ctx, prf, pt, logStdout, logStdout) |
| 155 | + execCommands, err := createCommandGroups(ctx, CreateCommandGroupArgs{ |
| 156 | + Runfile: prf, |
| 157 | + Task: pt, |
| 158 | + Trail: []string{pt.Name}, |
| 159 | + Stdout: logStdout, |
| 160 | + Stderr: logStdout, |
| 161 | + }) |
313 | 162 | if err != nil { |
314 | 163 | return err |
315 | 164 | } |
|
0 commit comments