in sharedlibraries/commandlineexecutor/commandlineexecutor.go [133:206]
func ExecuteCommand(ctx context.Context, params Params) Result {
if !exists(params.Executable) {
log.CtxLogger(ctx).Debugw("Command executable not found", "executable", params.Executable)
msg := fmt.Sprintf("Command executable: %q not found.", params.Executable)
return Result{"", msg, 0, fmt.Errorf("command executable: %s not found", params.Executable), false, false}
}
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
// Timeout the command at 60 seconds by default.
timeout := 60 * time.Second
if params.Timeout > 0 {
timeout = time.Duration(params.Timeout) * time.Second
}
// Context tctx has a Timeout while running the commands.
tctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
args := params.Args
if params.ArgsToSplit != "" {
args = splitParams(params.ArgsToSplit)
}
exe := exec.CommandContext(tctx, params.Executable, args...)
exe.Stdin = strings.NewReader(params.Stdin)
exe.Stdout = stdout
exe.Stderr = stderr
var err error
if exeForPlatform != nil {
err = exeForPlatform(exe, params)
} else {
// We pass ctx because this calls back into ExecuteCommand which adds the timeout before running the command.
err = setupExeForPlatform(ctx, exe, params, ExecuteCommand)
}
if err != nil {
log.CtxLogger(ctx).Debugw("Could not setup the executable environment", "executable", params.Executable, "args", args, "error", err)
return Result{stdout.String(), stderr.String(), 0, err, true, false}
}
log.CtxLogger(ctx).Debugw("Executing command", "executable", params.Executable, "args", args,
"timeout", timeout, "user", params.User, "env", params.Env)
if run != nil {
err = run()
} else {
err = exe.Run()
}
if err != nil {
// Set the exit code based on the error first, then see if we can get it from the error message.
exitCode := exitCode(err)
m := exitStatusPattern.FindStringSubmatch(err.Error())
exitStatusParsed := false
if len(m) > 0 {
atoi, serr := strconv.Atoi(m[1])
if serr != nil {
log.CtxLogger(ctx).Debugw("Failed to get command exit code from string match", "executable", params.Executable,
"args", args, "error", serr)
} else {
// This is the case where we expect to have an Error but want the exit code from the "exit status #" string
exitCode = atoi
exitStatusParsed = true
}
} else {
log.CtxLogger(ctx).Debugw("Error encountered when executing command", "executable", params.Executable,
"args", args, "exitcode", exitCode, "error", err, "stdout", stdout.String(),
"stderr", stderr.String())
}
return Result{stdout.String(), stderr.String(), exitCode, err, true, exitStatusParsed}
}
// Exit code can assumed to be 0
log.CtxLogger(ctx).Debugw("Successfully executed command", "executable", params.Executable, "args", args,
"stdout", stdout.String(), "stderr", stderr.String())
return Result{stdout.String(), stderr.String(), 0, nil, true, false}
}