in pkg/gcpbuildpack/exec.go [159:253]
func (ctx *Context) configuredExec(params execParams) (*ExecResult, error) {
if len(params.cmd) < 1 {
return nil, fmt.Errorf("no command provided")
}
if params.cmd[0] == "" {
return nil, fmt.Errorf("empty command provided")
}
defaultShouldLog := true
if !params.userAttribution && !ctx.debug {
// For "system" commands, we will only log if the debug flag is present.
defaultShouldLog = false
}
readableCmd := strings.Join(params.cmd, " ")
if len(params.env) > 0 {
env := strings.Join(params.env, " ")
readableCmd = fmt.Sprintf("%s (%s)", readableCmd, env)
}
logCmd := defaultShouldLog
if params.logCommandOverride != nil {
logCmd = *params.logCommandOverride
}
if logCmd {
ctx.Logf(divider)
ctx.Logf("Running %q", readableCmd)
}
status := buildererror.StatusInternal
defer func(start time.Time) {
truncated := readableCmd
if len(truncated) > 60 {
truncated = truncated[:60] + "..."
}
if logCmd {
ctx.Logf("Done %q (%v)", truncated, time.Since(start))
}
ctx.Span(ctx.createSpanName(params.cmd), start, status)
}(time.Now())
exitCode := 0
ecmd := ctx.execCmd(params.cmd[0], params.cmd[1:]...)
if params.dir != "" {
ecmd.Dir = params.dir
}
if len(params.env) > 0 {
ecmd.Env = append(append(ecmd.Env, os.Environ()...), params.env...)
}
logOutput := defaultShouldLog
if params.logOutputOverride != nil {
logOutput = *params.logOutputOverride
}
var outb, errb bytes.Buffer
combinedb := lockingBuffer{ctx: ctx, log: logOutput}
ecmd.Stdout = io.MultiWriter(&outb, &combinedb)
ecmd.Stderr = io.MultiWriter(&errb, &combinedb)
if err := ecmd.Run(); err != nil {
if ee, ok := err.(*exec.ExitError); ok {
// The command returned a non-zero result.
exitCode = ee.ExitCode()
} else if pe, ok := err.(*os.PathError); ok && pe.Err == unix.ENOENT {
// ENOENT normally occurs if the command cannot
// be found, but also occurs with scripts using
// CR-LF line endings. Unix uses LF as its line
// ending, so a script with a shebang using CR-LF
// will result in the kernel attempting to
// resolve an executable name with the trailing
// CR. This search will almost certainly fail and
// otherwise results in an confusing ENOENT.
return nil, fmt.Errorf("executing command %q: %v: if %q is a script, ensure that it has Unix-style LF line endings", readableCmd, err, params.cmd[0])
} else {
return nil, fmt.Errorf("executing command %q: %v", readableCmd, err)
}
}
result := &ExecResult{
ExitCode: exitCode,
Stdout: strings.TrimSpace(string(outb.Bytes())),
Stderr: strings.TrimSpace(string(errb.Bytes())),
Combined: strings.TrimSpace(string(combinedb.Bytes())),
}
if exitCode != 0 {
return result, fmt.Errorf("executing command %q: exit code %d", readableCmd, exitCode)
}
status = buildererror.StatusOk
return result, nil
}