pkg/commandhandler/cmd_windows.go (54 lines of code) (raw):

// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. package commandhandler import ( "fmt" "github.com/pkg/errors" "io" "os" "os/exec" "syscall" ) func execWait(cmd, workdir string, stdout, stderr io.WriteCloser) (int, error) { defer stdout.Close() defer stderr.Close() return execCommonWithEnvVariables(cmd, workdir, stdout, stderr, func(c *exec.Cmd) error { return c.Run() }, nil) } func execWaitWithEnvVariables(cmd, workdir string, stdout, stderr io.WriteCloser, params *map[string]string) (int, error) { defer stdout.Close() defer stderr.Close() return execCommonWithEnvVariables(cmd, workdir, stdout, stderr, func(c *exec.Cmd) error { return c.Run() }, params) } func execDontWait(cmd, workdir string) (int, error) { return execCommonWithEnvVariables(cmd, workdir, nil, nil, func(c *exec.Cmd) error { return c.Start() }, nil) } func execDontWaitWithEnvVariables(cmd, workdir string, params *map[string]string) (int, error) { return execCommonWithEnvVariables(cmd, workdir, nil, nil, func(c *exec.Cmd) error { return c.Start() }, params) } func execCommonWithEnvVariables(cmd, workdir string, stdout, stderr io.WriteCloser, execFunctionToCall func(*exec.Cmd) error, params *map[string]string) (int, error) { c := exec.Command("cmd") c.Dir = workdir c.Stdout = stdout c.Stderr = stderr c.Env = os.Environ() addEnvVariables(params, c) // don't pass the args in exec.Command because // On Windows, processes receive the whole command line as a single string // and do their own parsing. Command combines and quotes Args into a command // line string with an algorithm compatible with applications using // CommandLineToArgvW (which is the most common way). Notable exceptions are // msiexec.exe and cmd.exe (and thus, all batch files), which have a different // unquoting algorithm. In these or other similar cases, you can do the // quoting yourself and provide the full command line in SysProcAttr.CmdLine, // leaving Args empty. c.SysProcAttr = &syscall.SysProcAttr{CmdLine: "/C " + cmd} err := execFunctionToCall(c) exitErr, ok := err.(*exec.ExitError) if ok { if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { code := status.ExitStatus() return code, fmt.Errorf("command terminated with exit status=%d", code) } } if err != nil { return 1, errors.Wrapf(err, "failed to execute command") } return 0, nil }