blob: 18e0facffe827c2abcc704abee0d92a2c4200111 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package main
import (
"fmt"
"os/exec"
"runtime"
"strings"
"syscall"
)
type userError struct {
err string
}
var _ error = userError{}
func (err userError) Error() string {
return err.err
}
func newUserErrorf(format string, v ...interface{}) userError {
return userError{err: fmt.Sprintf(format, v...)}
}
func newErrorwithSourceLocf(format string, v ...interface{}) error {
return newErrorwithSourceLocfInternal(2, format, v...)
}
func wrapErrorwithSourceLocf(err error, format string, v ...interface{}) error {
return newErrorwithSourceLocfInternal(2, "%s: %s", fmt.Sprintf(format, v...), err.Error())
}
func wrapSubprocessErrorWithSourceLoc(cmd *command, subprocessErr error) (exitCode int, err error) {
if subprocessErr == nil {
return 0, nil
}
if userErr, ok := getCCacheError(cmd, subprocessErr); ok {
return 0, userErr
}
if exitCode, ok := getExitCode(subprocessErr); ok {
return exitCode, nil
}
err = newErrorwithSourceLocfInternal(2, "failed to execute %#v: %s", cmd, subprocessErr)
return 0, err
}
// Based on the implementation of log.Output
func newErrorwithSourceLocfInternal(skip int, format string, v ...interface{}) error {
_, file, line, ok := runtime.Caller(skip)
if !ok {
file = "???"
line = 0
}
if lastSlash := strings.LastIndex(file, "/"); lastSlash >= 0 {
file = file[lastSlash+1:]
}
return fmt.Errorf("%s:%d: %s", file, line, fmt.Sprintf(format, v...))
}
func getExitCode(err error) (exitCode int, ok bool) {
if err == nil {
return 0, true
}
if exiterr, ok := err.(*exec.ExitError); ok {
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
return status.ExitStatus(), true
}
}
return 0, false
}
func getCCacheError(compilerCmd *command, compilerCmdErr error) (ccacheErr userError, ok bool) {
if en, ok := compilerCmdErr.(syscall.Errno); ok && en == syscall.ENOENT &&
strings.Contains(compilerCmd.Path, "ccache") {
ccacheErr =
newUserErrorf("ccache not found under %s. Please install it",
compilerCmd.Path)
return ccacheErr, true
}
return ccacheErr, false
}