From 1d2d42f8e929b9aa4af90f4f70be516f1f734c1b Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Sat, 6 Mar 2021 20:08:12 +0000 Subject: [PATCH] Add sortableComponent abstraction In preparation for following changes that will ensure the order of registration (and so execution) for mutators, singletons and pre-singletons in tests match the order in runtime this change creates the sortableComponent interface to allow those to be sorted in the same way without having to resort to reflection. By moving the registration code into each component type this change also eliminates some unnecessary duplication of that code. Bug: 181953909 Test: m nothing Change-Id: I597b461b966c84faaeb13e7dff765f1fadd99981 --- android/mutator.go | 41 ++++++++++++---------- android/register.go | 85 +++++++++++++++++++++++++++++++++++++-------- android/testing.go | 4 +-- 3 files changed, 94 insertions(+), 36 deletions(-) diff --git a/android/mutator.go b/android/mutator.go index b0230011d..8bfb24ed3 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -33,22 +33,8 @@ import ( // run FinalDeps mutators (CreateVariations disallowed in this phase) // continue on to GenerateAndroidBuildActions -func registerMutatorsToContext(ctx *blueprint.Context, mutators []*mutator) { - for _, t := range mutators { - var handle blueprint.MutatorHandle - if t.bottomUpMutator != nil { - handle = ctx.RegisterBottomUpMutator(t.name, t.bottomUpMutator) - } else if t.topDownMutator != nil { - handle = ctx.RegisterTopDownMutator(t.name, t.topDownMutator) - } - if t.parallel { - handle.Parallel() - } - } -} - // RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing. -func RegisterMutatorsForBazelConversion(ctx *blueprint.Context, preArchMutators, depsMutators, bp2buildMutators []RegisterMutatorFunc) { +func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators, depsMutators, bp2buildMutators []RegisterMutatorFunc) { mctx := ®isterMutatorsContext{ bazelConversionMode: true, } @@ -80,10 +66,10 @@ func RegisterMutatorsForBazelConversion(ctx *blueprint.Context, preArchMutators, f(mctx) } - registerMutatorsToContext(ctx, mctx.mutators) + mctx.mutators.registerAll(ctx) } -func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) { +func registerMutators(ctx *Context, preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) { mctx := ®isterMutatorsContext{} register := func(funcs []RegisterMutatorFunc) { @@ -103,11 +89,11 @@ func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps, finalD mctx.finalPhase = true register(finalDeps) - registerMutatorsToContext(ctx, mctx.mutators) + mctx.mutators.registerAll(ctx) } type registerMutatorsContext struct { - mutators []*mutator + mutators sortableComponents finalPhase bool bazelConversionMode bool } @@ -473,6 +459,23 @@ func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) Mutator return mutator } +func (mutator *mutator) componentName() string { + return mutator.name +} + +func (mutator *mutator) register(ctx *Context) { + blueprintCtx := ctx.Context + var handle blueprint.MutatorHandle + if mutator.bottomUpMutator != nil { + handle = blueprintCtx.RegisterBottomUpMutator(mutator.name, mutator.bottomUpMutator) + } else if mutator.topDownMutator != nil { + handle = blueprintCtx.RegisterTopDownMutator(mutator.name, mutator.topDownMutator) + } + if mutator.parallel { + handle.Parallel() + } +} + type MutatorHandle interface { Parallel() MutatorHandle } diff --git a/android/register.go b/android/register.go index 47df9729e..5efa280cc 100644 --- a/android/register.go +++ b/android/register.go @@ -21,21 +21,78 @@ import ( "github.com/google/blueprint" ) +// A sortable component is one whose registration order affects the order in which it is executed +// and so affects the behavior of the build system. As a result it is important for the order in +// which they are registered during tests to match the order used at runtime and so the test +// infrastructure will sort them to match. +// +// The sortable components are mutators, singletons and pre-singletons. Module types are not +// sortable because their order of registration does not affect the runtime behavior. +type sortableComponent interface { + // componentName returns the name of the component. + // + // Uniquely identifies the components within the set of components used at runtimr and during + // tests. + componentName() string + + // register registers this component in the supplied context. + register(ctx *Context) +} + +type sortableComponents []sortableComponent + +// registerAll registers all components in this slice with the supplied context. +func (r sortableComponents) registerAll(ctx *Context) { + for _, c := range r { + c.register(ctx) + } +} + type moduleType struct { name string factory ModuleFactory } +func (t moduleType) register(ctx *Context) { + ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory)) +} + var moduleTypes []moduleType var moduleTypesForDocs = map[string]reflect.Value{} type singleton struct { + // True if this should be registered as a pre-singleton, false otherwise. + pre bool + name string factory SingletonFactory } -var singletons []singleton -var preSingletons []singleton +func newSingleton(name string, factory SingletonFactory) singleton { + return singleton{false, name, factory} +} + +func newPreSingleton(name string, factory SingletonFactory) singleton { + return singleton{true, name, factory} +} + +func (s singleton) componentName() string { + return s.name +} + +func (s singleton) register(ctx *Context) { + adaptor := SingletonFactoryAdaptor(ctx, s.factory) + if s.pre { + ctx.RegisterPreSingletonType(s.name, adaptor) + } else { + ctx.RegisterSingletonType(s.name, adaptor) + } +} + +var _ sortableComponent = singleton{} + +var singletons sortableComponents +var preSingletons sortableComponents type mutator struct { name string @@ -44,6 +101,8 @@ type mutator struct { parallel bool } +var _ sortableComponent = &mutator{} + type ModuleFactory func() Module // ModuleFactoryAdaptor wraps a ModuleFactory into a blueprint.ModuleFactory by converting a Module @@ -84,11 +143,11 @@ func RegisterModuleTypeForDocs(name string, factory reflect.Value) { } func RegisterSingletonType(name string, factory SingletonFactory) { - singletons = append(singletons, singleton{name, factory}) + singletons = append(singletons, newSingleton(name, factory)) } func RegisterPreSingletonType(name string, factory SingletonFactory) { - preSingletons = append(preSingletons, singleton{name, factory}) + preSingletons = append(preSingletons, newPreSingleton(name, factory)) } type Context struct { @@ -107,33 +166,29 @@ func NewContext(config Config) *Context { // files to semantically equivalent BUILD files. func (ctx *Context) RegisterForBazelConversion() { for _, t := range moduleTypes { - ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory)) + t.register(ctx) } // Required for SingletonModule types, even though we are not using them. for _, t := range singletons { - ctx.RegisterSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory)) + t.register(ctx) } - RegisterMutatorsForBazelConversion(ctx.Context, bp2buildPreArchMutators, bp2buildDepsMutators, bp2buildMutators) + RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators, bp2buildDepsMutators, bp2buildMutators) } // Register the pipeline of singletons, module types, and mutators for // generating build.ninja and other files for Kati, from Android.bp files. func (ctx *Context) Register() { - for _, t := range preSingletons { - ctx.RegisterPreSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory)) - } + preSingletons.registerAll(ctx) for _, t := range moduleTypes { - ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory)) + t.register(ctx) } - for _, t := range singletons { - ctx.RegisterSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory)) - } + singletons.registerAll(ctx) - registerMutators(ctx.Context, preArch, preDeps, postDeps, finalDeps) + registerMutators(ctx, preArch, preDeps, postDeps, finalDeps) ctx.RegisterSingletonType("bazeldeps", SingletonFactoryAdaptor(ctx, BazelSingleton)) diff --git a/android/testing.go b/android/testing.go index d8c123bba..556db7863 100644 --- a/android/testing.go +++ b/android/testing.go @@ -141,14 +141,14 @@ func (ctx *TestContext) DepsBp2BuildMutators(f RegisterMutatorFunc) { } func (ctx *TestContext) Register() { - registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps) + registerMutators(ctx.Context, ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps) ctx.RegisterSingletonType("env", EnvSingleton) } // RegisterForBazelConversion prepares a test context for bp2build conversion. func (ctx *TestContext) RegisterForBazelConversion() { - RegisterMutatorsForBazelConversion(ctx.Context.Context, ctx.bp2buildPreArch, ctx.bp2buildDeps, ctx.bp2buildMutators) + RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch, ctx.bp2buildDeps, ctx.bp2buildMutators) } func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {