Skip to content

Commit

Permalink
input: add 'clean' dependency property
Browse files Browse the repository at this point in the history
If this is set to `true` for a dependency the environment and tools are
dropped and the dependency starts with the default-environment and no
tools set.

This becomes particularly useful when an existing root-package should
become a dependency of another root-package, e.g. for building an
installer.
  • Loading branch information
rhubert committed May 22, 2024
1 parent cc29acc commit 2e1a20c
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 23 deletions.
5 changes: 5 additions & 0 deletions doc/manual/configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,11 @@ The following settings are supported:
| | | At the dependency both names will refer to the same |
| | | tool. |
+-------------+-----------------+-----------------------------------------------------+
| clean | Boolean | Drop all the environment and tools collected so far |
| | | for this dependency. This is mostly useful to make |
| | | an existing root-package become a dependency |
| | | of another root package. |
+-------------+-----------------+-----------------------------------------------------+

.. _configuration-recipes-env:

Expand Down
57 changes: 34 additions & 23 deletions pym/bob/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -1855,10 +1855,11 @@ class Recipe(object):
"""

class Dependency(object):
def __init__(self, recipe, env, fwd, use, cond, tools, checkoutDep):
def __init__(self, recipe, env, fwd, use, cond, tools, checkoutDep, clean):
self.recipe = recipe
self.envOverride = env
self.provideGlobal = fwd
self.clean = clean
self.use = use
self.useEnv = "environment" in self.use
self.useTools = "tools" in self.use
Expand All @@ -1870,9 +1871,9 @@ def __init__(self, recipe, env, fwd, use, cond, tools, checkoutDep):
self.checkoutDep = checkoutDep

@staticmethod
def __parseEntry(dep, env, fwd, use, cond, tools, checkoutDep):
def __parseEntry(dep, env, fwd, use, cond, tools, checkoutDep, clean):
if isinstance(dep, str):
return [ Recipe.Dependency(dep, env, fwd, use, cond, tools, checkoutDep) ]
return [ Recipe.Dependency(dep, env, fwd, use, cond, tools, checkoutDep, clean) ]
else:
envOverride = dep.get("environment")
if envOverride:
Expand All @@ -1884,6 +1885,7 @@ def __parseEntry(dep, env, fwd, use, cond, tools, checkoutDep):
tools.update(toolOverride)
fwd = dep.get("forward", fwd)
use = dep.get("use", use)
clean = dep.get("clean", clean)
newCond = dep.get("if")
if newCond is not None:
cond = cond + [newCond] if cond is not None else [ newCond ]
Expand All @@ -1892,22 +1894,22 @@ def __parseEntry(dep, env, fwd, use, cond, tools, checkoutDep):
if name:
if "depends" in dep:
raise ParseError("A dependency must not use 'name' and 'depends' at the same time!")
return [ Recipe.Dependency(name, env, fwd, use, cond, tools, checkoutDep) ]
return [ Recipe.Dependency(name, env, fwd, use, cond, tools, checkoutDep, clean) ]
dependencies = dep.get("depends")
if dependencies is None:
raise ParseError("Either 'name' or 'depends' required for dependencies!")
return Recipe.Dependency.parseEntries(dependencies, env, fwd,
use, cond, tools,
checkoutDep)
checkoutDep, clean)

@staticmethod
def parseEntries(deps, env={}, fwd=False, use=["result", "deps"],
cond=None, tools={}, checkoutDep=False):
cond=None, tools={}, checkoutDep=False, clean=False):
"""Returns an iterator yielding all dependencies as flat list"""
# return flattened list of dependencies
return chain.from_iterable(
Recipe.Dependency.__parseEntry(dep, env, fwd, use, cond, tools,
checkoutDep)
checkoutDep, clean)
for dep in deps )

@staticmethod
Expand Down Expand Up @@ -2317,24 +2319,29 @@ def prepare(self, inputEnv, sandboxEnabled, inputStates, inputSandbox=None,
if dep.condition and not all(env.evaluate(cond, "dependency "+recipe)
for cond in dep.condition): continue

if dep.toolOverride:
try:
thisDepTools = depTools.derive({
k : depTools[v] for k,v in dep.toolOverride.items() })
except KeyError as e:
raise ParseError("Cannot remap unkown tool '{}' for dependency '{}'!"
.format(e.args[0], recipe))
thisDepDiffTools = depDiffTools.copy()
thisDepDiffTools.update({
k : depDiffTools.get(v, v)
for k, v in dep.toolOverride.items() })
if dep.clean:
thisDepEnv = self.getRecipeSet().getRootEnv()
thisDepTools = Env()
thisDepDiffTools = Env()
else:
thisDepTools = depTools
thisDepDiffTools = depDiffTools
if dep.toolOverride:
try:
thisDepTools = depTools.derive({
k : depTools[v] for k,v in dep.toolOverride.items() })
except KeyError as e:
raise ParseError("Cannot remap unkown tool '{}' for dependency '{}'!"
.format(e.args[0], recipe))
thisDepDiffTools = depDiffTools.copy()
thisDepDiffTools.update({
k : depDiffTools.get(v, v)
for k, v in dep.toolOverride.items() })
else:
thisDepTools = depTools
thisDepDiffTools = depDiffTools

thisDepEnv = depEnv.derive(
{ key : env.substitute(value, "depends["+recipe+"].environment["+key+"]")
for key, value in dep.envOverride.items() })
thisDepEnv = depEnv.derive(
{ key : env.substitute(value, "depends["+recipe+"].environment["+key+"]")
for key, value in dep.envOverride.items() })

r = self.__recipeSet.getRecipe(recipe)
try:
Expand Down Expand Up @@ -3340,6 +3347,9 @@ async def getScmStatus(self):
def getBuildHook(self, name):
return self.__buildHooks.get(name)

def getRootEnv(self):
return self.__rootEnv

def getSandboxMounts(self):
return self.__sandboxOpts.get("mount", [])

Expand Down Expand Up @@ -3564,6 +3574,7 @@ def __createSchemas(self):
schema.Optional('name') : str,
schema.Optional('use') : useClauses,
schema.Optional('forward') : bool,
schema.Optional('clean') : bool,
schema.Optional('environment') : VarDefineValidator("depends::environment"),
schema.Optional('if') : schema.Or(str, IfExpression),
schema.Optional('tools') : { toolNameSchema : toolNameSchema },
Expand Down
55 changes: 55 additions & 0 deletions test/unit/test_input_recipeset.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,61 @@ def testCheckoutDepVariants(self):

self.assertNotEqual(paVId, pbVId, "checkout steps are different")

def testCleanDep(self):
""" Test the `clean` property for dependencies """

self.writeDefault(
{"environment" : {"DEFAULT" : "42" }})

self.writeClass("foo", """\
root: True
depends:
- name: foo
use: [tools]
forward: True
packageTools: [foo]
""")

self.writeRecipe("a", """\
inherit: [foo]
depends:
- name: b-env
use: [environment]
forward: true
- name: b
clean: True
packageScript: "true"
""")

self.writeRecipe("b-env", """\
provideVars:
B: "2"
""")

self.writeRecipe("b", """\
inherit: [foo]
packageVars: [DEFAULT, B]
packageScript: "true"
""")

self.writeRecipe("foo", """\
packageTools: [foo]
packageScript: "true"
provideTools:
foo: .
""")

recipes = RecipeSet()
recipes.parse()
packages = recipes.generatePackages(lambda x,y: "unused")

pa_b = packages.walkPackagePath("a/b")
pb = packages.walkPackagePath("b")
self.assertEqual(pa_b.getPackageStep().getVariantId(),
pb.getPackageStep().getVariantId())
self.assertEqual(
{"DEFAULT" : "42"},
pb.getPackageStep().getEnv())

class TestDependencyEnv(RecipesTmp, TestCase):
"""Tests related to "environment" block in dependencies"""
Expand Down

0 comments on commit 2e1a20c

Please sign in to comment.