diff options
author | Tristan Van Berkom <tristan.vanberkom@codethink.co.uk> | 2017-05-24 17:50:00 +0900 |
---|---|---|
committer | Tristan Van Berkom <tristan.vanberkom@codethink.co.uk> | 2017-05-24 17:50:00 +0900 |
commit | ca9a8837dd00a283fd8a9cca1760588640d23571 (patch) | |
tree | ff5546440ff4f4f4421b0256832b68b94c5cf162 | |
parent | f82a9be8f50490afa972468b1dad9aa5a5f7d5fb (diff) | |
download | buildstream-ca9a8837dd00a283fd8a9cca1760588640d23571.tar.gz |
script element: interim hacks
We will soon be refactoring this element to be more widely useful, in
the meantime I needed the following changes:
o Make staging of the input element optional
o Dont mount the root read-only
o Allow configuration of where to collect the output artifact
This was needed for a straight forward use case where the user
wants to
A.) Stage something in the root
B.) Modify that sysroot by running some commands
C.) Collect the entire resulting sysroot as an artifact
In this case, I needed to be able to run `dpkg --configure -a`
in a sysroot and collect the result.
-rw-r--r-- | buildstream/plugins/elements/script.py | 54 | ||||
-rw-r--r-- | buildstream/plugins/elements/script.yaml | 4 |
2 files changed, 33 insertions, 25 deletions
diff --git a/buildstream/plugins/elements/script.py b/buildstream/plugins/elements/script.py index d00fe53a0..f1c301056 100644 --- a/buildstream/plugins/elements/script.py +++ b/buildstream/plugins/elements/script.py @@ -42,11 +42,12 @@ class ScriptElement(Element): def configure(self, node): self.base_dep = self.node_get_member(node, str, 'base') - self.input_dep = self.node_get_member(node, str, 'input') + self.input_dep = self.node_get_member(node, str, 'input', '') or None self.stage_mode = self.node_get_member(node, str, 'stage-mode') + self.collect = self.node_get_member(node, str, 'collect') # Assert stage mode is valid - if self.stage_mode not in ['build', 'install']: + if self.stage_mode and self.stage_mode not in ['build', 'install']: p = self.node_provenance(node, 'stage-mode') raise ElementError("{}: Stage mode must be either 'build' or 'install'" .format(p)) @@ -80,24 +81,22 @@ class ScriptElement(Element): # Assert that a base and an input were specified if not self.base_dep: raise ElementError("{}: No base dependencies were specified".format(self)) - if not self.input_dep: - raise ElementError("{}: No input dependencies were specified".format(self)) # Now resolve the base and input elements self.base_elt = self.search(Scope.BUILD, self.base_dep) - self.input_elt = self.search(Scope.BUILD, self.input_dep) + if self.input_dep: + self.input_elt = self.search(Scope.BUILD, self.input_dep) if self.base_elt is None: raise ElementError("{}: Could not find base dependency {}".format(self, self.base_dep)) - if self.input_elt is None: - raise ElementError("{}: Could not find input dependency {}".format(self, self.input_dep)) def get_unique_key(self): return { 'commands': self.commands, 'base': self.base_dep, 'input': self.input_dep, - 'stage-mode': self.stage_mode + 'stage-mode': self.stage_mode, + 'collect': self.collect } def assemble(self, sandbox): @@ -107,26 +106,29 @@ class ScriptElement(Element): # Stage the base in the sandbox root with self.timed_activity("Staging {} as base".format(self.base_dep), silent_nested=True): - self.base_elt.stage_dependencies(sandbox, Scope.BUILD) + self.base_elt.stage_dependencies(sandbox, Scope.RUN) # Run any integration commands on the base with self.timed_activity("Integrating sandbox", silent_nested=True): - for dep in self.base_elt.dependencies(Scope.BUILD): + for dep in self.base_elt.dependencies(Scope.RUN): dep.integrate(sandbox) # Ensure some directories we'll need - os.makedirs(os.path.join(directory, - 'buildstream', - 'build'), exist_ok=True) - os.makedirs(os.path.join(directory, - 'buildstream', - 'install'), exist_ok=True) - - # Stage the input - input_dir = os.path.join(os.sep, 'buildstream', self.stage_mode) - with self.timed_activity("Staging {} as input at {}" - .format(self.input_dep, input_dir), silent_nested=True): - self.input_elt.stage_dependencies(sandbox, Scope.RUN, path=input_dir) + cmd_dir = '/' + if self.stage_mode: + os.makedirs(os.path.join(directory, + 'buildstream', + 'build'), exist_ok=True) + os.makedirs(os.path.join(directory, + 'buildstream', + 'install'), exist_ok=True) + + # Stage the input + input_dir = os.path.join(os.sep, 'buildstream', self.stage_mode) + cmd_dir = input_dir + with self.timed_activity("Staging {} as input at {}" + .format(self.input_dep, input_dir), silent_nested=True): + self.input_elt.stage_dependencies(sandbox, Scope.RUN, path=input_dir) # Run the scripts with self.timed_activity("Running script commands"): @@ -136,14 +138,16 @@ class ScriptElement(Element): # Note the -e switch to 'sh' means to exit with an error # if any untested command fails. exitcode = sandbox.run(['sh', '-c', '-e', cmd + '\n'], - SandboxFlags.ROOT_READ_ONLY, - cwd=input_dir, + 0, + cwd=cmd_dir, env=environment) if exitcode != 0: raise ElementError("Command '{}' failed with exitcode {}".format(cmd, exitcode)) # Return the install dir - return os.path.join(os.sep, 'buildstream', 'install') + if not self.collect: + self.collect = os.path.join(os.sep, 'buildstream', 'install') + return self.collect # Plugin entry point diff --git a/buildstream/plugins/elements/script.yaml b/buildstream/plugins/elements/script.yaml index c21e115fa..17e0cfa54 100644 --- a/buildstream/plugins/elements/script.yaml +++ b/buildstream/plugins/elements/script.yaml @@ -30,3 +30,7 @@ config: # List of commands to run in the sandbox # commands: [] + + # Directory to collect the output artifact from, + # default is %{install-root} + # collect: |