Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 65 additions & 16 deletions pym/bob/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from . import BOB_VERSION, BOB_INPUT_HASH, DEBUG
from .errors import ParseError, BobError
from .languages import getLanguage, ScriptLanguage, BashLanguage, PwshLanguage
from .languages import getLanguage, ScriptLanguage, BashLanguage, PwshLanguage, PythonLanguage
from .pathspec import PackageSet
from .scm import CvsScm, GitScm, ImportScm, SvnScm, UrlScm, ScmOverride, \
auditFromDir, getScm, SYNTHETIC_SCM_PROPS
Expand Down Expand Up @@ -115,9 +115,11 @@
recipe.get("fingerprintScript")),
ScriptLanguage.PWSH : recipe.get("fingerprintScriptPwsh",
recipe.get("fingerprintScript")),
ScriptLanguage.PYTHON : recipe.get("fingerprintScriptPython",
recipe.get("fingerprintScript")),
}

def fetchScripts(recipe, prefix, resolveBash, resolvePwsh):
def fetchScripts(recipe, prefix, resolveBash, resolvePwsh, resolvePython):
return {
ScriptLanguage.BASH : (
resolveBash(recipe.get(prefix + "SetupBash", recipe.get(prefix + "Setup")),
Expand All @@ -130,21 +132,31 @@
prefix + "Setup[Pwsh]"),
resolvePwsh(recipe.get(prefix + "ScriptPwsh", recipe.get(prefix + "Script")),
prefix + "Script[Pwsh]"),
)
),
ScriptLanguage.PYTHON : (
resolvePython(recipe.get(prefix + "SetupPython", recipe.get(prefix + "Setup")),
prefix + "Setup[Python]"),
resolvePython(recipe.get(prefix + "ScriptPython", recipe.get(prefix + "Script")),
prefix + "Script[Python]"),
),
}

def mergeScripts(fragments, glue):
"""Join all scripts of the recipe and its classes.

The result is a tuple with (setupScript, mainScript, digestScript)
The result is a tuple with (setupScript, mainScript, digestScript, includedFiles)
"""

return (
joinScripts((f[0][0] for f in fragments), glue),
joinScripts((f[1][0] for f in fragments), glue),
joinScripts(
( joinScripts((f[0][1] for f in fragments), "\n"),
joinScripts((f[1][1] for f in fragments), "\n"),
), "\n")
), "\n"),
{ name : content for name, content in
chain.from_iterable(chain(f[0][2].items(), f[1][2].items()) for f in fragments)
},
)


Expand Down Expand Up @@ -790,6 +802,9 @@
def getDigestScript(self):
raise NotImplementedError

def getIncludedFiles(self):
raise NotImplementedError

Check warning on line 806 in pym/bob/input.py

View check run for this annotation

Codecov / codecov/patch

pym/bob/input.py#L806

Added line #L806 was not covered by tests

def getLabel(self):
raise NotImplementedError

Expand Down Expand Up @@ -1042,6 +1057,9 @@
"""
return self._coreStep.getDigestScript()

def getIncludedFiles(self):
return self._coreStep.getIncludedFiles()

def isDeterministic(self):
"""Return whether the step is deterministic.

Expand Down Expand Up @@ -1458,6 +1476,9 @@
else:
return None

def getIncludedFiles(self):
return self.corePackage.recipe.checkoutIncludedFiles

@property
def fingerprintMask(self):
return 0
Expand Down Expand Up @@ -1537,7 +1558,7 @@
class CoreBuildStep(CoreStep):
__slots__ = []

def __init__(self, corePackage, script=(None, None, None), digestEnv=Env(), env=Env(), args=[]):
def __init__(self, corePackage, script=(None, None, None, {}), digestEnv=Env(), env=Env(), args=[]):
isValid = script[1] is not None
super().__init__(corePackage, isValid, True, digestEnv, env, args)

Expand Down Expand Up @@ -1568,6 +1589,9 @@
def getDigestScript(self):
return self.corePackage.recipe.buildDigestScript

def getIncludedFiles(self):
return self.corePackage.recipe.buildIncludedFiles

@property
def fingerprintMask(self):
# Remove bits of all tools that are not used in buildStep
Expand All @@ -1591,7 +1615,7 @@
class CorePackageStep(CoreStep):
__slots__ = []

def __init__(self, corePackage, script=(None, None, None), digestEnv=Env(), env=Env(), args=[]):
def __init__(self, corePackage, script=(None, None, None, {}), digestEnv=Env(), env=Env(), args=[]):
isValid = script[1] is not None
super().__init__(corePackage, isValid, True, digestEnv, env, args)

Expand Down Expand Up @@ -1622,6 +1646,9 @@
def getDigestScript(self):
return self.corePackage.recipe.packageDigestScript

