@@ -2087,9 +2087,16 @@ def getLayer(self):
20872087 are named from top to bottom. Example:
20882088 ``layers/foo/layers/bar/recipes/baz.yaml`` -> ``['foo', 'bar']``.
20892089
2090+ If the managedLayers policy is set to the new behaviour, nested layers
2091+ are flattened. This means that layers are always returnd as single-item
2092+ lists.
2093+
20902094 :rtype: List[str]
20912095 """
2092- return self .__layer
2096+ if self .__layer :
2097+ return self .__layer .split ("/" )
2098+ else :
2099+ return []
20932100
20942101 def resolveClasses (self , rootEnv ):
20952102 # must be done only once
@@ -3003,6 +3010,7 @@ class RecipeSet:
30033010 schema .Optional ('fixImportScmVariant' ) : bool ,
30043011 schema .Optional ('defaultFileMode' ) : bool ,
30053012 schema .Optional ('substituteMetaEnv' ) : bool ,
3013+ schema .Optional ('managedLayers' ) : bool ,
30063014 },
30073015 error = "Invalid policy specified! Are you using an appropriate version of Bob?"
30083016 ),
@@ -3051,7 +3059,12 @@ class RecipeSet:
30513059 "0.25rc1" ,
30523060 InfoOnce ("substituteMetaEnv policy is not set. MetaEnv will not be substituted." ,
30533061 help = "See http://bob-build-tool.readthedocs.io/en/latest/manual/policies.html#substitutemetaenv for more information." )
3054- )
3062+ ),
3063+ "managedLayers" : (
3064+ "0.25.0rc2.dev6" ,
3065+ InfoOnce ("managedLayers policy is not set. Only unmanaged layers are supported." ,
3066+ help = "See http://bob-build-tool.readthedocs.io/en/latest/manual/policies.html#managedlayers for more information." )
3067+ ),
30553068 }
30563069
30573070 _ignoreCmdConfig = False
@@ -3481,7 +3494,7 @@ def __parse(self, envOverrides, platform, recipesRoot=""):
34813494 os .path .join (os .path .expanduser ("~" ), '.config' )), 'bob' , 'default.yaml' ))
34823495
34833496 # Begin with root layer
3484- self .__parseLayer (LayerSpec ("" ), "9999" , recipesRoot )
3497+ self .__parseLayer (LayerSpec ("" ), "9999" , recipesRoot , None )
34853498
34863499 # Out-of-tree builds may have a dedicated default.yaml
34873500 if recipesRoot :
@@ -3557,20 +3570,40 @@ def calculatePolicies(cls, config):
35573570 ret [name ] = (behaviour , None )
35583571 return ret
35593572
3560- def __parseLayer (self , layerSpec , maxVer , recipesRoot ):
3573+ def __parseLayer (self , layerSpec , maxVer , recipesRoot , upperLayer ):
35613574 layer = layerSpec .getName ()
3562-
3563- if layer in self .__layers :
3564- return
3565- self .__layers .append (layer )
3566-
3567- # SCM backed layers are in build dir, regular layers are in project dir.
3568- rootDir = recipesRoot if layerSpec .getScm () is None else ""
35693575 if layer :
3570- rootDir = os .path .join (rootDir , "layers" , layer )
3571- if not os .path .isdir (rootDir or "." ):
3572- raise ParseError (f"Layer '{ layer } ' does not exist!" ,
3576+ # Managed layers imply that layers are potentially nested instead
3577+ # of being checked out next to each other in the build directory.
3578+ managedLayers = self .getPolicy ('managedLayers' )
3579+ if layerSpec .getScm () is not None and not managedLayers :
3580+ raise ParseError ("Managed layers aren't enabled! See the managedLayers policy for details." )
3581+
3582+ # Pre 0.25, layers could be nested.
3583+ if not managedLayers and upperLayer :
3584+ layer = upperLayer + "/" + layer
3585+
3586+ if layer in self .__layers :
3587+ return
3588+ self .__layers .append (layer )
3589+
3590+ if managedLayers :
3591+ # SCM backed layers are in build dir, regular layers are in
3592+ # project dir.
3593+ rootDir = recipesRoot if layerSpec .getScm () is None else ""
3594+ rootDir = os .path .join (rootDir , "layers" , layer )
3595+ if not os .path .isdir (rootDir ):
3596+ raise ParseError (f"Layer '{ layer } ' does not exist!" ,
35733597 help = "You probably want to run 'bob layers update' to fetch missing layers." )
3598+ else :
3599+ # Before managed layers existed, layers could be nested in the
3600+ # project directory.
3601+ rootDir = os .path .join (recipesRoot , * ( os .path .join ("layers" , l )
3602+ for l in layer .split ("/" ) ))
3603+ if not os .path .isdir (rootDir ):
3604+ raise ParseError (f"Layer '{ layer } ' does not exist!" )
3605+ else :
3606+ rootDir = recipesRoot
35743607
35753608 config = self .loadConfigYaml (self .loadYaml , rootDir )
35763609 minVer = config .get ("bobMinimumVersion" , "0.16" )
@@ -3593,7 +3626,7 @@ def __parseLayer(self, layerSpec, maxVer, recipesRoot):
35933626 # First parse any sub-layers. Their settings have a lower precedence
35943627 # and may be overwritten by higher layers.
35953628 for l in config .get ("layers" , []):
3596- self .__parseLayer (l , maxVer , recipesRoot )
3629+ self .__parseLayer (l , maxVer , recipesRoot , layer )
35973630
35983631 # Load plugins and re-create schemas as new keys may have been added
35993632 self .__loadPlugins (rootDir , layer , config .get ("plugins" , []))
0 commit comments