blob: 18e0facffe827c2abcc704abee0d92a2c4200111 [file] [log] [blame]
Tobias Boschcfa8c242019-07-19 03:29:40 -07001// Copyright 2019 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Tobias Bosch900dbc92019-06-24 09:31:39 -07005package main
6
7import (
8 "fmt"
9 "os/exec"
10 "runtime"
11 "strings"
12 "syscall"
13)
14
15type userError struct {
16 err string
17}
18
19var _ error = userError{}
20
21func (err userError) Error() string {
22 return err.err
23}
24
25func newUserErrorf(format string, v ...interface{}) userError {
26 return userError{err: fmt.Sprintf(format, v...)}
27}
28
29func newErrorwithSourceLocf(format string, v ...interface{}) error {
30 return newErrorwithSourceLocfInternal(2, format, v...)
31}
32
33func wrapErrorwithSourceLocf(err error, format string, v ...interface{}) error {
34 return newErrorwithSourceLocfInternal(2, "%s: %s", fmt.Sprintf(format, v...), err.Error())
35}
36
Tobias Bosch9332d212019-07-10 06:23:57 -070037func wrapSubprocessErrorWithSourceLoc(cmd *command, subprocessErr error) (exitCode int, err error) {
38 if subprocessErr == nil {
39 return 0, nil
40 }
41 if userErr, ok := getCCacheError(cmd, subprocessErr); ok {
42 return 0, userErr
43 }
44 if exitCode, ok := getExitCode(subprocessErr); ok {
45 return exitCode, nil
46 }
47 err = newErrorwithSourceLocfInternal(2, "failed to execute %#v: %s", cmd, subprocessErr)
48 return 0, err
49}
50
Tobias Bosch900dbc92019-06-24 09:31:39 -070051// Based on the implementation of log.Output
52func newErrorwithSourceLocfInternal(skip int, format string, v ...interface{}) error {
53 _, file, line, ok := runtime.Caller(skip)
54 if !ok {
55 file = "???"
56 line = 0
57 }
58 if lastSlash := strings.LastIndex(file, "/"); lastSlash >= 0 {
59 file = file[lastSlash+1:]
60 }
61
62 return fmt.Errorf("%s:%d: %s", file, line, fmt.Sprintf(format, v...))
63}
64
65func getExitCode(err error) (exitCode int, ok bool) {
66 if err == nil {
67 return 0, true
68 }
69 if exiterr, ok := err.(*exec.ExitError); ok {
70 if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
71 return status.ExitStatus(), true
72 }
73 }
74 return 0, false
75}
Tobias Bosch9332d212019-07-10 06:23:57 -070076
77func getCCacheError(compilerCmd *command, compilerCmdErr error) (ccacheErr userError, ok bool) {
78 if en, ok := compilerCmdErr.(syscall.Errno); ok && en == syscall.ENOENT &&
Tobias Bosch22c32b42019-07-17 03:23:59 -070079 strings.Contains(compilerCmd.Path, "ccache") {
Tobias Bosch9332d212019-07-10 06:23:57 -070080 ccacheErr =
81 newUserErrorf("ccache not found under %s. Please install it",
Tobias Bosch22c32b42019-07-17 03:23:59 -070082 compilerCmd.Path)
Tobias Bosch9332d212019-07-10 06:23:57 -070083 return ccacheErr, true
84 }
85 return ccacheErr, false
86}