// Copyright © 2018 Intel Corporation // // SPDX-License-Identifier: GPL-3.0-only package errors import ( "fmt" "path/filepath" "runtime" "strings" "time" ) // TraceableError is an internal error used to carry trace details // to be shared across the multiple layers and reporting facilities type TraceableError struct { Trace string When time.Time What string } // ValidationError is a type of error used to report model or any general condition // validation error. We don't deal this error as a regular error i.e panic`ing, showing // the error stack trace and exiting with a non zero code, otherwise, we do show // a nicely formatted and user friendly error message (the What attribute) and keep // returning a non zero exit code. // Consider this error as a user error, not an internal malfunctioning. type ValidationError struct { When time.Time What string } func getTraceIdx(idx int) (string, string, int) { pc := make([]uintptr, 10) runtime.Callers(2, pc) f := runtime.FuncForPC(pc[idx+1]) file, line := f.FileLine(pc[idx+1]) return f.Name(), file, line } func formatTraceIdx(idx int) (string, string) { funcName, file, line := getTraceIdx(idx) fileName := filepath.Base(file) fn := strings.Split(funcName, "github.com/clearlinux/clr-installer/") if len(fn) > 1 { funcName = fn[1] } else { funcName = fn[0] } dir := filepath.Dir(file) return funcName, fmt.Sprintf("%s/%s:%d", dir, fileName, line) } func getTrace() string { cfName, cTrace := formatTraceIdx(3) caller := fmt.Sprintf("%s()\n %s\n", cfName, cTrace) rfName, rTrace := formatTraceIdx(2) raiser := fmt.Sprintf("%s()\n %s\n", rfName, rTrace) return fmt.Sprintf("\n\nError Trace:\n%s%s", raiser, caller) } func (e TraceableError) Error() string { return fmt.Sprintf("%s%s", e.What, e.Trace) } // Errorf Returns a new error with the stack information func Errorf(format string, a ...interface{}) error { return TraceableError{ Trace: getTrace(), When: time.Now(), What: fmt.Sprintf(format, a...), } } // Wrap returns an error with the caller stack information // embedded in the original error message func Wrap(err error) error { return Errorf(err.Error()) } func (ve ValidationError) Error() string { return ve.What } // ValidationErrorf formats a new ValidationError func ValidationErrorf(format string, a ...interface{}) error { return ValidationError{ What: fmt.Sprintf(format, a...), } } // IsValidationError returns true if err is a ValidationError // returns false otherwise func IsValidationError(err error) bool { if _, ok := err.(ValidationError); ok { return true } return false }