def getIncludedFiles(self):
return self.corePackage.recipe.packageIncludedFiles

@property
def fingerprintMask(self):
return self.corePackage.fingerprintMask
Expand Down Expand Up @@ -1884,7 +1911,7 @@
raise ParseError("Bad substiturion in {}: {}".format(section, str(e)))
return resolver.resolve(ret)
else:
return (None, None)
return (None, None, {})

def mergeFilter(left, right):
if left is None:
Expand Down Expand Up @@ -2168,9 +2195,11 @@
baseDir, packageName, sourceName).resolve
incHelperPwsh = IncludeHelper(PwshLanguage, recipeSet.loadBinary,
baseDir, packageName, sourceName).resolve
incHelperPython = IncludeHelper(PythonLanguage, recipeSet.loadBinary,
baseDir, packageName, sourceName).resolve

self.__scriptLanguage = recipe.get("scriptLanguage")
self.__checkout = fetchScripts(recipe, "checkout", incHelperBash, incHelperPwsh)
self.__checkout = fetchScripts(recipe, "checkout", incHelperBash, incHelperPwsh, incHelperPython)
self.__checkoutSCMs = recipe.get("checkoutSCM", [])
for scm in self.__checkoutSCMs:
scm["__source"] = sourceName
Expand All @@ -2180,8 +2209,8 @@
for a in self.__checkoutAsserts:
a["__source"] = sourceName + ", checkoutAssert #{}".format(i)
i += 1
self.__build = fetchScripts(recipe, "build", incHelperBash, incHelperPwsh)
self.__package = fetchScripts(recipe, "package", incHelperBash, incHelperPwsh)
self.__build = fetchScripts(recipe, "build", incHelperBash, incHelperPwsh, incHelperPython)
self.__package = fetchScripts(recipe, "package", incHelperBash, incHelperPwsh, incHelperPython)
self.__fingerprintScriptList = fetchFingerprintScripts(recipe)
self.__fingerprintIf = recipe.get("fingerprintIf")
self.__fingerprintVarsList = set(recipe.get("fingerprintVars", []))
Expand Down Expand Up @@ -2316,7 +2345,7 @@

# the package step must always be valid
if self.__package[1] is None:
self.__package = (None, "", 'da39a3ee5e6b4b0d3255bfef95601890afd80709')
self.__package = (None, "", 'da39a3ee5e6b4b0d3255bfef95601890afd80709', {})

# final shared value
self.__shared = self.__shared == True
Expand Down Expand Up @@ -2643,7 +2672,7 @@
directPackages, indirectPackages, states, uidGen(), doFingerprint)

# optional checkout step
if self.__checkout != (None, None, None) or self.__checkoutSCMs or self.__checkoutAsserts:
if self.__checkout != (None, None, None, {}) or self.__checkoutSCMs or self.__checkoutAsserts:
checkoutDigestEnv = env.prune(self.__checkoutVars)
checkoutEnv = ( env.prune(self.__checkoutVars | self.__checkoutVarsWeak)
if self.__checkoutVarsWeak else checkoutDigestEnv )
Expand All @@ -2653,7 +2682,7 @@
srcCoreStep = p.createInvalidCoreCheckoutStep()

# optional build step
if self.__build != (None, None, None):
if self.__build != (None, None, None, {}):
buildDigestEnv = env.prune(self.__buildVars)
buildEnv = ( env.prune(self.__buildVars | self.__buildVarsWeak)
if self.__buildVarsWeak else buildDigestEnv )
Expand Down Expand Up @@ -2765,6 +2794,10 @@
def checkoutDigestScript(self):
return self.__checkout[2] or ""

@property
def checkoutIncludedFiles(self):
return self.__checkout[3]

@property
def checkoutDeterministic(self):
return self.__checkoutDeterministic
Expand Down Expand Up @@ -2793,6 +2826,10 @@
def buildDigestScript(self):
return self.__build[2]

@property
def buildIncludedFiles(self):
return self.__build[3]

@property
def buildVars(self):
return self.__buildVars
Expand All @@ -2813,6 +2850,10 @@
def packageDigestScript(self):
return self.__package[2]

@property
def packageIncludedFiles(self):
return self.__package[3]

@property
def packageVars(self):
return self.__packageVars
Expand Down Expand Up @@ -3024,7 +3065,7 @@
),
schema.Optional('layers') : [str],
schema.Optional('scriptLanguage',
default=ScriptLanguage.BASH) : schema.And(schema.Or("bash", "PowerShell"),
default=ScriptLanguage.BASH) : schema.And(schema.Or("bash", "PowerShell", "python"),
schema.Use(ScriptLanguage)),
})

