blob: 8cf963448a87df2ed161e1494603ebeab8bfbc9f [file] [log] [blame]
Tobias Bosch900dbc92019-06-24 09:31:39 -07001package main
2
3import (
4 "fmt"
5 "os/exec"
6 "runtime"
7 "strings"
8 "syscall"
9)
10
11type userError struct {
12 err string
13}
14
15var _ error = userError{}
16
17func (err userError) Error() string {
18 return err.err
19}
20
21func newUserErrorf(format string, v ...interface{}) userError {
22 return userError{err: fmt.Sprintf(format, v...)}
23}
24
25func newErrorwithSourceLocf(format string, v ...interface{}) error {
26 return newErrorwithSourceLocfInternal(2, format, v...)
27}
28
29func wrapErrorwithSourceLocf(err error, format string, v ...interface{}) error {
30 return newErrorwithSourceLocfInternal(2, "%s: %s", fmt.Sprintf(format, v...), err.Error())
31}
32
Tobias Bosch9332d212019-07-10 06:23:57 -070033func wrapSubprocessErrorWithSourceLoc(cmd *command, subprocessErr error) (exitCode int, err error) {
34 if subprocessErr == nil {
35 return 0, nil
36 }
37 if userErr, ok := getCCacheError(cmd, subprocessErr); ok {
38 return 0, userErr
39 }
40 if exitCode, ok := getExitCode(subprocessErr); ok {
41 return exitCode, nil
42 }
43 err = newErrorwithSourceLocfInternal(2, "failed to execute %#v: %s", cmd, subprocessErr)
44 return 0, err
45}
46
Tobias Bosch900dbc92019-06-24 09:31:39 -070047// Based on the implementation of log.Output
48func newErrorwithSourceLocfInternal(skip int, format string, v ...interface{}) error {
49 _, file, line, ok := runtime.Caller(skip)
50 if !ok {
51 file = "???"
52 line = 0
53 }
54 if lastSlash := strings.LastIndex(file, "/"); lastSlash >= 0 {
55 file = file[lastSlash+1:]
56 }
57
58 return fmt.Errorf("%s:%d: %s", file, line, fmt.Sprintf(format, v...))
59}
60
61func getExitCode(err error) (exitCode int, ok bool) {
62 if err == nil {
63 return 0, true
64 }
65 if exiterr, ok := err.(*exec.ExitError); ok {
66 if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
67 return status.ExitStatus(), true
68 }
69 }
70 return 0, false
71}
Tobias Bosch9332d212019-07-10 06:23:57 -070072
73func getCCacheError(compilerCmd *command, compilerCmdErr error) (ccacheErr userError, ok bool) {
74 if en, ok := compilerCmdErr.(syscall.Errno); ok && en == syscall.ENOENT &&
Tobias Bosch22c32b42019-07-17 03:23:59 -070075 strings.Contains(compilerCmd.Path, "ccache") {
Tobias Bosch9332d212019-07-10 06:23:57 -070076 ccacheErr =
77 newUserErrorf("ccache not found under %s. Please install it",
Tobias Bosch22c32b42019-07-17 03:23:59 -070078 compilerCmd.Path)
Tobias Bosch9332d212019-07-10 06:23:57 -070079 return ccacheErr, true
80 }
81 return ccacheErr, false
82}