richardmaw-codethink pushed to branch richardmaw/shell-multi-stage at BuildStream / buildstream
Commits:
-
b8aa5d7c
by Richard Maw at 2018-10-30T10:21:01Z
-
ca00aa8b
by Richard Maw at 2018-10-30T10:21:01Z
-
427dd289
by Richard Maw at 2018-10-30T10:21:01Z
-
5a7ccad0
by Richard Maw at 2018-10-30T10:21:01Z
6 changed files:
- NEWS
- buildstream/_frontend/cli.py
- + tests/integration/project/elements/shell/adds-bar.bst
- + tests/integration/project/elements/shell/adds-foo.bst
- tests/integration/project/elements/integration.bst → tests/integration/project/elements/shell/integration.bst
- tests/integration/shell.py
Changes:
1 |
+===============
|
|
2 |
+buildstream 1.4
|
|
3 |
+===============
|
|
4 |
+ |
|
5 |
+ o `bst shell` learned the `-e` option for staging multiple elements
|
|
6 |
+ provided the element's kind implements `BST_GRANULAR_STAGE`.
|
|
7 |
+ |
|
1 | 8 |
=================
|
2 | 9 |
buildstream 1.3.1
|
3 | 10 |
=================
|
... | ... | @@ -572,11 +572,13 @@ def show(app, elements, deps, except_, order, format_): |
572 | 572 |
help="Mount a file or directory into the sandbox")
|
573 | 573 |
@click.option('--isolate', is_flag=True, default=False,
|
574 | 574 |
help='Create an isolated build sandbox')
|
575 |
+@click.option('--element', '-e', 'elements', multiple=True,
|
|
576 |
+ type=click.Path(readable=False), required=False)
|
|
575 | 577 |
@click.argument('element',
|
576 |
- type=click.Path(readable=False))
|
|
578 |
+ type=click.Path(readable=False), required=False)
|
|
577 | 579 |
@click.argument('command', type=click.STRING, nargs=-1)
|
578 | 580 |
@click.pass_obj
|
579 |
-def shell(app, element, sysroot, mount, isolate, build_, command):
|
|
581 |
+def shell(app, element, elements, sysroot, mount, isolate, build_, command):
|
|
580 | 582 |
"""Run a command in the target element's sandbox environment
|
581 | 583 |
|
582 | 584 |
This will stage a temporary sysroot for running the target
|
... | ... | @@ -597,13 +599,21 @@ def shell(app, element, sysroot, mount, isolate, build_, command): |
597 | 599 |
from .._project import HostMount
|
598 | 600 |
from .._pipeline import PipelineSelection
|
599 | 601 |
|
602 |
+ if elements and element is not None:
|
|
603 |
+ command = [element] + list(command)
|
|
604 |
+ element = None
|
|
605 |
+ if not elements and element is not None:
|
|
606 |
+ elements = [element]
|
|
607 |
+ if not elements:
|
|
608 |
+ raise AppError('No elemenets specified to open a shell in')
|
|
609 |
+ |
|
600 | 610 |
if build_:
|
601 | 611 |
scope = Scope.BUILD
|
602 | 612 |
else:
|
603 | 613 |
scope = Scope.RUN
|
604 | 614 |
|
605 | 615 |
with app.initialized():
|
606 |
- dependencies = app.stream.load_selection((element,), selection=PipelineSelection.NONE)
|
|
616 |
+ dependencies = app.stream.load_selection(elements, selection=PipelineSelection.NONE)
|
|
607 | 617 |
element = dependencies[0]
|
608 | 618 |
prompt = app.shell_prompt(element)
|
609 | 619 |
mounts = [
|
... | ... | @@ -611,7 +621,7 @@ def shell(app, element, sysroot, mount, isolate, build_, command): |
611 | 621 |
for host_path, path in mount
|
612 | 622 |
]
|
613 | 623 |
try:
|
614 |
- exitcode = app.stream.shell((element,), scope, prompt,
|
|
624 |
+ exitcode = app.stream.shell(dependencies, scope, prompt,
|
|
615 | 625 |
directory=sysroot,
|
616 | 626 |
mounts=mounts,
|
617 | 627 |
isolate=isolate,
|
1 |
+kind: manual
|
|
2 |
+depends:
|
|
3 |
+- base.bst
|
|
4 |
+ |
|
5 |
+config:
|
|
6 |
+ install-commands:
|
|
7 |
+ - |
|
|
8 |
+ install -D -m775 /proc/self/fd/0 %{install-root}%{bindir}/bar <<\EOF
|
|
9 |
+ #!/bin/sh
|
|
10 |
+ echo bar
|
|
11 |
+ EOF
|
1 |
+kind: manual
|
|
2 |
+depends:
|
|
3 |
+- base.bst
|
|
4 |
+ |
|
5 |
+config:
|
|
6 |
+ install-commands:
|
|
7 |
+ - |
|
|
8 |
+ install -D -m775 /proc/self/fd/0 %{install-root}%{bindir}/foo <<\EOF
|
|
9 |
+ #!/bin/sh
|
|
10 |
+ echo foo
|
|
11 |
+ EOF
|
... | ... | @@ -29,9 +29,11 @@ DATA_DIR = os.path.join( |
29 | 29 |
# element (str): The element to build and run a shell with
|
30 | 30 |
# isolate (bool): Whether to pass --isolate to `bst shell`
|
31 | 31 |
#
|
32 |
-def execute_shell(cli, project, command, *, config=None, mount=None, element='base.bst', isolate=False):
|
|
32 |
+def execute_shell(cli, project, command, *, config=None, mount=None, element='base.bst', elements=None, isolate=False):
|
|
33 | 33 |
# Ensure the element is built
|
34 |
- result = cli.run(project=project, project_config=config, args=['build', element])
|
|
34 |
+ if elements is None:
|
|
35 |
+ elements = [element]
|
|
36 |
+ result = cli.run(project=project, project_config=config, args=['build'] + elements)
|
|
35 | 37 |
assert result.exit_code == 0
|
36 | 38 |
|
37 | 39 |
args = ['shell']
|
... | ... | @@ -40,7 +42,7 @@ def execute_shell(cli, project, command, *, config=None, mount=None, element='ba |
40 | 42 |
if mount is not None:
|
41 | 43 |
host_path, target_path = mount
|
42 | 44 |
args += ['--mount', host_path, target_path]
|
43 |
- args += [element, '--'] + command
|
|
45 |
+ args += ["-e" + e for e in elements] + ['--'] + command
|
|
44 | 46 |
|
45 | 47 |
return cli.run(project=project, project_config=config, args=args)
|
46 | 48 |
|
... | ... | @@ -345,10 +347,51 @@ def test_sysroot_workspace_visible(cli, tmpdir, datafiles): |
345 | 347 |
|
346 | 348 |
|
347 | 349 |
# Test system integration commands can access devices in /dev
|
350 |
+@pytest.mark.integration
|
|
348 | 351 |
@pytest.mark.datafiles(DATA_DIR)
|
349 | 352 |
def test_integration_devices(cli, tmpdir, datafiles):
|
350 | 353 |
project = os.path.join(datafiles.dirname, datafiles.basename)
|
351 |
- element_name = 'integration.bst'
|
|
354 |
+ element_name = 'shell/integration.bst'
|
|
352 | 355 |
|
353 | 356 |
result = execute_shell(cli, project, ["true"], element=element_name)
|
354 | 357 |
assert result.exit_code == 0
|
358 |
+ |
|
359 |
+ |
|
360 |
+# Test multiple element shell
|
|
361 |
+@pytest.mark.integration
|
|
362 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
363 |
+def test_shell_multiple_elements(cli, tmpdir, datafiles):
|
|
364 |
+ project = os.path.join(datafiles.dirname, datafiles.basename)
|
|
365 |
+ |
|
366 |
+ result = execute_shell(cli, project, ["sh", "-c", "foo && bar"],
|
|
367 |
+ elements=["shell/adds-foo.bst", "shell/adds-bar.bst"])
|
|
368 |
+ assert result.exit_code == 0
|
|
369 |
+ |
|
370 |
+ |
|
371 |
+# Test multiple element build shell
|
|
372 |
+@pytest.mark.integration
|
|
373 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
374 |
+def test_shell_multiple_workspace(cli, tmpdir, datafiles):
|
|
375 |
+ project = os.path.join(datafiles.dirname, datafiles.basename)
|
|
376 |
+ elements = {'workspace/workspace-mount.bst': os.path.join(cli.directory, 'workspace-mount'),
|
|
377 |
+ 'make/makehello.bst': os.path.join(cli.directory, 'makehello')}
|
|
378 |
+ |
|
379 |
+ for element, workspace in elements.items():
|
|
380 |
+ res = cli.run(project=project, args=['workspace', 'open', element, workspace])
|
|
381 |
+ assert res.exit_code == 0
|
|
382 |
+ |
|
383 |
+ for workspace in elements.values():
|
|
384 |
+ with open(os.path.join(workspace, "workspace-exists"), "w") as f:
|
|
385 |
+ pass
|
|
386 |
+ |
|
387 |
+ # Ensure the dependencies of our build failing element are built
|
|
388 |
+ result = cli.run(project=project, args=['build', 'base.bst'])
|
|
389 |
+ assert result.exit_code == 0
|
|
390 |
+ |
|
391 |
+ args = ['shell', '--build'] + ['-e' + e for e in elements]
|
|
392 |
+ args += ['--', 'sh', '-c',
|
|
393 |
+ 'test -e /buildstream/test/workspace/workspace-mount.bst/workspace-exists && \
|
|
394 |
+ test -e /buildstream/test/make/makehello.bst/workspace-exists']
|
|
395 |
+ result = cli.run(project=project, args=args)
|
|
396 |
+ assert result.exit_code == 0
|
|
397 |
+ assert result.output == ''
|