|
1 | 1 | package utils
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "bytes" |
| 5 | + "io" |
4 | 6 | "os"
|
5 | 7 | "strings"
|
6 | 8 | "unicode"
|
7 | 9 |
|
| 10 | + "github.com/arduino/arduino-cli/executils" |
8 | 11 | f "github.com/arduino/arduino-cli/internal/algorithms"
|
9 | 12 | "github.com/arduino/go-paths-helper"
|
10 | 13 | "github.com/pkg/errors"
|
@@ -179,3 +182,69 @@ func FindFilesInFolder(dir *paths.Path, recurse bool, extensions ...string) (pat
|
179 | 182 | }
|
180 | 183 | return dir.ReadDir(fileFilter)
|
181 | 184 | }
|
| 185 | + |
| 186 | +const ( |
| 187 | + Ignore = 0 // Redirect to null |
| 188 | + Show = 1 // Show on stdout/stderr as normal |
| 189 | + ShowIfVerbose = 2 // Show if verbose is set, Ignore otherwise |
| 190 | + Capture = 3 // Capture into buffer |
| 191 | +) |
| 192 | + |
| 193 | +func printableArgument(arg string) string { |
| 194 | + if strings.ContainsAny(arg, "\"\\ \t") { |
| 195 | + arg = strings.ReplaceAll(arg, "\\", "\\\\") |
| 196 | + arg = strings.ReplaceAll(arg, "\"", "\\\"") |
| 197 | + return "\"" + arg + "\"" |
| 198 | + } else { |
| 199 | + return arg |
| 200 | + } |
| 201 | +} |
| 202 | + |
| 203 | +// Convert a command and argument slice back to a printable string. |
| 204 | +// This adds basic escaping which is sufficient for debug output, but |
| 205 | +// probably not for shell interpretation. This essentially reverses |
| 206 | +// ParseCommandLine. |
| 207 | +func PrintableCommand(parts []string) string { |
| 208 | + return strings.Join(f.Map(parts, printableArgument), " ") |
| 209 | +} |
| 210 | + |
| 211 | +func ExecCommand( |
| 212 | + verbose bool, |
| 213 | + stdoutWriter, stderrWriter io.Writer, |
| 214 | + command *executils.Process, stdout int, stderr int, |
| 215 | +) ([]byte, []byte, []byte, error) { |
| 216 | + verboseInfoBuf := &bytes.Buffer{} |
| 217 | + if verbose { |
| 218 | + verboseInfoBuf.WriteString(PrintableCommand(command.GetArgs())) |
| 219 | + } |
| 220 | + |
| 221 | + stdoutBuffer := &bytes.Buffer{} |
| 222 | + if stdout == Capture { |
| 223 | + command.RedirectStdoutTo(stdoutBuffer) |
| 224 | + } else if stdout == Show || (stdout == ShowIfVerbose && verbose) { |
| 225 | + if stdoutWriter != nil { |
| 226 | + command.RedirectStdoutTo(stdoutWriter) |
| 227 | + } else { |
| 228 | + command.RedirectStdoutTo(os.Stdout) |
| 229 | + } |
| 230 | + } |
| 231 | + |
| 232 | + stderrBuffer := &bytes.Buffer{} |
| 233 | + if stderr == Capture { |
| 234 | + command.RedirectStderrTo(stderrBuffer) |
| 235 | + } else if stderr == Show || (stderr == ShowIfVerbose && verbose) { |
| 236 | + if stderrWriter != nil { |
| 237 | + command.RedirectStderrTo(stderrWriter) |
| 238 | + } else { |
| 239 | + command.RedirectStderrTo(os.Stderr) |
| 240 | + } |
| 241 | + } |
| 242 | + |
| 243 | + err := command.Start() |
| 244 | + if err != nil { |
| 245 | + return verboseInfoBuf.Bytes(), nil, nil, errors.WithStack(err) |
| 246 | + } |
| 247 | + |
| 248 | + err = command.Wait() |
| 249 | + return verboseInfoBuf.Bytes(), stdoutBuffer.Bytes(), stderrBuffer.Bytes(), errors.WithStack(err) |
| 250 | +} |
0 commit comments