go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/lucicfg/errors.go (about) 1 // Copyright 2018 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package lucicfg 16 17 import ( 18 "go.starlark.net/starlark" 19 20 "go.chromium.org/luci/lucicfg/graph" 21 "go.chromium.org/luci/starlark/builtins" 22 ) 23 24 // BacktracableError is an error that has a starlark backtrace attached to it. 25 // 26 // Implemented by Error here, by starlark.EvalError and graph errors. 27 type BacktracableError interface { 28 error 29 30 // Backtrace returns a user-friendly error message describing the stack 31 // of calls that led to this error, along with the error message itself. 32 Backtrace() string 33 } 34 35 var ( 36 _ BacktracableError = (*starlark.EvalError)(nil) 37 _ BacktracableError = (*builtins.Failure)(nil) 38 _ BacktracableError = (*Error)(nil) 39 _ BacktracableError = (*graph.NodeRedeclarationError)(nil) 40 _ BacktracableError = (*graph.CycleError)(nil) 41 _ BacktracableError = (*graph.DanglingEdgeError)(nil) 42 ) 43 44 // Error is a single error message emitted by the config generator. 45 // 46 // It holds a stack trace responsible for the error. 47 type Error struct { 48 Msg string 49 Stack *builtins.CapturedStacktrace 50 } 51 52 // Error is part of 'error' interface. 53 func (e *Error) Error() string { 54 return e.Msg 55 } 56 57 // Backtrace is part of BacktracableError interface. 58 func (e *Error) Backtrace() string { 59 if e.Stack == nil { 60 return e.Msg 61 } 62 return e.Stack.String() + "Error: " + e.Msg 63 } 64 65 func init() { 66 // emit_error(msg, stack) adds the given error to the list of errors in the 67 // state, to be returned at the end of generation (in the default mode), or 68 // immediately aborts the execution if 'fail_on_errors' has been called 69 // before. 70 declNative("emit_error", func(call nativeCall) (starlark.Value, error) { 71 var msg starlark.String 72 var stack *builtins.CapturedStacktrace 73 if err := call.unpack(2, &msg, &stack); err != nil { 74 return nil, err 75 } 76 err := &Error{ 77 Msg: msg.GoString(), 78 Stack: stack, 79 } 80 if call.State.failOnErrs { 81 return nil, err 82 } 83 call.State.err(err) 84 return starlark.None, nil 85 }) 86 87 // fail_on_errors() enables a mode in which emit_error(...) immediately aborts 88 // the execution instead of just recording the error. This is useful in 89 // tests to check what errors are emitted (using assert.fails). A call to 90 // clear_state() resets this mode. 91 declNative("fail_on_errors", func(call nativeCall) (starlark.Value, error) { 92 if err := call.unpack(0); err != nil { 93 return nil, err 94 } 95 call.State.failOnErrs = true 96 return starlark.None, nil 97 }) 98 }