xref: /aosp_15_r20/external/toolchain-utils/compiler_wrapper/errors.go (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1*760c253cSXin Li// Copyright 2019 The ChromiumOS Authors
2*760c253cSXin Li// Use of this source code is governed by a BSD-style license that can be
3*760c253cSXin Li// found in the LICENSE file.
4*760c253cSXin Li
5*760c253cSXin Lipackage main
6*760c253cSXin Li
7*760c253cSXin Liimport (
8*760c253cSXin Li	"fmt"
9*760c253cSXin Li	"os/exec"
10*760c253cSXin Li	"runtime"
11*760c253cSXin Li	"strings"
12*760c253cSXin Li	"syscall"
13*760c253cSXin Li)
14*760c253cSXin Li
15*760c253cSXin Litype userError struct {
16*760c253cSXin Li	err string
17*760c253cSXin Li}
18*760c253cSXin Li
19*760c253cSXin Livar _ error = userError{}
20*760c253cSXin Li
21*760c253cSXin Lifunc (err userError) Error() string {
22*760c253cSXin Li	return err.err
23*760c253cSXin Li}
24*760c253cSXin Li
25*760c253cSXin Lifunc newUserErrorf(format string, v ...interface{}) userError {
26*760c253cSXin Li	return userError{err: fmt.Sprintf(format, v...)}
27*760c253cSXin Li}
28*760c253cSXin Li
29*760c253cSXin Lifunc newErrorwithSourceLocf(format string, v ...interface{}) error {
30*760c253cSXin Li	return newErrorwithSourceLocfInternal(2, format, v...)
31*760c253cSXin Li}
32*760c253cSXin Li
33*760c253cSXin Lifunc wrapErrorwithSourceLocf(err error, format string, v ...interface{}) error {
34*760c253cSXin Li	return newErrorwithSourceLocfInternal(2, "%s: %s", fmt.Sprintf(format, v...), err.Error())
35*760c253cSXin Li}
36*760c253cSXin Li
37*760c253cSXin Lifunc wrapSubprocessErrorWithSourceLoc(cmd *command, subprocessErr error) (exitCode int, err error) {
38*760c253cSXin Li	if subprocessErr == nil {
39*760c253cSXin Li		return 0, nil
40*760c253cSXin Li	}
41*760c253cSXin Li	if userErr, ok := getCCacheError(cmd, subprocessErr); ok {
42*760c253cSXin Li		return 0, userErr
43*760c253cSXin Li	}
44*760c253cSXin Li	if exitCode, ok := getExitCode(subprocessErr); ok {
45*760c253cSXin Li		return exitCode, nil
46*760c253cSXin Li	}
47*760c253cSXin Li	err = newErrorwithSourceLocfInternal(2, "failed to execute %#v: %s", cmd, subprocessErr)
48*760c253cSXin Li	return 0, err
49*760c253cSXin Li}
50*760c253cSXin Li
51*760c253cSXin Li// Based on the implementation of log.Output
52*760c253cSXin Lifunc newErrorwithSourceLocfInternal(skip int, format string, v ...interface{}) error {
53*760c253cSXin Li	_, file, line, ok := runtime.Caller(skip)
54*760c253cSXin Li	if !ok {
55*760c253cSXin Li		file = "???"
56*760c253cSXin Li		line = 0
57*760c253cSXin Li	}
58*760c253cSXin Li	if lastSlash := strings.LastIndex(file, "/"); lastSlash >= 0 {
59*760c253cSXin Li		file = file[lastSlash+1:]
60*760c253cSXin Li	}
61*760c253cSXin Li
62*760c253cSXin Li	return fmt.Errorf("%s:%d: %s", file, line, fmt.Sprintf(format, v...))
63*760c253cSXin Li}
64*760c253cSXin Li
65*760c253cSXin Lifunc getExitCode(err error) (exitCode int, ok bool) {
66*760c253cSXin Li	if err == nil {
67*760c253cSXin Li		return 0, true
68*760c253cSXin Li	}
69*760c253cSXin Li	if exiterr, ok := err.(*exec.ExitError); ok {
70*760c253cSXin Li		if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
71*760c253cSXin Li			return status.ExitStatus(), true
72*760c253cSXin Li		}
73*760c253cSXin Li	}
74*760c253cSXin Li	return 0, false
75*760c253cSXin Li}
76*760c253cSXin Li
77*760c253cSXin Lifunc getCCacheError(compilerCmd *command, compilerCmdErr error) (ccacheErr userError, ok bool) {
78*760c253cSXin Li	if en, ok := compilerCmdErr.(syscall.Errno); ok && en == syscall.ENOENT &&
79*760c253cSXin Li		strings.Contains(compilerCmd.Path, "ccache") {
80*760c253cSXin Li		ccacheErr =
81*760c253cSXin Li			newUserErrorf("ccache not found under %s. Please install it",
82*760c253cSXin Li				compilerCmd.Path)
83*760c253cSXin Li		return ccacheErr, true
84*760c253cSXin Li	}
85*760c253cSXin Li	return ccacheErr, false
86*760c253cSXin Li}
87