Introduce infrastructure for calling and testing nested
commands, error messages and exit codes.
Also:
- implements the -Xclang-path= flag as use case of calling
a nested command.
- adds tests for forwarding errors, comparing against the
old wrapper, and exit codes.
- captures the source locations of errors in error messages.
- compares exit codes of new wrapper and old wrapper.
BUG=chromium:773875
TEST=unit test
Change-Id: I919e58091d093d68939809f676f799a68ec7a34e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/1676833
Reviewed-by: George Burgess <gbiv@chromium.org>
Tested-by: Tobias Bosch <tbosch@google.com>
diff --git a/compiler_wrapper/errors.go b/compiler_wrapper/errors.go
new file mode 100644
index 0000000..525b986
--- /dev/null
+++ b/compiler_wrapper/errors.go
@@ -0,0 +1,57 @@
+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())
+}
+
+// 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
+}