1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2024 Google Inc. All rights reserved. 2*1fa6dee9SAndroid Build Coastguard Worker// 3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*1fa6dee9SAndroid Build Coastguard Worker// 7*1fa6dee9SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*1fa6dee9SAndroid Build Coastguard Worker// 9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License. 14*1fa6dee9SAndroid Build Coastguard Worker 15*1fa6dee9SAndroid Build Coastguard Workerpackage blueprint 16*1fa6dee9SAndroid Build Coastguard Worker 17*1fa6dee9SAndroid Build Coastguard Workerimport ( 18*1fa6dee9SAndroid Build Coastguard Worker "fmt" 19*1fa6dee9SAndroid Build Coastguard Worker "slices" 20*1fa6dee9SAndroid Build Coastguard Worker "sort" 21*1fa6dee9SAndroid Build Coastguard Worker) 22*1fa6dee9SAndroid Build Coastguard Worker 23*1fa6dee9SAndroid Build Coastguard Worker// TransitionMutator implements a top-down mechanism where a module tells its 24*1fa6dee9SAndroid Build Coastguard Worker// direct dependencies what variation they should be built in but the dependency 25*1fa6dee9SAndroid Build Coastguard Worker// has the final say. 26*1fa6dee9SAndroid Build Coastguard Worker// 27*1fa6dee9SAndroid Build Coastguard Worker// When implementing a transition mutator, one needs to implement four methods: 28*1fa6dee9SAndroid Build Coastguard Worker// - Split() that tells what variations a module has by itself 29*1fa6dee9SAndroid Build Coastguard Worker// - OutgoingTransition() where a module tells what it wants from its 30*1fa6dee9SAndroid Build Coastguard Worker// dependency 31*1fa6dee9SAndroid Build Coastguard Worker// - IncomingTransition() where a module has the final say about its own 32*1fa6dee9SAndroid Build Coastguard Worker// variation 33*1fa6dee9SAndroid Build Coastguard Worker// - Mutate() that changes the state of a module depending on its variation 34*1fa6dee9SAndroid Build Coastguard Worker// 35*1fa6dee9SAndroid Build Coastguard Worker// That the effective variation of module B when depended on by module A is the 36*1fa6dee9SAndroid Build Coastguard Worker// composition the outgoing transition of module A and the incoming transition 37*1fa6dee9SAndroid Build Coastguard Worker// of module B. 38*1fa6dee9SAndroid Build Coastguard Worker// 39*1fa6dee9SAndroid Build Coastguard Worker// The outgoing transition should not take the properties of the dependency into 40*1fa6dee9SAndroid Build Coastguard Worker// account, only those of the module that depends on it. For this reason, the 41*1fa6dee9SAndroid Build Coastguard Worker// dependency is not even passed into it as an argument. Likewise, the incoming 42*1fa6dee9SAndroid Build Coastguard Worker// transition should not take the properties of the depending module into 43*1fa6dee9SAndroid Build Coastguard Worker// account and is thus not informed about it. This makes for a nice 44*1fa6dee9SAndroid Build Coastguard Worker// decomposition of the decision logic. 45*1fa6dee9SAndroid Build Coastguard Worker// 46*1fa6dee9SAndroid Build Coastguard Worker// A given transition mutator only affects its own variation; other variations 47*1fa6dee9SAndroid Build Coastguard Worker// stay unchanged along the dependency edges. 48*1fa6dee9SAndroid Build Coastguard Worker// 49*1fa6dee9SAndroid Build Coastguard Worker// Soong makes sure that all modules are created in the desired variations and 50*1fa6dee9SAndroid Build Coastguard Worker// that dependency edges are set up correctly. This ensures that "missing 51*1fa6dee9SAndroid Build Coastguard Worker// variation" errors do not happen and allows for more flexible changes in the 52*1fa6dee9SAndroid Build Coastguard Worker// value of the variation among dependency edges (as opposed to bottom-up 53*1fa6dee9SAndroid Build Coastguard Worker// mutators where if module A in variation X depends on module B and module B 54*1fa6dee9SAndroid Build Coastguard Worker// has that variation X, A must depend on variation X of B) 55*1fa6dee9SAndroid Build Coastguard Worker// 56*1fa6dee9SAndroid Build Coastguard Worker// The limited power of the context objects passed to individual mutators 57*1fa6dee9SAndroid Build Coastguard Worker// methods also makes it more difficult to shoot oneself in the foot. Complete 58*1fa6dee9SAndroid Build Coastguard Worker// safety is not guaranteed because no one prevents individual transition 59*1fa6dee9SAndroid Build Coastguard Worker// mutators from mutating modules in illegal ways and for e.g. Split() or 60*1fa6dee9SAndroid Build Coastguard Worker// Mutate() to run their own visitations of the transitive dependency of the 61*1fa6dee9SAndroid Build Coastguard Worker// module and both of these are bad ideas, but it's better than no guardrails at 62*1fa6dee9SAndroid Build Coastguard Worker// all. 63*1fa6dee9SAndroid Build Coastguard Worker// 64*1fa6dee9SAndroid Build Coastguard Worker// This model is pretty close to Bazel's configuration transitions. The mapping 65*1fa6dee9SAndroid Build Coastguard Worker// between concepts in Soong and Bazel is as follows: 66*1fa6dee9SAndroid Build Coastguard Worker// - Module == configured target 67*1fa6dee9SAndroid Build Coastguard Worker// - Variant == configuration 68*1fa6dee9SAndroid Build Coastguard Worker// - Variation name == configuration flag 69*1fa6dee9SAndroid Build Coastguard Worker// - Variation == configuration flag value 70*1fa6dee9SAndroid Build Coastguard Worker// - Outgoing transition == attribute transition 71*1fa6dee9SAndroid Build Coastguard Worker// - Incoming transition == rule transition 72*1fa6dee9SAndroid Build Coastguard Worker// 73*1fa6dee9SAndroid Build Coastguard Worker// The Split() method does not have a Bazel equivalent and Bazel split 74*1fa6dee9SAndroid Build Coastguard Worker// transitions do not have a Soong equivalent. 75*1fa6dee9SAndroid Build Coastguard Worker// 76*1fa6dee9SAndroid Build Coastguard Worker// Mutate() does not make sense in Bazel due to the different models of the 77*1fa6dee9SAndroid Build Coastguard Worker// two systems: when creating new variations, Soong clones the old module and 78*1fa6dee9SAndroid Build Coastguard Worker// thus some way is needed to change it state whereas Bazel creates each 79*1fa6dee9SAndroid Build Coastguard Worker// configuration of a given configured target anew. 80*1fa6dee9SAndroid Build Coastguard Workertype TransitionMutator interface { 81*1fa6dee9SAndroid Build Coastguard Worker // Split returns the set of variations that should be created for a module no matter 82*1fa6dee9SAndroid Build Coastguard Worker // who depends on it. Used when Make depends on a particular variation or when 83*1fa6dee9SAndroid Build Coastguard Worker // the module knows its variations just based on information given to it in 84*1fa6dee9SAndroid Build Coastguard Worker // the Blueprint file. This method should not mutate the module it is called 85*1fa6dee9SAndroid Build Coastguard Worker // on. 86*1fa6dee9SAndroid Build Coastguard Worker Split(ctx BaseModuleContext) []string 87*1fa6dee9SAndroid Build Coastguard Worker 88*1fa6dee9SAndroid Build Coastguard Worker // OutgoingTransition is called on a module to determine which variation it wants 89*1fa6dee9SAndroid Build Coastguard Worker // from its direct dependencies. The dependency itself can override this decision. 90*1fa6dee9SAndroid Build Coastguard Worker // This method should not mutate the module itself. 91*1fa6dee9SAndroid Build Coastguard Worker OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string 92*1fa6dee9SAndroid Build Coastguard Worker 93*1fa6dee9SAndroid Build Coastguard Worker // IncomingTransition is called on a module to determine which variation it should 94*1fa6dee9SAndroid Build Coastguard Worker // be in based on the variation modules that depend on it want. This gives the module 95*1fa6dee9SAndroid Build Coastguard Worker // a final say about its own variations. This method should not mutate the module 96*1fa6dee9SAndroid Build Coastguard Worker // itself. 97*1fa6dee9SAndroid Build Coastguard Worker IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string 98*1fa6dee9SAndroid Build Coastguard Worker 99*1fa6dee9SAndroid Build Coastguard Worker // Mutate is called after a module was split into multiple variations on each 100*1fa6dee9SAndroid Build Coastguard Worker // variation. It should not split the module any further but adding new dependencies 101*1fa6dee9SAndroid Build Coastguard Worker // is fine. Unlike all the other methods on TransitionMutator, this method is 102*1fa6dee9SAndroid Build Coastguard Worker // allowed to mutate the module. 103*1fa6dee9SAndroid Build Coastguard Worker Mutate(ctx BottomUpMutatorContext, variation string) 104*1fa6dee9SAndroid Build Coastguard Worker} 105*1fa6dee9SAndroid Build Coastguard Worker 106*1fa6dee9SAndroid Build Coastguard Workertype IncomingTransitionContext interface { 107*1fa6dee9SAndroid Build Coastguard Worker // Module returns the target of the dependency edge for which the transition 108*1fa6dee9SAndroid Build Coastguard Worker // is being computed 109*1fa6dee9SAndroid Build Coastguard Worker Module() Module 110*1fa6dee9SAndroid Build Coastguard Worker 111*1fa6dee9SAndroid Build Coastguard Worker // Config returns the config object that was passed to 112*1fa6dee9SAndroid Build Coastguard Worker // Context.PrepareBuildActions. 113*1fa6dee9SAndroid Build Coastguard Worker Config() interface{} 114*1fa6dee9SAndroid Build Coastguard Worker 115*1fa6dee9SAndroid Build Coastguard Worker // Provider returns the value for a provider for the target of the dependency edge for which the 116*1fa6dee9SAndroid Build Coastguard Worker // transition is being computed. If the value is not set it returns nil and false. It panics if 117*1fa6dee9SAndroid Build Coastguard Worker // called before the appropriate mutator or GenerateBuildActions pass for the provider. The value 118*1fa6dee9SAndroid Build Coastguard Worker // returned may be a deep copy of the value originally passed to SetProvider. 119*1fa6dee9SAndroid Build Coastguard Worker // 120*1fa6dee9SAndroid Build Coastguard Worker // This method shouldn't be used directly, prefer the type-safe android.ModuleProvider instead. 121*1fa6dee9SAndroid Build Coastguard Worker Provider(provider AnyProviderKey) (any, bool) 122*1fa6dee9SAndroid Build Coastguard Worker 123*1fa6dee9SAndroid Build Coastguard Worker // IsAddingDependency returns true if the transition is being called while adding a dependency 124*1fa6dee9SAndroid Build Coastguard Worker // after the transition mutator has already run, or false if it is being called when the transition 125*1fa6dee9SAndroid Build Coastguard Worker // mutator is running. This should be used sparingly, all uses will have to be removed in order 126*1fa6dee9SAndroid Build Coastguard Worker // to support creating variants on demand. 127*1fa6dee9SAndroid Build Coastguard Worker IsAddingDependency() bool 128*1fa6dee9SAndroid Build Coastguard Worker 129*1fa6dee9SAndroid Build Coastguard Worker // ModuleErrorf reports an error at the line number of the module type in the module definition. 130*1fa6dee9SAndroid Build Coastguard Worker ModuleErrorf(fmt string, args ...interface{}) 131*1fa6dee9SAndroid Build Coastguard Worker 132*1fa6dee9SAndroid Build Coastguard Worker // PropertyErrorf reports an error at the line number of a property in the module definition. 133*1fa6dee9SAndroid Build Coastguard Worker PropertyErrorf(property, fmt string, args ...interface{}) 134*1fa6dee9SAndroid Build Coastguard Worker} 135*1fa6dee9SAndroid Build Coastguard Worker 136*1fa6dee9SAndroid Build Coastguard Workertype OutgoingTransitionContext interface { 137*1fa6dee9SAndroid Build Coastguard Worker // Module returns the source of the dependency edge for which the transition 138*1fa6dee9SAndroid Build Coastguard Worker // is being computed 139*1fa6dee9SAndroid Build Coastguard Worker Module() Module 140*1fa6dee9SAndroid Build Coastguard Worker 141*1fa6dee9SAndroid Build Coastguard Worker // DepTag() Returns the dependency tag through which this dependency is 142*1fa6dee9SAndroid Build Coastguard Worker // reached 143*1fa6dee9SAndroid Build Coastguard Worker DepTag() DependencyTag 144*1fa6dee9SAndroid Build Coastguard Worker 145*1fa6dee9SAndroid Build Coastguard Worker // Config returns the config object that was passed to 146*1fa6dee9SAndroid Build Coastguard Worker // Context.PrepareBuildActions. 147*1fa6dee9SAndroid Build Coastguard Worker Config() interface{} 148*1fa6dee9SAndroid Build Coastguard Worker 149*1fa6dee9SAndroid Build Coastguard Worker // Provider returns the value for a provider for the source of the dependency edge for which the 150*1fa6dee9SAndroid Build Coastguard Worker // transition is being computed. If the value is not set it returns nil and false. It panics if 151*1fa6dee9SAndroid Build Coastguard Worker // called before the appropriate mutator or GenerateBuildActions pass for the provider. The value 152*1fa6dee9SAndroid Build Coastguard Worker // returned may be a deep copy of the value originally passed to SetProvider. 153*1fa6dee9SAndroid Build Coastguard Worker // 154*1fa6dee9SAndroid Build Coastguard Worker // This method shouldn't be used directly, prefer the type-safe android.ModuleProvider instead. 155*1fa6dee9SAndroid Build Coastguard Worker Provider(provider AnyProviderKey) (any, bool) 156*1fa6dee9SAndroid Build Coastguard Worker 157*1fa6dee9SAndroid Build Coastguard Worker // ModuleErrorf reports an error at the line number of the module type in the module definition. 158*1fa6dee9SAndroid Build Coastguard Worker ModuleErrorf(fmt string, args ...interface{}) 159*1fa6dee9SAndroid Build Coastguard Worker 160*1fa6dee9SAndroid Build Coastguard Worker // PropertyErrorf reports an error at the line number of a property in the module definition. 161*1fa6dee9SAndroid Build Coastguard Worker PropertyErrorf(property, fmt string, args ...interface{}) 162*1fa6dee9SAndroid Build Coastguard Worker} 163*1fa6dee9SAndroid Build Coastguard Worker 164*1fa6dee9SAndroid Build Coastguard Workertype transitionMutatorImpl struct { 165*1fa6dee9SAndroid Build Coastguard Worker name string 166*1fa6dee9SAndroid Build Coastguard Worker mutator TransitionMutator 167*1fa6dee9SAndroid Build Coastguard Worker variantCreatingMutatorIndex int 168*1fa6dee9SAndroid Build Coastguard Worker inputVariants map[*moduleGroup][]*moduleInfo 169*1fa6dee9SAndroid Build Coastguard Worker} 170*1fa6dee9SAndroid Build Coastguard Worker 171*1fa6dee9SAndroid Build Coastguard Worker// Adds each argument in items to l if it's not already there. 172*1fa6dee9SAndroid Build Coastguard Workerfunc addToStringListIfNotPresent(l []string, items ...string) []string { 173*1fa6dee9SAndroid Build Coastguard Worker for _, i := range items { 174*1fa6dee9SAndroid Build Coastguard Worker if !slices.Contains(l, i) { 175*1fa6dee9SAndroid Build Coastguard Worker l = append(l, i) 176*1fa6dee9SAndroid Build Coastguard Worker } 177*1fa6dee9SAndroid Build Coastguard Worker } 178*1fa6dee9SAndroid Build Coastguard Worker 179*1fa6dee9SAndroid Build Coastguard Worker return l 180*1fa6dee9SAndroid Build Coastguard Worker} 181*1fa6dee9SAndroid Build Coastguard Worker 182*1fa6dee9SAndroid Build Coastguard Workerfunc (t *transitionMutatorImpl) addRequiredVariation(m *moduleInfo, variation string) { 183*1fa6dee9SAndroid Build Coastguard Worker m.requiredVariationsLock.Lock() 184*1fa6dee9SAndroid Build Coastguard Worker defer m.requiredVariationsLock.Unlock() 185*1fa6dee9SAndroid Build Coastguard Worker 186*1fa6dee9SAndroid Build Coastguard Worker // This is only a consistency check. Leaking the variations of a transition 187*1fa6dee9SAndroid Build Coastguard Worker // mutator to another one could well lead to issues that are difficult to 188*1fa6dee9SAndroid Build Coastguard Worker // track down. 189*1fa6dee9SAndroid Build Coastguard Worker if m.currentTransitionMutator != "" && m.currentTransitionMutator != t.name { 190*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("transition mutator is %s in mutator %s", m.currentTransitionMutator, t.name)) 191*1fa6dee9SAndroid Build Coastguard Worker } 192*1fa6dee9SAndroid Build Coastguard Worker 193*1fa6dee9SAndroid Build Coastguard Worker m.currentTransitionMutator = t.name 194*1fa6dee9SAndroid Build Coastguard Worker m.transitionVariations = addToStringListIfNotPresent(m.transitionVariations, variation) 195*1fa6dee9SAndroid Build Coastguard Worker} 196*1fa6dee9SAndroid Build Coastguard Worker 197*1fa6dee9SAndroid Build Coastguard Workerfunc (t *transitionMutatorImpl) topDownMutator(mctx TopDownMutatorContext) { 198*1fa6dee9SAndroid Build Coastguard Worker module := mctx.(*mutatorContext).module 199*1fa6dee9SAndroid Build Coastguard Worker mutatorSplits := t.mutator.Split(mctx) 200*1fa6dee9SAndroid Build Coastguard Worker if mutatorSplits == nil || len(mutatorSplits) == 0 { 201*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("transition mutator %s returned no splits for module %s", t.name, mctx.ModuleName())) 202*1fa6dee9SAndroid Build Coastguard Worker } 203*1fa6dee9SAndroid Build Coastguard Worker 204*1fa6dee9SAndroid Build Coastguard Worker // transitionVariations for given a module can be mutated by the module itself 205*1fa6dee9SAndroid Build Coastguard Worker // and modules that directly depend on it. Since this is a top-down mutator, 206*1fa6dee9SAndroid Build Coastguard Worker // all modules that directly depend on this module have already been processed 207*1fa6dee9SAndroid Build Coastguard Worker // so no locking is necessary. 208*1fa6dee9SAndroid Build Coastguard Worker // Sort the module transitions, but keep the mutatorSplits in the order returned 209*1fa6dee9SAndroid Build Coastguard Worker // by Split, as the order can be significant when inter-variant dependencies are 210*1fa6dee9SAndroid Build Coastguard Worker // used. 211*1fa6dee9SAndroid Build Coastguard Worker sort.Strings(module.transitionVariations) 212*1fa6dee9SAndroid Build Coastguard Worker module.transitionVariations = addToStringListIfNotPresent(mutatorSplits, module.transitionVariations...) 213*1fa6dee9SAndroid Build Coastguard Worker 214*1fa6dee9SAndroid Build Coastguard Worker outgoingTransitionCache := make([][]string, len(module.transitionVariations)) 215*1fa6dee9SAndroid Build Coastguard Worker for srcVariationIndex, srcVariation := range module.transitionVariations { 216*1fa6dee9SAndroid Build Coastguard Worker srcVariationTransitionCache := make([]string, len(module.directDeps)) 217*1fa6dee9SAndroid Build Coastguard Worker for depIndex, dep := range module.directDeps { 218*1fa6dee9SAndroid Build Coastguard Worker finalVariation := t.transition(mctx)(mctx.moduleInfo(), srcVariation, dep.module, dep.tag) 219*1fa6dee9SAndroid Build Coastguard Worker srcVariationTransitionCache[depIndex] = finalVariation 220*1fa6dee9SAndroid Build Coastguard Worker t.addRequiredVariation(dep.module, finalVariation) 221*1fa6dee9SAndroid Build Coastguard Worker } 222*1fa6dee9SAndroid Build Coastguard Worker outgoingTransitionCache[srcVariationIndex] = srcVariationTransitionCache 223*1fa6dee9SAndroid Build Coastguard Worker } 224*1fa6dee9SAndroid Build Coastguard Worker module.outgoingTransitionCache = outgoingTransitionCache 225*1fa6dee9SAndroid Build Coastguard Worker} 226*1fa6dee9SAndroid Build Coastguard Worker 227*1fa6dee9SAndroid Build Coastguard Workertype transitionContextImpl struct { 228*1fa6dee9SAndroid Build Coastguard Worker context *Context 229*1fa6dee9SAndroid Build Coastguard Worker source *moduleInfo 230*1fa6dee9SAndroid Build Coastguard Worker dep *moduleInfo 231*1fa6dee9SAndroid Build Coastguard Worker depTag DependencyTag 232*1fa6dee9SAndroid Build Coastguard Worker postMutator bool 233*1fa6dee9SAndroid Build Coastguard Worker config interface{} 234*1fa6dee9SAndroid Build Coastguard Worker errs []error 235*1fa6dee9SAndroid Build Coastguard Worker} 236*1fa6dee9SAndroid Build Coastguard Worker 237*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) DepTag() DependencyTag { 238*1fa6dee9SAndroid Build Coastguard Worker return c.depTag 239*1fa6dee9SAndroid Build Coastguard Worker} 240*1fa6dee9SAndroid Build Coastguard Worker 241*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) Config() interface{} { 242*1fa6dee9SAndroid Build Coastguard Worker return c.config 243*1fa6dee9SAndroid Build Coastguard Worker} 244*1fa6dee9SAndroid Build Coastguard Worker 245*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) IsAddingDependency() bool { 246*1fa6dee9SAndroid Build Coastguard Worker return c.postMutator 247*1fa6dee9SAndroid Build Coastguard Worker} 248*1fa6dee9SAndroid Build Coastguard Worker 249*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) error(err error) { 250*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 251*1fa6dee9SAndroid Build Coastguard Worker c.errs = append(c.errs, err) 252*1fa6dee9SAndroid Build Coastguard Worker } 253*1fa6dee9SAndroid Build Coastguard Worker} 254*1fa6dee9SAndroid Build Coastguard Worker 255*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) ModuleErrorf(fmt string, args ...interface{}) { 256*1fa6dee9SAndroid Build Coastguard Worker c.error(c.context.moduleErrorf(c.dep, fmt, args...)) 257*1fa6dee9SAndroid Build Coastguard Worker} 258*1fa6dee9SAndroid Build Coastguard Worker 259*1fa6dee9SAndroid Build Coastguard Workerfunc (c *transitionContextImpl) PropertyErrorf(property, fmt string, args ...interface{}) { 260*1fa6dee9SAndroid Build Coastguard Worker c.error(c.context.PropertyErrorf(c.dep.logicModule, property, fmt, args...)) 261*1fa6dee9SAndroid Build Coastguard Worker} 262*1fa6dee9SAndroid Build Coastguard Worker 263*1fa6dee9SAndroid Build Coastguard Workertype outgoingTransitionContextImpl struct { 264*1fa6dee9SAndroid Build Coastguard Worker transitionContextImpl 265*1fa6dee9SAndroid Build Coastguard Worker} 266*1fa6dee9SAndroid Build Coastguard Worker 267*1fa6dee9SAndroid Build Coastguard Workerfunc (c *outgoingTransitionContextImpl) Module() Module { 268*1fa6dee9SAndroid Build Coastguard Worker return c.source.logicModule 269*1fa6dee9SAndroid Build Coastguard Worker} 270*1fa6dee9SAndroid Build Coastguard Worker 271*1fa6dee9SAndroid Build Coastguard Workerfunc (c *outgoingTransitionContextImpl) Provider(provider AnyProviderKey) (any, bool) { 272*1fa6dee9SAndroid Build Coastguard Worker return c.context.provider(c.source, provider.provider()) 273*1fa6dee9SAndroid Build Coastguard Worker} 274*1fa6dee9SAndroid Build Coastguard Worker 275*1fa6dee9SAndroid Build Coastguard Workertype incomingTransitionContextImpl struct { 276*1fa6dee9SAndroid Build Coastguard Worker transitionContextImpl 277*1fa6dee9SAndroid Build Coastguard Worker} 278*1fa6dee9SAndroid Build Coastguard Worker 279*1fa6dee9SAndroid Build Coastguard Workerfunc (c *incomingTransitionContextImpl) Module() Module { 280*1fa6dee9SAndroid Build Coastguard Worker return c.dep.logicModule 281*1fa6dee9SAndroid Build Coastguard Worker} 282*1fa6dee9SAndroid Build Coastguard Worker 283*1fa6dee9SAndroid Build Coastguard Workerfunc (c *incomingTransitionContextImpl) Provider(provider AnyProviderKey) (any, bool) { 284*1fa6dee9SAndroid Build Coastguard Worker return c.context.provider(c.dep, provider.provider()) 285*1fa6dee9SAndroid Build Coastguard Worker} 286*1fa6dee9SAndroid Build Coastguard Worker 287*1fa6dee9SAndroid Build Coastguard Workerfunc (t *transitionMutatorImpl) transition(mctx BaseModuleContext) Transition { 288*1fa6dee9SAndroid Build Coastguard Worker return func(source *moduleInfo, sourceVariation string, dep *moduleInfo, depTag DependencyTag) string { 289*1fa6dee9SAndroid Build Coastguard Worker tc := transitionContextImpl{ 290*1fa6dee9SAndroid Build Coastguard Worker context: mctx.base().context, 291*1fa6dee9SAndroid Build Coastguard Worker source: source, 292*1fa6dee9SAndroid Build Coastguard Worker dep: dep, 293*1fa6dee9SAndroid Build Coastguard Worker depTag: depTag, 294*1fa6dee9SAndroid Build Coastguard Worker config: mctx.Config(), 295*1fa6dee9SAndroid Build Coastguard Worker } 296*1fa6dee9SAndroid Build Coastguard Worker outCtx := &outgoingTransitionContextImpl{tc} 297*1fa6dee9SAndroid Build Coastguard Worker outgoingVariation := t.mutator.OutgoingTransition(outCtx, sourceVariation) 298*1fa6dee9SAndroid Build Coastguard Worker for _, err := range outCtx.errs { 299*1fa6dee9SAndroid Build Coastguard Worker mctx.error(err) 300*1fa6dee9SAndroid Build Coastguard Worker } 301*1fa6dee9SAndroid Build Coastguard Worker if mctx.Failed() { 302*1fa6dee9SAndroid Build Coastguard Worker return outgoingVariation 303*1fa6dee9SAndroid Build Coastguard Worker } 304*1fa6dee9SAndroid Build Coastguard Worker inCtx := &incomingTransitionContextImpl{tc} 305*1fa6dee9SAndroid Build Coastguard Worker finalVariation := t.mutator.IncomingTransition(inCtx, outgoingVariation) 306*1fa6dee9SAndroid Build Coastguard Worker for _, err := range inCtx.errs { 307*1fa6dee9SAndroid Build Coastguard Worker mctx.error(err) 308*1fa6dee9SAndroid Build Coastguard Worker } 309*1fa6dee9SAndroid Build Coastguard Worker return finalVariation 310*1fa6dee9SAndroid Build Coastguard Worker } 311*1fa6dee9SAndroid Build Coastguard Worker} 312*1fa6dee9SAndroid Build Coastguard Worker 313*1fa6dee9SAndroid Build Coastguard Workerfunc (t *transitionMutatorImpl) bottomUpMutator(mctx BottomUpMutatorContext) { 314*1fa6dee9SAndroid Build Coastguard Worker mc := mctx.(*mutatorContext) 315*1fa6dee9SAndroid Build Coastguard Worker // Fetch and clean up transition mutator state. No locking needed since the 316*1fa6dee9SAndroid Build Coastguard Worker // only time interaction between multiple modules is required is during the 317*1fa6dee9SAndroid Build Coastguard Worker // computation of the variations required by a given module. 318*1fa6dee9SAndroid Build Coastguard Worker variations := mc.module.transitionVariations 319*1fa6dee9SAndroid Build Coastguard Worker outgoingTransitionCache := mc.module.outgoingTransitionCache 320*1fa6dee9SAndroid Build Coastguard Worker mc.module.transitionVariations = nil 321*1fa6dee9SAndroid Build Coastguard Worker mc.module.outgoingTransitionCache = nil 322*1fa6dee9SAndroid Build Coastguard Worker mc.module.currentTransitionMutator = "" 323*1fa6dee9SAndroid Build Coastguard Worker 324*1fa6dee9SAndroid Build Coastguard Worker if len(variations) < 1 { 325*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Errorf("no variations found for module %s by mutator %s", 326*1fa6dee9SAndroid Build Coastguard Worker mctx.ModuleName(), t.name)) 327*1fa6dee9SAndroid Build Coastguard Worker } 328*1fa6dee9SAndroid Build Coastguard Worker 329*1fa6dee9SAndroid Build Coastguard Worker if len(variations) == 1 && variations[0] == "" { 330*1fa6dee9SAndroid Build Coastguard Worker // Module is not split, just apply the transition 331*1fa6dee9SAndroid Build Coastguard Worker mc.context.convertDepsToVariation(mc.module, 0, 332*1fa6dee9SAndroid Build Coastguard Worker chooseDepByIndexes(mc.mutator.name, outgoingTransitionCache)) 333*1fa6dee9SAndroid Build Coastguard Worker } else { 334*1fa6dee9SAndroid Build Coastguard Worker mc.createVariationsWithTransition(variations, outgoingTransitionCache) 335*1fa6dee9SAndroid Build Coastguard Worker } 336*1fa6dee9SAndroid Build Coastguard Worker} 337*1fa6dee9SAndroid Build Coastguard Worker 338*1fa6dee9SAndroid Build Coastguard Workerfunc (t *transitionMutatorImpl) mutateMutator(mctx BottomUpMutatorContext) { 339*1fa6dee9SAndroid Build Coastguard Worker module := mctx.(*mutatorContext).module 340*1fa6dee9SAndroid Build Coastguard Worker currentVariation := module.variant.variations.get(t.name) 341*1fa6dee9SAndroid Build Coastguard Worker t.mutator.Mutate(mctx, currentVariation) 342*1fa6dee9SAndroid Build Coastguard Worker} 343*1fa6dee9SAndroid Build Coastguard Worker 344*1fa6dee9SAndroid Build Coastguard Workertype TransitionMutatorHandle interface { 345*1fa6dee9SAndroid Build Coastguard Worker // NeverFar causes the variations created by this mutator to never be ignored when adding 346*1fa6dee9SAndroid Build Coastguard Worker // far variation dependencies. Normally, far variation dependencies ignore all the variants 347*1fa6dee9SAndroid Build Coastguard Worker // of the source module, and only use the variants explicitly requested by the 348*1fa6dee9SAndroid Build Coastguard Worker // AddFarVariationDependencies call. 349*1fa6dee9SAndroid Build Coastguard Worker NeverFar() TransitionMutatorHandle 350*1fa6dee9SAndroid Build Coastguard Worker} 351*1fa6dee9SAndroid Build Coastguard Worker 352*1fa6dee9SAndroid Build Coastguard Workertype transitionMutatorHandle struct { 353*1fa6dee9SAndroid Build Coastguard Worker inner MutatorHandle 354*1fa6dee9SAndroid Build Coastguard Worker} 355*1fa6dee9SAndroid Build Coastguard Worker 356*1fa6dee9SAndroid Build Coastguard Workervar _ TransitionMutatorHandle = (*transitionMutatorHandle)(nil) 357*1fa6dee9SAndroid Build Coastguard Worker 358*1fa6dee9SAndroid Build Coastguard Workerfunc (h *transitionMutatorHandle) NeverFar() TransitionMutatorHandle { 359*1fa6dee9SAndroid Build Coastguard Worker h.inner.setNeverFar() 360*1fa6dee9SAndroid Build Coastguard Worker return h 361*1fa6dee9SAndroid Build Coastguard Worker} 362*1fa6dee9SAndroid Build Coastguard Worker 363*1fa6dee9SAndroid Build Coastguard Workerfunc (c *Context) RegisterTransitionMutator(name string, mutator TransitionMutator) TransitionMutatorHandle { 364*1fa6dee9SAndroid Build Coastguard Worker impl := &transitionMutatorImpl{name: name, mutator: mutator} 365*1fa6dee9SAndroid Build Coastguard Worker 366*1fa6dee9SAndroid Build Coastguard Worker c.RegisterTopDownMutator(name+"_propagate", impl.topDownMutator) 367*1fa6dee9SAndroid Build Coastguard Worker bottomUpHandle := c.RegisterBottomUpMutator(name, impl.bottomUpMutator).setTransitionMutator(impl) 368*1fa6dee9SAndroid Build Coastguard Worker c.RegisterBottomUpMutator(name+"_mutate", impl.mutateMutator) 369*1fa6dee9SAndroid Build Coastguard Worker return &transitionMutatorHandle{inner: bottomUpHandle} 370*1fa6dee9SAndroid Build Coastguard Worker} 371*1fa6dee9SAndroid Build Coastguard Worker 372*1fa6dee9SAndroid Build Coastguard Worker// This function is called for every dependency edge to determine which 373*1fa6dee9SAndroid Build Coastguard Worker// variation of the dependency is needed. Its inputs are the depending module, 374*1fa6dee9SAndroid Build Coastguard Worker// its variation, the dependency and the dependency tag. 375*1fa6dee9SAndroid Build Coastguard Workertype Transition func(source *moduleInfo, sourceVariation string, dep *moduleInfo, depTag DependencyTag) string 376