| ... | ... | @@ -28,11 +28,22 @@ DATA_DIR = os.path.join( | 
| 28 | 28 |  #    config (dict): A project.conf dictionary to composite over the default
 | 
| 29 | 29 |  #    mount (tuple): A (host, target) tuple for the `--mount` option
 | 
| 30 | 30 |  #    element (str): The element to build and run a shell with
 | 
|  | 31 | +#    elements (list): Other elements to build and run a shell with
 | 
| 31 | 32 |  #    isolate (bool): Whether to pass --isolate to `bst shell`
 | 
| 32 | 33 |  #
 | 
| 33 |  | -def execute_shell(cli, project, command, *, config=None, mount=None, element='base.bst', isolate=False):
 | 
|  | 34 | +def execute_shell(cli, project, command, *, config=None, mount=None, element=None, elements=None, isolate=False):
 | 
|  | 35 | +    assert element is None or elements is None, "Cannot mix single element and multi-element list options"
 | 
| 34 | 36 |      # Ensure the element is built
 | 
| 35 |  | -    result = cli.run(project=project, project_config=config, args=['build', element])
 | 
|  | 37 | +    if element is None and elements is None:
 | 
|  | 38 | +        element = 'base.bst'
 | 
|  | 39 | +    if elements is None:
 | 
|  | 40 | +        elements = []
 | 
|  | 41 | +
 | 
|  | 42 | +    args = ['build']
 | 
|  | 43 | +    args.extend(elements)
 | 
|  | 44 | +    if element is not None:
 | 
|  | 45 | +        args.append(element)
 | 
|  | 46 | +    result = cli.run(project=project, project_config=config, args=args)
 | 
| 36 | 47 |      assert result.exit_code == 0
 | 
| 37 | 48 |  
 | 
| 38 | 49 |      args = ['shell']
 | 
| ... | ... | @@ -41,7 +52,10 @@ def execute_shell(cli, project, command, *, config=None, mount=None, element='ba | 
| 41 | 52 |      if mount is not None:
 | 
| 42 | 53 |          host_path, target_path = mount
 | 
| 43 | 54 |          args += ['--mount', host_path, target_path]
 | 
| 44 |  | -    args += [element, '--'] + command
 | 
|  | 55 | +    args += ["-e" + e for e in elements]
 | 
|  | 56 | +    if element is not None:
 | 
|  | 57 | +        args.append(element)
 | 
|  | 58 | +    args += ['--'] + command
 | 
| 45 | 59 |  
 | 
| 46 | 60 |      return cli.run(project=project, project_config=config, args=args)
 | 
| 47 | 61 |  
 | 
| ... | ... | @@ -354,3 +368,45 @@ def test_integration_devices(cli, tmpdir, datafiles): | 
| 354 | 368 |  
 | 
| 355 | 369 |      result = execute_shell(cli, project, ["true"], element=element_name)
 | 
| 356 | 370 |      assert result.exit_code == 0
 | 
|  | 371 | +
 | 
|  | 372 | +
 | 
|  | 373 | +# Test multiple element shell
 | 
|  | 374 | +@pytest.mark.integration
 | 
|  | 375 | +@pytest.mark.datafiles(DATA_DIR)
 | 
|  | 376 | +@pytest.mark.skipif(IS_LINUX and not HAVE_BWRAP, reason='Only available with bubblewrap on Linux')
 | 
|  | 377 | +def test_shell_multiple_elements(cli, tmpdir, datafiles):
 | 
|  | 378 | +    project = os.path.join(datafiles.dirname, datafiles.basename)
 | 
|  | 379 | +
 | 
|  | 380 | +    result = execute_shell(cli, project, ["sh", "-c", "foo && bar"],
 | 
|  | 381 | +                           elements=["shell/adds-foo.bst", "shell/adds-bar.bst"])
 | 
|  | 382 | +    assert result.exit_code == 0
 | 
|  | 383 | +
 | 
|  | 384 | +
 | 
|  | 385 | +# Test multiple element build shell
 | 
|  | 386 | +@pytest.mark.integration
 | 
|  | 387 | +@pytest.mark.datafiles(DATA_DIR)
 | 
|  | 388 | +@pytest.mark.skipif(IS_LINUX and not HAVE_BWRAP, reason='Only available with bubblewrap on Linux')
 | 
|  | 389 | +def test_shell_multiple_workspace(cli, tmpdir, datafiles):
 | 
|  | 390 | +    project = os.path.join(datafiles.dirname, datafiles.basename)
 | 
|  | 391 | +    elements = {'workspace/workspace-mount.bst': os.path.join(cli.directory, 'workspace-mount'),
 | 
|  | 392 | +                'make/makehello.bst': os.path.join(cli.directory, 'makehello')}
 | 
|  | 393 | +
 | 
|  | 394 | +    for element, workspace in elements.items():
 | 
|  | 395 | +        res = cli.run(project=project, args=['workspace', 'open', element, '--directory', workspace])
 | 
|  | 396 | +        assert res.exit_code == 0
 | 
|  | 397 | +
 | 
|  | 398 | +    for workspace in elements.values():
 | 
|  | 399 | +        with open(os.path.join(workspace, "workspace-exists"), "w") as f:
 | 
|  | 400 | +            pass
 | 
|  | 401 | +
 | 
|  | 402 | +    # Ensure the dependencies of our build failing element are built
 | 
|  | 403 | +    result = cli.run(project=project, args=['build', 'base.bst'])
 | 
|  | 404 | +    assert result.exit_code == 0
 | 
|  | 405 | +
 | 
|  | 406 | +    args = ['shell', '--build'] + ['-e' + e for e in elements]
 | 
|  | 407 | +    args += ['--', 'sh', '-c',
 | 
|  | 408 | +             'test -e /buildstream/test/workspace/workspace-mount.bst/workspace-exists && \
 | 
|  | 409 | +              test -e /buildstream/test/make/makehello.bst/workspace-exists']
 | 
|  | 410 | +    result = cli.run(project=project, args=args)
 | 
|  | 411 | +    assert result.exit_code == 0
 | 
|  | 412 | +    assert result.output == '' |