Expand Down Expand Up @@ -3622,21 +3663,27 @@
schema.Optional('checkoutScript') : str,
schema.Optional('checkoutScriptBash') : str,
schema.Optional('checkoutScriptPwsh') : str,
schema.Optional('checkoutScriptPython') : str,
schema.Optional('checkoutSetup') : str,
schema.Optional('checkoutSetupBash') : str,
schema.Optional('checkoutSetupPwsh') : str,
schema.Optional('checkoutSetupPython') : str,
schema.Optional('buildScript') : str,
schema.Optional('buildScriptBash') : str,
schema.Optional('buildScriptPwsh') : str,
schema.Optional('buildScriptPython') : str,
schema.Optional('buildSetup') : str,
schema.Optional('buildSetupBash') : str,
schema.Optional('buildSetupPwsh') : str,
schema.Optional('buildSetupPython') : str,
schema.Optional('packageScript') : str,
schema.Optional('packageScriptBash') : str,
schema.Optional('packageScriptPwsh') : str,
schema.Optional('packageScriptPython') : str,
schema.Optional('packageSetup') : str,
schema.Optional('packageSetupBash') : str,
schema.Optional('packageSetupPwsh') : str,
schema.Optional('packageSetupPython') : str,
schema.Optional('checkoutTools') : [ toolNameSchema ],
schema.Optional('buildTools') : [ toolNameSchema ],
schema.Optional('packageTools') : [ toolNameSchema ],
Expand Down Expand Up @@ -3674,6 +3721,7 @@
schema.Optional('fingerprintScript', default="") : str,
schema.Optional('fingerprintScriptBash') : str,
schema.Optional('fingerprintScriptPwsh', default="") : str,
schema.Optional('fingerprintScriptPython', default="") : str,
schema.Optional('fingerprintIf') : schema.Or(None, str, bool, IfExpression),
schema.Optional('fingerprintVars') : [ varNameUseSchema ],
})
Expand All @@ -3694,9 +3742,10 @@
schema.Optional('fingerprintScript', default="") : str,
schema.Optional('fingerprintScriptBash') : str,
schema.Optional('fingerprintScriptPwsh', default="") : str,
schema.Optional('fingerprintScriptPython', default="") : str,
schema.Optional('fingerprintIf') : schema.Or(None, str, bool, IfExpression),
schema.Optional('fingerprintVars') : [ varNameUseSchema ],
schema.Optional('scriptLanguage') : schema.And(schema.Or("bash", "PowerShell"),
schema.Optional('scriptLanguage') : schema.And(schema.Or("bash", "PowerShell", "python"),
schema.Use(ScriptLanguage)),
schema.Optional('jobServer') : bool,
}
Expand Down
13 changes: 12 additions & 1 deletion pym/bob/invoker.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import os
import re
import shutil
import stat
import subprocess
import sys
import tempfile
Expand Down Expand Up @@ -266,7 +267,6 @@ def __getSandboxCmds(self, tmpDir):
#FIXME: if verbosity >= 4: cmdArgs.append('-D')
cmdArgs.extend(["-S", tmpDir])
cmdArgs.extend(["-H", "bob"])
cmdArgs.extend(["-d", "/tmp"])
sandboxRootFs = os.path.abspath(self.__spec.sandboxRootWorkspace)
for f in os.listdir(sandboxRootFs):
cmdArgs.extend(["-M", os.path.join(sandboxRootFs, f), "-m", "/"+f])
Expand Down Expand Up @@ -301,6 +301,16 @@ async def executeStep(self, mode, clean=False, keepSandbox=False):
# also used as ephemeral sandbox container.
tmpDir = tempfile.mkdtemp()

# Create /tmp in sandbox container. Receives included files and
# needs to be there anyway.
os.mkdir(os.path.join(tmpDir, "tmp"), 0o755)
for name, content in self.__spec.includedFiles.items():
fn = os.path.join(tmpDir, "tmp", name)
with open(fn, "wb") as f:
f.write(content)
# Set explicit mode to retain Bob 0.19 behaviour.
os.chmod(fn, stat.S_IREAD|stat.S_IWRITE)

# prepare workspace
clean = self.__spec.clean if self.__spec.clean is not None else clean
if not os.path.isdir(self.__spec.workspaceWorkspacePath):
Expand Down Expand Up @@ -468,6 +478,7 @@ async def executeFingerprint(self, keepSandbox=False):

# Setup workspace
cmdArgs = self.__getSandboxCmds(tmpDir)
cmdArgs.extend(["-d", "/tmp"])
cmdArgs.extend(["-d", "/bob/fingerprint"])
cmdArgs.extend(["-W", "/bob/fingerprint"])

Expand Down
Loading