From f52ddfb40cd063e77722e435afcb0f4a3f565059 Mon Sep 17 00:00:00 2001 From: William Salmon <will.salmon@codethink.co.uk> Date: Fri, 2 Nov 2018 15:49:12 +0000 Subject: [PATCH] Workspace CLI update This is to update the workspace CLI to as agreed on the mailing list https://mail.gnome.org/archives/buildstream-list/2018-September/msg00046.html This patch also introduces the default workspace directory. --- buildstream/_context.py | 7 +- buildstream/_frontend/cli.py | 37 ++++--- buildstream/_stream.py | 105 ++++++++++++-------- buildstream/data/userconfig.yaml | 3 + buildstream/utils.py | 14 +++ doc/sessions/developing.run | 2 +- tests/examples/developing.py | 4 +- tests/examples/junctions.py | 2 +- tests/frontend/buildcheckout.py | 2 +- tests/frontend/cross_junction_workspace.py | 2 +- tests/frontend/workspace.py | 108 ++++++++++++++++++++- tests/integration/shell.py | 2 +- tests/integration/workspace.py | 12 +-- tests/plugins/filter.py | 8 +- 14 files changed, 230 insertions(+), 78 deletions(-) diff --git a/buildstream/_context.py b/buildstream/_context.py index 876b74712f..788c513b46 100644 --- a/buildstream/_context.py +++ b/buildstream/_context.py @@ -59,6 +59,9 @@ class Context(): # The directory where build sandboxes will be created self.builddir = None + # Default root location for workspaces + self.workspacedir = None + # The local binary artifact cache directory self.artifactdir = None @@ -160,10 +163,10 @@ class Context(): _yaml.node_validate(defaults, [ 'sourcedir', 'builddir', 'artifactdir', 'logdir', 'scheduler', 'artifacts', 'logging', 'projects', - 'cache' + 'cache', 'workspacedir', ]) - for directory in ['sourcedir', 'builddir', 'artifactdir', 'logdir']: + for directory in ['sourcedir', 'builddir', 'artifactdir', 'logdir', 'workspacedir']: # Allow the ~ tilde expansion and any environment variables in # path specification in the config files. # diff --git a/buildstream/_frontend/cli.py b/buildstream/_frontend/cli.py index 85632959fe..3e796fe009 100644 --- a/buildstream/_frontend/cli.py +++ b/buildstream/_frontend/cli.py @@ -6,6 +6,7 @@ from .. import _yaml from .._exceptions import BstError, LoadError, AppError from .._versions import BST_FORMAT_VERSION from .complete import main_bashcomplete, complete_path, CompleteUnhandled +from ..utils import DirectoryDescription ################################################################## @@ -678,28 +679,36 @@ def workspace(): @click.option('--no-checkout', default=False, is_flag=True, help="Do not checkout the source, only link to the given directory") @click.option('--force', '-f', default=False, is_flag=True, - help="Overwrite files existing in checkout directory") + help="The workspace will be created even if the directory in which it will be created is not empty " + + "or if a workspace for that element already exists") @click.option('--track', 'track_', default=False, is_flag=True, help="Track and fetch new source references before checking out the workspace") -@click.argument('element', - type=click.Path(readable=False)) -@click.argument('directory', type=click.Path(file_okay=False)) +@click.option('--directory', type=click.Path(file_okay=False), default=None, + help="Only for use when a single Element is given: Set the directory to use to create the workspace") +@click.argument('elements', nargs=-1, type=click.Path(readable=False)) @click.pass_obj -def workspace_open(app, no_checkout, force, track_, element, directory): +def workspace_open(app, no_checkout, force, track_, directory, elements): """Open a workspace for manual source modification""" - - if os.path.exists(directory): - - if not os.path.isdir(directory): - click.echo("Checkout directory is not a directory: {}".format(directory), err=True) + directories = [] + if directory is not None: + if len(elements) > 1: + click.echo("Directory option can only be used if a single element is given", err=True) sys.exit(-1) + if os.path.exists(directory): + if not os.path.isdir(directory): + click.echo("Directory path is not a directory: {}".format(directory), err=True) + sys.exit(-1) - if not (no_checkout or force) and os.listdir(directory): - click.echo("Checkout directory is not empty: {}".format(directory), err=True) - sys.exit(-1) + if not (no_checkout or force) and os.listdir(directory): + click.echo("Directory path is not empty: {}".format(directory), err=True) + sys.exit(-1) + directories.append(DirectoryDescription(directory, use_default=False)) + else: + for element in elements: + directories.append(DirectoryDescription(element.rstrip('.bst'))) with app.initialized(): - app.stream.workspace_open(element, directory, + app.stream.workspace_open(elements, directories, no_checkout=no_checkout, track_first=track_, force=force) diff --git a/buildstream/_stream.py b/buildstream/_stream.py index 6e2e8b25b2..d0f9a56b98 100644 --- a/buildstream/_stream.py +++ b/buildstream/_stream.py @@ -448,44 +448,29 @@ class Stream(): # Open a project workspace # # Args: - # target (str): The target element to open the workspace for - # directory (str): The directory to stage the source in + # target (list): List of target elements to open workspaces for + # directory (list): List of DirectoryDescription objects to stage the source in # no_checkout (bool): Whether to skip checking out the source # track_first (bool): Whether to track and fetch first # force (bool): Whether to ignore contents in an existing directory # - def workspace_open(self, target, directory, *, + def workspace_open(self, targets, directories, *, no_checkout, track_first, force): + # This function is a little funny but it is trying to be as atomic as possible. if track_first: - track_targets = (target,) + track_targets = targets else: track_targets = () - elements, track_elements = self._load((target,), track_targets, + elements, track_elements = self._load(targets, track_targets, selection=PipelineSelection.REDIRECT, track_selection=PipelineSelection.REDIRECT) - target = elements[0] - directory = os.path.abspath(directory) - - if not list(target.sources()): - build_depends = [x.name for x in target.dependencies(Scope.BUILD, recurse=False)] - if not build_depends: - raise StreamError("The given element has no sources") - detail = "Try opening a workspace on one of its dependencies instead:\n" - detail += " \n".join(build_depends) - raise StreamError("The given element has no sources", detail=detail) workspaces = self._context.get_workspaces() - # Check for workspace config - workspace = workspaces.get_workspace(target._get_full_name()) - if workspace and not force: - raise StreamError("Workspace '{}' is already defined at: {}" - .format(target.name, workspace.get_absolute_path())) - # If we're going to checkout, we need at least a fetch, # if we were asked to track first, we're going to fetch anyway. # @@ -495,29 +480,69 @@ class Stream(): track_elements = elements self._fetch(elements, track_elements=track_elements) - if not no_checkout and target._get_consistency() != Consistency.CACHED: - raise StreamError("Could not stage uncached source. " + - "Use `--track` to track and " + - "fetch the latest version of the " + - "source.") + expanded_directories = [] + # To try to be more atomic, loop through the elements and raise any errors we can early + for target, directory_obj in zip(elements, directories): + + if not list(target.sources()): + build_depends = [x.name for x in target.dependencies(Scope.BUILD, recurse=False)] + if not build_depends: + raise StreamError("The element {} has no sources".format(target.name)) + detail = "Try opening a workspace on one of its dependencies instead:\n" + detail += " \n".join(build_depends) + raise StreamError("The element {} has no sources".format(target.name), detail=detail) + + # Check for workspace config + workspace = workspaces.get_workspace(target._get_full_name()) + if workspace and not force: + raise StreamError("Workspace '{}' is already defined at: {}" + .format(target.name, workspace.get_absolute_path())) + + if not no_checkout and target._get_consistency() != Consistency.CACHED: + raise StreamError("Could not stage uncached source. For {} ".format(target.name) + + "Use `--track` to track and " + + "fetch the latest version of the " + + "source.") + + if directory_obj.use_default: + directory = os.path.abspath(os.path.join(self._context.workspacedir, directory_obj.directory)) + else: + directory = directory_obj.directory - if workspace: - workspaces.delete_workspace(target._get_full_name()) - workspaces.save_config() - shutil.rmtree(directory) - try: - os.makedirs(directory, exist_ok=True) - except OSError as e: - raise StreamError("Failed to create workspace directory: {}".format(e)) from e + expanded_directories.append(directory) - workspaces.create_workspace(target._get_full_name(), directory) + # So far this function has tried to catch as many issues as possible with out making any changes + # Now it dose the bits that can not be made atomic. + targetGenerator = zip(elements, expanded_directories) + for target, directory in targetGenerator: + self._message(MessageType.INFO, "Creating workspace for element {}" + .format(target.name)) - if not no_checkout: - with target.timed_activity("Staging sources to {}".format(directory)): - target._open_workspace() + workspace = workspaces.get_workspace(target._get_full_name()) + if workspace: + workspaces.delete_workspace(target._get_full_name()) + workspaces.save_config() + shutil.rmtree(directory) + try: + os.makedirs(directory, exist_ok=True) + except OSError as e: + todo_elements = " ".join([str(target.name) for target, directory_dict in targetGenerator]) + if todo_elements: + # This output should make creating the remaining workspaces as easy as possible. + todo_elements = "\nDid not try to create workspaces for " + todo_elements + raise StreamError("Failed to create workspace directory: {}".format(e) + todo_elements) from e - workspaces.save_config() - self._message(MessageType.INFO, "Saved workspace configuration") + workspaces.create_workspace(target._get_full_name(), directory) + + if not no_checkout: + with target.timed_activity("Staging sources to {}".format(directory)): + target._open_workspace() + + # Saving the workspace once it is set up means that if the next workspace fails to be created before + # the configuration gets saved. The successfully created workspace still gets saved. + workspaces.save_config() + self._message(MessageType.INFO, "Added element {} to the workspace configuration" + .format(target._get_full_name())) # workspace_close # diff --git a/buildstream/data/userconfig.yaml b/buildstream/data/userconfig.yaml index efe419cfc6..b111525675 100644 --- a/buildstream/data/userconfig.yaml +++ b/buildstream/data/userconfig.yaml @@ -22,6 +22,9 @@ artifactdir: ${XDG_CACHE_HOME}/buildstream/artifacts # Location to store build logs logdir: ${XDG_CACHE_HOME}/buildstream/logs +# Default root location for workspaces, blank for no default set. +workspacedir: . + # # Cache # diff --git a/buildstream/utils.py b/buildstream/utils.py index dc66f3e623..81d1622fb2 100644 --- a/buildstream/utils.py +++ b/buildstream/utils.py @@ -105,6 +105,20 @@ class FileListResult(): return ret +class DirectoryDescription(): + """ + This object is used to keep information about directories in a nice tidy object. + """ + def __init__(self, directory, *, use_default=True): + """ + Args: + directory (str): The path to the directory this object describes + use_default (bool): Weather to process the directory so it is in the default folder. + """ + self.directory = directory + self.use_default = use_default + + def list_relative_paths(directory, *, list_dirs=True): """A generator for walking directory relative paths diff --git a/doc/sessions/developing.run b/doc/sessions/developing.run index 10beb2ad03..55d9a3a6a8 100644 --- a/doc/sessions/developing.run +++ b/doc/sessions/developing.run @@ -7,7 +7,7 @@ commands: # Capture workspace open output - directory: ../examples/developing/ output: ../source/sessions/developing-workspace-open.html - command: workspace open hello.bst workspace_hello + command: workspace open hello.bst --directory workspace_hello # Catpure output from workspace list - directory: ../examples/developing/ diff --git a/tests/examples/developing.py b/tests/examples/developing.py index bca6ac61d7..d598290373 100644 --- a/tests/examples/developing.py +++ b/tests/examples/developing.py @@ -55,7 +55,7 @@ def test_open_workspace(cli, tmpdir, datafiles): project = os.path.join(datafiles.dirname, datafiles.basename) workspace_dir = os.path.join(str(tmpdir), "workspace_hello") - result = cli.run(project=project, args=['workspace', 'open', '-f', 'hello.bst', workspace_dir]) + result = cli.run(project=project, args=['workspace', 'open', '-f', '--directory', workspace_dir, 'hello.bst', ]) result.assert_success() result = cli.run(project=project, args=['workspace', 'list']) @@ -72,7 +72,7 @@ def test_make_change_in_workspace(cli, tmpdir, datafiles): project = os.path.join(datafiles.dirname, datafiles.basename) workspace_dir = os.path.join(str(tmpdir), "workspace_hello") - result = cli.run(project=project, args=['workspace', 'open', '-f', 'hello.bst', workspace_dir]) + result = cli.run(project=project, args=['workspace', 'open', '-f', '--directory', workspace_dir, 'hello.bst']) result.assert_success() result = cli.run(project=project, args=['workspace', 'list']) diff --git a/tests/examples/junctions.py b/tests/examples/junctions.py index d2a6538847..bcb4177ad8 100644 --- a/tests/examples/junctions.py +++ b/tests/examples/junctions.py @@ -44,7 +44,7 @@ def test_open_cross_junction_workspace(cli, tmpdir, datafiles): workspace_dir = os.path.join(str(tmpdir), "workspace_hello_junction") result = cli.run(project=project, - args=['workspace', 'open', 'hello-junction.bst:hello.bst', workspace_dir]) + args=['workspace', 'open', '--directory', workspace_dir, 'hello-junction.bst:hello.bst']) result.assert_success() result = cli.run(project=project, diff --git a/tests/frontend/buildcheckout.py b/tests/frontend/buildcheckout.py index a0b4617624..159af2d744 100644 --- a/tests/frontend/buildcheckout.py +++ b/tests/frontend/buildcheckout.py @@ -509,7 +509,7 @@ def test_build_checkout_workspaced_junction(cli, tmpdir, datafiles): # Now open a workspace on the junction # - result = cli.run(project=project, args=['workspace', 'open', 'junction.bst', workspace]) + result = cli.run(project=project, args=['workspace', 'open', '--directory', workspace, 'junction.bst']) result.assert_success() filename = os.path.join(workspace, 'files', 'etc-files', 'etc', 'animal.conf') diff --git a/tests/frontend/cross_junction_workspace.py b/tests/frontend/cross_junction_workspace.py index eb2bc2eb8b..fb2b34c434 100644 --- a/tests/frontend/cross_junction_workspace.py +++ b/tests/frontend/cross_junction_workspace.py @@ -47,7 +47,7 @@ def open_cross_junction(cli, tmpdir): workspace = tmpdir.join("workspace") element = 'sub.bst:data.bst' - args = ['workspace', 'open', element, str(workspace)] + args = ['workspace', 'open', '--directory', str(workspace), element] result = cli.run(project=project, args=args) result.assert_success() diff --git a/tests/frontend/workspace.py b/tests/frontend/workspace.py index f620d4c133..62653a8b63 100644 --- a/tests/frontend/workspace.py +++ b/tests/frontend/workspace.py @@ -25,6 +25,7 @@ # import os +import stat import pytest import shutil import subprocess @@ -182,6 +183,103 @@ def test_open_bzr_customize(cli, tmpdir, datafiles): assert(expected_output_str in str(output)) +@pytest.mark.datafiles(DATA_DIR) +def test_open_multi(cli, tmpdir, datafiles): + + workspace_object = WorkspaceCreater(cli, tmpdir, datafiles) + workspaces = workspace_object.open_workspaces(repo_kinds, False) + + for (elname, workspace), kind in zip(workspaces, repo_kinds): + assert kind in elname + workspace_lsdir = os.listdir(workspace) + if kind == 'git': + assert('.git' in workspace_lsdir) + elif kind == 'bzr': + assert('.bzr' in workspace_lsdir) + else: + assert not ('.git' in workspace_lsdir) + assert not ('.bzr' in workspace_lsdir) + + +@pytest.mark.datafiles(DATA_DIR) +def test_open_multi_unwritable(cli, tmpdir, datafiles): + workspace_object = WorkspaceCreater(cli, tmpdir, datafiles) + + element_tuples = workspace_object.create_workspace_elements(repo_kinds, False, repo_kinds) + os.makedirs(workspace_object.workspace_cmd, exist_ok=True) + + # Now open the workspace, this should have the effect of automatically + # tracking & fetching the source from the repo. + args = ['workspace', 'open'] + args.extend([element_name for element_name, workspace_dir_suffix in element_tuples]) + cli.configure({'workspacedir': workspace_object.workspace_cmd}) + + cwdstat = os.stat(workspace_object.workspace_cmd) + try: + os.chmod(workspace_object.workspace_cmd, cwdstat.st_mode - stat.S_IWRITE) + result = workspace_object.cli.run(project=workspace_object.project_path, args=args) + finally: + # Using this finally to make sure we always put thing back how they should be. + os.chmod(workspace_object.workspace_cmd, cwdstat.st_mode) + + result.assert_main_error(ErrorDomain.STREAM, None) + # Normally we avoid checking stderr in favour of using the mechine readable result.assert_main_error + # But Tristan was very keen that the names of the elements left needing workspaces were present in the out put + assert (" ".join([element_name for element_name, workspace_dir_suffix in element_tuples[1:]]) in result.stderr) + + +@pytest.mark.datafiles(DATA_DIR) +def test_open_multi_with_directory(cli, tmpdir, datafiles): + workspace_object = WorkspaceCreater(cli, tmpdir, datafiles) + + element_tuples = workspace_object.create_workspace_elements(repo_kinds, False, repo_kinds) + os.makedirs(workspace_object.workspace_cmd, exist_ok=True) + + # Now open the workspace, this should have the effect of automatically + # tracking & fetching the source from the repo. + args = ['workspace', 'open'] + args.extend(['--directory', 'any/dir/should/fail']) + + args.extend([element_name for element_name, workspace_dir_suffix in element_tuples]) + result = workspace_object.cli.run(cwd=workspace_object.workspace_cmd, project=workspace_object.project_path, + args=args) + + result.assert_main_error(ErrorDomain.CAS, None) + assert ("Directory option can only be used if a single element is given" in result.stderr) + + +@pytest.mark.datafiles(DATA_DIR) +def test_open_defaultlocation(cli, tmpdir, datafiles): + workspace_object = WorkspaceCreater(cli, tmpdir, datafiles) + + ((element_name, workspace_dir), ) = workspace_object.create_workspace_elements(['git'], False, ['git']) + os.makedirs(workspace_object.workspace_cmd, exist_ok=True) + + # Now open the workspace, this should have the effect of automatically + # tracking & fetching the source from the repo. + args = ['workspace', 'open'] + args.append(element_name) + + # In the other tests we set the cmd to workspace_object.workspace_cmd with the optional + # argument, cwd for the workspace_object.cli.run function. But hear we set the default + # workspace location to workspace_object.workspace_cmd and run the cli.run function with + # no cwd option so that it runs in the project directory. + cli.configure({'workspacedir': workspace_object.workspace_cmd}) + result = workspace_object.cli.run(project=workspace_object.project_path, + args=args) + + result.assert_success() + + assert cli.get_element_state(workspace_object.project_path, element_name) == 'buildable' + + # Check that the executable hello file is found in the workspace + # even though the cli.run function was not run with cwd = workspace_object.workspace_cmd + # the workspace should be created in there as we used the 'workspacedir' configuration + # option. + filename = os.path.join(workspace_dir, 'usr', 'bin', 'hello') + assert os.path.exists(filename) + + @pytest.mark.datafiles(DATA_DIR) @pytest.mark.parametrize("kind", repo_kinds) def test_open_track(cli, tmpdir, datafiles, kind): @@ -204,7 +302,7 @@ def test_open_force(cli, tmpdir, datafiles, kind): # Now open the workspace again with --force, this should happily succeed result = cli.run(project=project, args=[ - 'workspace', 'open', '--force', element_name, workspace + 'workspace', 'open', '--force', '--directory', workspace, element_name ]) result.assert_success() @@ -219,7 +317,7 @@ def test_open_force_open(cli, tmpdir, datafiles, kind): # Now open the workspace again with --force, this should happily succeed result = cli.run(project=project, args=[ - 'workspace', 'open', '--force', element_name, workspace + 'workspace', 'open', '--force', '--directory', workspace, element_name ]) result.assert_success() @@ -250,7 +348,7 @@ def test_open_force_different_workspace(cli, tmpdir, datafiles, kind): # Now open the workspace again with --force, this should happily succeed result = cli.run(project=project, args=[ - 'workspace', 'open', '--force', element_name2, workspace + 'workspace', 'open', '--force', '--directory', workspace, element_name2 ]) # Assert that the file in workspace 1 has been replaced @@ -558,7 +656,7 @@ def test_buildable_no_ref(cli, tmpdir, datafiles): # Now open the workspace. We don't need to checkout the source though. workspace = os.path.join(str(tmpdir), 'workspace-no-ref') os.makedirs(workspace) - args = ['workspace', 'open', '--no-checkout', element_name, workspace] + args = ['workspace', 'open', '--no-checkout', '--directory', workspace, element_name] result = cli.run(project=project, args=args) result.assert_success() @@ -820,7 +918,7 @@ def test_list_supported_workspace(cli, tmpdir, datafiles, workspace_cfg, expecte element_name)) # Make a change to the workspaces file - result = cli.run(project=project, args=['workspace', 'open', element_name, workspace]) + result = cli.run(project=project, args=['workspace', 'open', '--directory', workspace, element_name]) result.assert_success() result = cli.run(project=project, args=['workspace', 'close', '--remove-dir', element_name]) result.assert_success() diff --git a/tests/integration/shell.py b/tests/integration/shell.py index 1db29a0c44..047569f2d0 100644 --- a/tests/integration/shell.py +++ b/tests/integration/shell.py @@ -278,7 +278,7 @@ def test_workspace_visible(cli, tmpdir, datafiles): # Open a workspace on our build failing element # - res = cli.run(project=project, args=['workspace', 'open', element_name, workspace]) + res = cli.run(project=project, args=['workspace', 'open', '--directory', workspace, element_name]) assert res.exit_code == 0 # Ensure the dependencies of our build failing element are built diff --git a/tests/integration/workspace.py b/tests/integration/workspace.py index bcbcd674bf..4418510627 100644 --- a/tests/integration/workspace.py +++ b/tests/integration/workspace.py @@ -23,7 +23,7 @@ def test_workspace_mount(cli, tmpdir, datafiles): workspace = os.path.join(cli.directory, 'workspace') element_name = 'workspace/workspace-mount.bst' - res = cli.run(project=project, args=['workspace', 'open', element_name, workspace]) + res = cli.run(project=project, args=['workspace', 'open', '--directory', workspace, element_name]) assert res.exit_code == 0 res = cli.run(project=project, args=['build', element_name]) @@ -39,7 +39,7 @@ def test_workspace_commanddir(cli, tmpdir, datafiles): workspace = os.path.join(cli.directory, 'workspace') element_name = 'workspace/workspace-commanddir.bst' - res = cli.run(project=project, args=['workspace', 'open', element_name, workspace]) + res = cli.run(project=project, args=['workspace', 'open', '--directory', workspace, element_name]) assert res.exit_code == 0 res = cli.run(project=project, args=['build', element_name]) @@ -75,7 +75,7 @@ def test_workspace_updated_dependency(cli, tmpdir, datafiles): _yaml.dump(dependency, os.path.join(element_path, dep_name)) # First open the workspace - res = cli.run(project=project, args=['workspace', 'open', element_name, workspace]) + res = cli.run(project=project, args=['workspace', 'open', '--directory', workspace, element_name]) assert res.exit_code == 0 # We build the workspaced element, so that we have an artifact @@ -130,7 +130,7 @@ def test_workspace_update_dependency_failed(cli, tmpdir, datafiles): _yaml.dump(dependency, os.path.join(element_path, dep_name)) # First open the workspace - res = cli.run(project=project, args=['workspace', 'open', element_name, workspace]) + res = cli.run(project=project, args=['workspace', 'open', '--directory', workspace, element_name]) assert res.exit_code == 0 # We build the workspaced element, so that we have an artifact @@ -205,7 +205,7 @@ def test_updated_dependency_nested(cli, tmpdir, datafiles): _yaml.dump(dependency, os.path.join(element_path, dep_name)) # First open the workspace - res = cli.run(project=project, args=['workspace', 'open', element_name, workspace]) + res = cli.run(project=project, args=['workspace', 'open', '--directory', workspace, element_name]) assert res.exit_code == 0 # We build the workspaced element, so that we have an artifact @@ -258,7 +258,7 @@ def test_incremental_configure_commands_run_only_once(cli, tmpdir, datafiles): _yaml.dump(element, os.path.join(element_path, element_name)) # We open a workspace on the above element - res = cli.run(project=project, args=['workspace', 'open', element_name, workspace]) + res = cli.run(project=project, args=['workspace', 'open', '--directory', workspace, element_name]) res.assert_success() # Then we build, and check whether the configure step succeeded diff --git a/tests/plugins/filter.py b/tests/plugins/filter.py index 559815a8b3..cec7fa3f92 100644 --- a/tests/plugins/filter.py +++ b/tests/plugins/filter.py @@ -108,7 +108,7 @@ def test_filter_forbid_also_rdep(datafiles, cli): def test_filter_workspace_open(datafiles, cli, tmpdir): project = os.path.join(datafiles.dirname, datafiles.basename) workspace_dir = os.path.join(tmpdir.dirname, tmpdir.basename, "workspace") - result = cli.run(project=project, args=['workspace', 'open', 'deps-permitted.bst', workspace_dir]) + result = cli.run(project=project, args=['workspace', 'open', '--directory', workspace_dir, 'deps-permitted.bst']) result.assert_success() assert os.path.exists(os.path.join(workspace_dir, "foo")) assert os.path.exists(os.path.join(workspace_dir, "bar")) @@ -120,7 +120,7 @@ def test_filter_workspace_build(datafiles, cli, tmpdir): project = os.path.join(datafiles.dirname, datafiles.basename) tempdir = os.path.join(tmpdir.dirname, tmpdir.basename) workspace_dir = os.path.join(tempdir, "workspace") - result = cli.run(project=project, args=['workspace', 'open', 'output-orphans.bst', workspace_dir]) + result = cli.run(project=project, args=['workspace', 'open', '--directory', workspace_dir, 'output-orphans.bst']) result.assert_success() src = os.path.join(workspace_dir, "foo") dst = os.path.join(workspace_dir, "quux") @@ -138,7 +138,7 @@ def test_filter_workspace_close(datafiles, cli, tmpdir): project = os.path.join(datafiles.dirname, datafiles.basename) tempdir = os.path.join(tmpdir.dirname, tmpdir.basename) workspace_dir = os.path.join(tempdir, "workspace") - result = cli.run(project=project, args=['workspace', 'open', 'output-orphans.bst', workspace_dir]) + result = cli.run(project=project, args=['workspace', 'open', '--directory', workspace_dir, 'output-orphans.bst']) result.assert_success() src = os.path.join(workspace_dir, "foo") dst = os.path.join(workspace_dir, "quux") @@ -158,7 +158,7 @@ def test_filter_workspace_reset(datafiles, cli, tmpdir): project = os.path.join(datafiles.dirname, datafiles.basename) tempdir = os.path.join(tmpdir.dirname, tmpdir.basename) workspace_dir = os.path.join(tempdir, "workspace") - result = cli.run(project=project, args=['workspace', 'open', 'output-orphans.bst', workspace_dir]) + result = cli.run(project=project, args=['workspace', 'open', '--directory', workspace_dir, 'output-orphans.bst']) result.assert_success() src = os.path.join(workspace_dir, "foo") dst = os.path.join(workspace_dir, "quux") -- GitLab