Catch panics in build logic
Catch panics in the build logic in order to provide extra data on when the panic occurred, for example which module had GenerateBuildActions called on it.
This commit is contained in:
parent
ea5995439c
commit
0aa6a5f0ad
4 changed files with 223 additions and 28 deletions
202
context.go
202
context.go
|
@ -157,6 +157,14 @@ type moduleInfo struct {
|
|||
actionDefs localBuildActions
|
||||
}
|
||||
|
||||
func (module *moduleInfo) String() string {
|
||||
s := fmt.Sprintf("module %q", module.properties.Name)
|
||||
if module.variantName != "" {
|
||||
s += fmt.Sprintf(" variant %q", module.variantName)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// A Variation is a way that a variant of a module differs from other variants of the same module.
|
||||
// For example, two variants of the same module might have Variation{"arch","arm"} and
|
||||
// Variation{"arch","arm64"}
|
||||
|
@ -1122,6 +1130,12 @@ func blueprintDepsMutator(ctx BottomUpMutatorContext) {
|
|||
ctx.AddDependency(ctx.Module(), ctx.moduleInfo().properties.Deps...)
|
||||
|
||||
if dynamicDepender, ok := ctx.Module().(DynamicDependerModule); ok {
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
ctx.error(newPanicErrorf(r, "DynamicDependencies for %s", ctx.moduleInfo()))
|
||||
}
|
||||
}()
|
||||
dynamicDeps := dynamicDepender.DynamicDependencies(ctx)
|
||||
|
||||
if ctx.Failed() {
|
||||
|
@ -1129,6 +1143,7 @@ func blueprintDepsMutator(ctx BottomUpMutatorContext) {
|
|||
}
|
||||
|
||||
ctx.AddDependency(ctx.Module(), dynamicDeps...)
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1516,7 +1531,20 @@ func (c *Context) runEarlyMutators(config interface{}) (errs []error) {
|
|||
},
|
||||
name: mutator.name,
|
||||
}
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
in := fmt.Sprintf("early mutator %q for %s", mutator.name, module)
|
||||
if err, ok := r.(panicError); ok {
|
||||
err.addIn(in)
|
||||
mctx.error(err)
|
||||
} else {
|
||||
mctx.error(newPanicErrorf(r, in))
|
||||
}
|
||||
}
|
||||
}()
|
||||
mutator.mutator(mctx)
|
||||
}()
|
||||
if len(mctx.errs) > 0 {
|
||||
errs = append(errs, mctx.errs...)
|
||||
return errs
|
||||
|
@ -1576,8 +1604,21 @@ func (c *Context) runTopDownMutator(config interface{},
|
|||
},
|
||||
name: name,
|
||||
}
|
||||
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
in := fmt.Sprintf("top down mutator %q for %s", name, module)
|
||||
if err, ok := r.(panicError); ok {
|
||||
err.addIn(in)
|
||||
mctx.error(err)
|
||||
} else {
|
||||
mctx.error(newPanicErrorf(r, in))
|
||||
}
|
||||
}
|
||||
}()
|
||||
mutator(mctx)
|
||||
}()
|
||||
|
||||
if len(mctx.errs) > 0 {
|
||||
errs = append(errs, mctx.errs...)
|
||||
return errs
|
||||
|
@ -1609,7 +1650,20 @@ func (c *Context) runBottomUpMutator(config interface{},
|
|||
reverseDeps: reverseDeps,
|
||||
}
|
||||
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
in := fmt.Sprintf("bottom up mutator %q for %s", name, module)
|
||||
if err, ok := r.(panicError); ok {
|
||||
err.addIn(in)
|
||||
mctx.error(err)
|
||||
} else {
|
||||
mctx.error(newPanicErrorf(r, in))
|
||||
}
|
||||
}
|
||||
}()
|
||||
mutator(mctx)
|
||||
}()
|
||||
if len(mctx.errs) > 0 {
|
||||
errs = append(errs, mctx.errs...)
|
||||
return errs
|
||||
|
@ -1726,7 +1780,20 @@ func (c *Context) generateModuleBuildActions(config interface{},
|
|||
handledMissingDeps: module.missingDeps == nil,
|
||||
}
|
||||
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
in := fmt.Sprintf("GenerateBuildActions for %s", module)
|
||||
if err, ok := r.(panicError); ok {
|
||||
err.addIn(in)
|
||||
mctx.error(err)
|
||||
} else {
|
||||
mctx.error(newPanicErrorf(r, in))
|
||||
}
|
||||
}
|
||||
}()
|
||||
mctx.module.logicModule.GenerateBuildActions(mctx)
|
||||
}()
|
||||
|
||||
if len(mctx.errs) > 0 {
|
||||
errsCh <- mctx.errs
|
||||
|
@ -1781,7 +1848,20 @@ func (c *Context) generateSingletonBuildActions(config interface{},
|
|||
scope: scope,
|
||||
}
|
||||
|
||||
func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
in := fmt.Sprintf("GenerateBuildActions for singleton %s", info.name)
|
||||
if err, ok := r.(panicError); ok {
|
||||
err.addIn(in)
|
||||
sctx.error(err)
|
||||
} else {
|
||||
sctx.error(newPanicErrorf(r, in))
|
||||
}
|
||||
}
|
||||
}()
|
||||
info.singleton.GenerateBuildActions(sctx)
|
||||
}()
|
||||
|
||||
if len(sctx.errs) > 0 {
|
||||
errs = append(errs, sctx.errs...)
|
||||
|
@ -1849,6 +1929,14 @@ func (c *Context) walkDeps(topModule *moduleInfo,
|
|||
visit func(Module, Module) bool) {
|
||||
|
||||
visited := make(map[*moduleInfo]bool)
|
||||
var visiting *moduleInfo
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
panic(newPanicErrorf(r, "WalkDeps(%s, %s) for dependency %s",
|
||||
topModule, funcName(visit), visiting))
|
||||
}
|
||||
}()
|
||||
|
||||
var walk func(module *moduleInfo)
|
||||
walk = func(module *moduleInfo) {
|
||||
|
@ -1856,6 +1944,7 @@ func (c *Context) walkDeps(topModule *moduleInfo,
|
|||
|
||||
for _, moduleDep := range module.directDeps {
|
||||
if !visited[moduleDep] {
|
||||
visiting = moduleDep
|
||||
if visit(moduleDep.logicModule, module.logicModule) {
|
||||
walk(moduleDep)
|
||||
}
|
||||
|
@ -1866,8 +1955,18 @@ func (c *Context) walkDeps(topModule *moduleInfo,
|
|||
walk(topModule)
|
||||
}
|
||||
|
||||
type innerPanicError error
|
||||
|
||||
func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module)) {
|
||||
visited := make(map[*moduleInfo]bool)
|
||||
var visiting *moduleInfo
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
panic(newPanicErrorf(r, "VisitDepsDepthFirst(%s, %s) for dependency %s",
|
||||
topModule, funcName(visit), visiting))
|
||||
}
|
||||
}()
|
||||
|
||||
var walk func(module *moduleInfo)
|
||||
walk = func(module *moduleInfo) {
|
||||
|
@ -1879,6 +1978,7 @@ func (c *Context) visitDepsDepthFirst(topModule *moduleInfo, visit func(Module))
|
|||
}
|
||||
|
||||
if module != topModule {
|
||||
visiting = module
|
||||
visit(module.logicModule)
|
||||
}
|
||||
}
|
||||
|
@ -1890,6 +1990,14 @@ func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module)
|
|||
visit func(Module)) {
|
||||
|
||||
visited := make(map[*moduleInfo]bool)
|
||||
var visiting *moduleInfo
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
panic(newPanicErrorf(r, "VisitDepsDepthFirstIf(%s, %s, %s) for dependency %s",
|
||||
topModule, funcName(pred), funcName(visit), visiting))
|
||||
}
|
||||
}()
|
||||
|
||||
var walk func(module *moduleInfo)
|
||||
walk = func(module *moduleInfo) {
|
||||
|
@ -1902,6 +2010,7 @@ func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module)
|
|||
|
||||
if module != topModule {
|
||||
if pred(module.logicModule) {
|
||||
visiting = module
|
||||
visit(module.logicModule)
|
||||
}
|
||||
}
|
||||
|
@ -1911,7 +2020,16 @@ func (c *Context) visitDepsDepthFirstIf(topModule *moduleInfo, pred func(Module)
|
|||
}
|
||||
|
||||
func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
|
||||
for _, dep := range module.directDeps {
|
||||
var dep *moduleInfo
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
panic(newPanicErrorf(r, "VisitDirectDeps(%s, %s) for dependency %s",
|
||||
module, funcName(visit), dep))
|
||||
}
|
||||
}()
|
||||
|
||||
for _, dep = range module.directDeps {
|
||||
visit(dep.logicModule)
|
||||
}
|
||||
}
|
||||
|
@ -1919,7 +2037,16 @@ func (c *Context) visitDirectDeps(module *moduleInfo, visit func(Module)) {
|
|||
func (c *Context) visitDirectDepsIf(module *moduleInfo, pred func(Module) bool,
|
||||
visit func(Module)) {
|
||||
|
||||
for _, dep := range module.directDeps {
|
||||
var dep *moduleInfo
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
panic(newPanicErrorf(r, "VisitDirectDepsIf(%s, %s, %s) for dependency %s",
|
||||
module, funcName(pred), funcName(visit), dep))
|
||||
}
|
||||
}()
|
||||
|
||||
for _, dep = range module.directDeps {
|
||||
if pred(dep.logicModule) {
|
||||
visit(dep.logicModule)
|
||||
}
|
||||
|
@ -1940,9 +2067,18 @@ func (c *Context) sortedModuleNames() []string {
|
|||
}
|
||||
|
||||
func (c *Context) visitAllModules(visit func(Module)) {
|
||||
var module *moduleInfo
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
panic(newPanicErrorf(r, "VisitAllModules(%s) for %s",
|
||||
funcName(visit), module))
|
||||
}
|
||||
}()
|
||||
|
||||
for _, moduleName := range c.sortedModuleNames() {
|
||||
group := c.moduleGroups[moduleName]
|
||||
for _, module := range group.modules {
|
||||
for _, module = range group.modules {
|
||||
visit(module.logicModule)
|
||||
}
|
||||
}
|
||||
|
@ -1951,6 +2087,15 @@ func (c *Context) visitAllModules(visit func(Module)) {
|
|||
func (c *Context) visitAllModulesIf(pred func(Module) bool,
|
||||
visit func(Module)) {
|
||||
|
||||
var module *moduleInfo
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
panic(newPanicErrorf(r, "VisitAllModulesIf(%s, %s) for %s",
|
||||
funcName(pred), funcName(visit), module))
|
||||
}
|
||||
}()
|
||||
|
||||
for _, moduleName := range c.sortedModuleNames() {
|
||||
group := c.moduleGroups[moduleName]
|
||||
for _, module := range group.modules {
|
||||
|
@ -1961,6 +2106,23 @@ func (c *Context) visitAllModulesIf(pred func(Module) bool,
|
|||
}
|
||||
}
|
||||
|
||||
func (c *Context) visitAllModuleVariants(module *moduleInfo,
|
||||
visit func(Module)) {
|
||||
|
||||
var variant *moduleInfo
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
panic(newPanicErrorf(r, "VisitAllModuleVariants(%s, %s) for %s",
|
||||
module, funcName(visit), variant))
|
||||
}
|
||||
}()
|
||||
|
||||
for _, variant = range module.group.modules {
|
||||
visit(variant.logicModule)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Context) requireNinjaVersion(major, minor, micro int) {
|
||||
if major != 1 {
|
||||
panic("ninja version with major version != 1 not supported")
|
||||
|
@ -2236,9 +2398,7 @@ func (c *Context) FinalModule(module Module) Module {
|
|||
func (c *Context) VisitAllModuleVariants(module Module,
|
||||
visit func(Module)) {
|
||||
|
||||
for _, module := range c.moduleInfo[module].group.modules {
|
||||
visit(module.logicModule)
|
||||
}
|
||||
c.visitAllModuleVariants(c.moduleInfo[module], visit)
|
||||
}
|
||||
|
||||
// WriteBuildFile writes the Ninja manifeset text for the generated build
|
||||
|
@ -2739,6 +2899,34 @@ func beforeInModuleList(a, b *moduleInfo, list []*moduleInfo) bool {
|
|||
panic(fmt.Errorf("element %v not found in list %v", missing, list))
|
||||
}
|
||||
|
||||
type panicError struct {
|
||||
panic interface{}
|
||||
stack []byte
|
||||
in string
|
||||
}
|
||||
|
||||
func newPanicErrorf(panic interface{}, in string, a ...interface{}) error {
|
||||
buf := make([]byte, 4096)
|
||||
count := runtime.Stack(buf, false)
|
||||
return panicError{
|
||||
panic: panic,
|
||||
in: fmt.Sprintf(in, a...),
|
||||
stack: buf[:count],
|
||||
}
|
||||
}
|
||||
|
||||
func (p panicError) Error() string {
|
||||
return fmt.Sprintf("panic in %s\n%s\n%s\n", p.in, p.panic, p.stack)
|
||||
}
|
||||
|
||||
func (p *panicError) addIn(in string) {
|
||||
p.in += " in " + in
|
||||
}
|
||||
|
||||
func funcName(f interface{}) string {
|
||||
return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
|
||||
}
|
||||
|
||||
var fileHeaderTemplate = `******************************************************************************
|
||||
*** This file is generated and should not be edited ***
|
||||
******************************************************************************
|
||||
|
|
|
@ -119,6 +119,7 @@ type BaseModuleContext interface {
|
|||
Failed() bool
|
||||
|
||||
moduleInfo() *moduleInfo
|
||||
error(err error)
|
||||
}
|
||||
|
||||
type DynamicDependerModuleContext BottomUpMutatorContext
|
||||
|
@ -180,10 +181,16 @@ func (d *baseModuleContext) Config() interface{} {
|
|||
return d.config
|
||||
}
|
||||
|
||||
func (d *baseModuleContext) error(err error) {
|
||||
if err != nil {
|
||||
d.errs = append(d.errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *baseModuleContext) Errorf(pos scanner.Position,
|
||||
format string, args ...interface{}) {
|
||||
|
||||
d.errs = append(d.errs, &Error{
|
||||
d.error(&Error{
|
||||
Err: fmt.Errorf(format, args...),
|
||||
Pos: pos,
|
||||
})
|
||||
|
@ -192,7 +199,7 @@ func (d *baseModuleContext) Errorf(pos scanner.Position,
|
|||
func (d *baseModuleContext) ModuleErrorf(format string,
|
||||
args ...interface{}) {
|
||||
|
||||
d.errs = append(d.errs, &Error{
|
||||
d.error(&Error{
|
||||
Err: fmt.Errorf(format, args...),
|
||||
Pos: d.module.pos,
|
||||
})
|
||||
|
@ -209,7 +216,7 @@ func (d *baseModuleContext) PropertyErrorf(property, format string,
|
|||
|
||||
format = property + ": " + format
|
||||
|
||||
d.errs = append(d.errs, &Error{
|
||||
d.error(&Error{
|
||||
Err: fmt.Errorf(format, args...),
|
||||
Pos: pos,
|
||||
})
|
||||
|
@ -320,9 +327,7 @@ func (m *moduleContext) FinalModule() Module {
|
|||
}
|
||||
|
||||
func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
|
||||
for _, module := range m.module.group.modules {
|
||||
visit(module.logicModule)
|
||||
}
|
||||
m.context.visitAllModuleVariants(m.module, visit)
|
||||
}
|
||||
|
||||
func (m *moduleContext) GetMissingDependencies() []string {
|
||||
|
|
|
@ -91,15 +91,21 @@ func (s *singletonContext) BlueprintFile(logicModule Module) string {
|
|||
return s.context.BlueprintFile(logicModule)
|
||||
}
|
||||
|
||||
func (s *singletonContext) error(err error) {
|
||||
if err != nil {
|
||||
s.errs = append(s.errs, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *singletonContext) ModuleErrorf(logicModule Module, format string,
|
||||
args ...interface{}) {
|
||||
|
||||
s.errs = append(s.errs, s.context.ModuleErrorf(logicModule, format, args...))
|
||||
s.error(s.context.ModuleErrorf(logicModule, format, args...))
|
||||
}
|
||||
|
||||
func (s *singletonContext) Errorf(format string, args ...interface{}) {
|
||||
// TODO: Make this not result in the error being printed as "internal error"
|
||||
s.errs = append(s.errs, fmt.Errorf(format, args...))
|
||||
s.error(fmt.Errorf(format, args...))
|
||||
}
|
||||
|
||||
func (s *singletonContext) Failed() bool {
|
||||
|
|
|
@ -28,10 +28,6 @@ var (
|
|||
testModuleF = &moduleInfo{variantName: "testModuleF"}
|
||||
)
|
||||
|
||||
func (m *moduleInfo) String() string {
|
||||
return m.variantName
|
||||
}
|
||||
|
||||
var spliceModulesTestCases = []struct {
|
||||
in []*moduleInfo
|
||||
replace *moduleInfo
|
||||
|
|
Loading…
Reference in a new issue