diff options
author | Will Salmon <will.salmon@codethink.co.uk> | 2018-11-21 16:20:26 +0000 |
---|---|---|
committer | Will Salmon <will.salmon@codethink.co.uk> | 2018-11-21 16:20:26 +0000 |
commit | 4d6e2cd3aef77a4ffe697cb0cb475de79d1a7b42 (patch) | |
tree | 9b86ea4cb78bf0bc383548a8d5b7e76593e69a81 | |
parent | 58353aad0e603679fd55e2c42bd3bb463088854f (diff) | |
parent | 6612e70809bc8893376789f9342dffc155e8424b (diff) | |
download | buildstream-4d6e2cd3aef77a4ffe697cb0cb475de79d1a7b42.tar.gz |
Merge branch 'willsalmon/defaultWorkspaces' into 'master'
Updated Workspace CLI
See merge request BuildStream/buildstream!897
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | buildstream/_context.py | 7 | ||||
-rw-r--r-- | buildstream/_frontend/cli.py | 26 | ||||
-rw-r--r-- | buildstream/_stream.py | 129 | ||||
-rw-r--r-- | buildstream/data/userconfig.yaml | 3 | ||||
-rw-r--r-- | doc/sessions/developing.run | 4 | ||||
-rw-r--r-- | doc/sessions/junctions.run | 2 | ||||
-rw-r--r-- | tests/examples/developing.py | 4 | ||||
-rw-r--r-- | tests/examples/junctions.py | 2 | ||||
-rw-r--r-- | tests/frontend/buildcheckout.py | 2 | ||||
-rw-r--r-- | tests/frontend/cross_junction_workspace.py | 2 | ||||
-rw-r--r-- | tests/frontend/workspace.py | 291 | ||||
-rw-r--r-- | tests/integration/shell.py | 2 | ||||
-rw-r--r-- | tests/integration/workspace.py | 12 | ||||
-rw-r--r-- | tests/plugins/filter.py | 17 |
15 files changed, 371 insertions, 136 deletions
@@ -63,6 +63,10 @@ buildstream 1.3.1 o Added new `bst source-checkout` command to checkout sources of an element. + o `bst workspace open` now supports the creation of multiple elements and + allows the user to set a default location for their creation. This has meant + that the new CLI is no longer backwards compatible with buildstream 1.2. + ================= buildstream 1.1.5 diff --git a/buildstream/_context.py b/buildstream/_context.py index 7a47a30d3..e8342d101 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 @@ -177,10 +180,10 @@ class Context(): _yaml.node_validate(defaults, [ 'sourcedir', 'builddir', 'artifactdir', 'logdir', 'scheduler', 'artifacts', 'logging', 'projects', - 'cache', 'prompt' + 'cache', 'prompt', '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 92abd96e8..b1b4e03b0 100644 --- a/buildstream/_frontend/cli.py +++ b/buildstream/_frontend/cli.py @@ -707,31 +707,23 @@ 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), required=True) @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) - 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) - with app.initialized(): - app.stream.workspace_open(element, directory, + app.stream.workspace_open(elements, no_checkout=no_checkout, track_first=track_, - force=force) + force=force, + custom_dir=directory) ################################################################## diff --git a/buildstream/_stream.py b/buildstream/_stream.py index 97b47ebb0..76f1d67aa 100644 --- a/buildstream/_stream.py +++ b/buildstream/_stream.py @@ -464,44 +464,30 @@ 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 + # targets (list): List of target elements to open workspaces for # 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 + # custom_dir (str): Custom location to create a workspace or false to use default location. # - def workspace_open(self, target, directory, *, + def workspace_open(self, targets, *, no_checkout, track_first, - force): + force, + custom_dir): + # 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. # @@ -511,29 +497,88 @@ 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.") - - 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 = [] + # To try to be more atomic, loop through the elements and raise any errors we can early + for target in elements: + + 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("Element '{}' already has workspace 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 not custom_dir: + directory = os.path.abspath(os.path.join(self._context.workspacedir, target.name)) + if directory[-4:] == '.bst': + directory = directory[:-4] + expanded_directories.append(directory) + + if custom_dir: + if len(elements) != 1: + raise StreamError("Exactly one element can be given if --directory is used", + reason='directory-with-multiple-elements') + expanded_directories = [custom_dir, ] + else: + # If this fails it is a bug in what ever calls this, usually cli.py and so can not be tested for via the + # run bst test mechanism. + assert len(elements) == len(expanded_directories) + + for target, directory in zip(elements, expanded_directories): + if os.path.exists(directory): + if not os.path.isdir(directory): + raise StreamError("For element '{}', Directory path is not a directory: {}" + .format(target.name, directory), reason='bad-directory') + + if not (no_checkout or force) and os.listdir(directory): + raise StreamError("For element '{}', Directory path is not empty: {}" + .format(target.name, directory), reason='bad-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)) + + 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.create_workspace(target._get_full_name(), directory) + workspaces.create_workspace(target._get_full_name(), directory) - if not no_checkout: - with target.timed_activity("Staging sources to {}".format(directory)): - target._open_workspace() + if not no_checkout: + with target.timed_activity("Staging sources to {}".format(directory)): + target._open_workspace() - workspaces.save_config() - self._message(MessageType.INFO, "Saved workspace configuration") + # 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, "Created a workspace for element: {}" + .format(target._get_full_name())) # workspace_close # diff --git a/buildstream/data/userconfig.yaml b/buildstream/data/userconfig.yaml index dfc18545e..e81961c53 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/doc/sessions/developing.run b/doc/sessions/developing.run index 10beb2ad0..eca2af90b 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 --directory workspace_hello hello.bst # Catpure output from workspace list - directory: ../examples/developing/ @@ -37,7 +37,7 @@ commands: # Reopen workspace - directory: ../examples/developing/ output: ../source/sessions/developing-reopen-workspace.html - command: workspace open --no-checkout hello.bst workspace_hello + command: workspace open --no-checkout --directory workspace_hello hello.bst # Reset workspace - directory: ../examples/developing/ diff --git a/doc/sessions/junctions.run b/doc/sessions/junctions.run index 28ada6cf9..74c3a4f57 100644 --- a/doc/sessions/junctions.run +++ b/doc/sessions/junctions.run @@ -13,7 +13,7 @@ commands: # Open a crossJunction workspace: - directory: ../examples/junctions output: ../source/sessions/junctions-workspace-open.html - command: workspace open hello-junction.bst:hello.bst workspace_hello + command: workspace open --directory workspace_hello hello-junction.bst:hello.bst # Remove the workspace - directory: ../examples/junctions diff --git a/tests/examples/developing.py b/tests/examples/developing.py index 59bcdcd47..4bb7076c5 100644 --- a/tests/examples/developing.py +++ b/tests/examples/developing.py @@ -59,7 +59,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']) @@ -78,7 +78,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 022569c52..97c622bbd 100644 --- a/tests/examples/junctions.py +++ b/tests/examples/junctions.py @@ -48,7 +48,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 a0b461762..159af2d74 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 eb2bc2eb8..fb2b34c43 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 51b7d6088..bc928ad51 100644 --- a/tests/frontend/workspace.py +++ b/tests/frontend/workspace.py @@ -21,9 +21,11 @@ # Phillip Smyth <phillip.smyth@codethink.co.uk> # Jonathan Maw <jonathan.maw@codethink.co.uk> # Richard Maw <richard.maw@codethink.co.uk> +# William Salmon <will.salmon@codethink.co.uk> # import os +import stat import pytest import shutil import subprocess @@ -43,65 +45,120 @@ DATA_DIR = os.path.join( ) -def open_workspace(cli, tmpdir, datafiles, kind, track, suffix='', workspace_dir=None, - project_path=None, element_attrs=None): - if not workspace_dir: - workspace_dir = os.path.join(str(tmpdir), 'workspace{}'.format(suffix)) - if not project_path: - project_path = os.path.join(datafiles.dirname, datafiles.basename) - else: - shutil.copytree(os.path.join(datafiles.dirname, datafiles.basename), project_path) - bin_files_path = os.path.join(project_path, 'files', 'bin-files') - element_path = os.path.join(project_path, 'elements') - element_name = 'workspace-test-{}{}.bst'.format(kind, suffix) +class WorkspaceCreater(): + def __init__(self, cli, tmpdir, datafiles, project_path=None): + self.cli = cli + self.tmpdir = tmpdir + self.datafiles = datafiles + + if not project_path: + project_path = os.path.join(datafiles.dirname, datafiles.basename) + else: + shutil.copytree(os.path.join(datafiles.dirname, datafiles.basename), project_path) + + self.project_path = project_path + self.bin_files_path = os.path.join(project_path, 'files', 'bin-files') + + self.workspace_cmd = os.path.join(self.project_path, 'workspace_cmd') + + def create_workspace_element(self, kind, track, suffix='', workspace_dir=None, + element_attrs=None): + element_name = 'workspace-test-{}{}.bst'.format(kind, suffix) + element_path = os.path.join(self.project_path, 'elements') + if not workspace_dir: + workspace_dir = os.path.join(self.workspace_cmd, element_name) + if workspace_dir[-4:] == '.bst': + workspace_dir = workspace_dir[:-4] + + # Create our repo object of the given source type with + # the bin files, and then collect the initial ref. + repo = create_repo(kind, str(self.tmpdir)) + ref = repo.create(self.bin_files_path) + if track: + ref = None + + # Write out our test target + element = { + 'kind': 'import', + 'sources': [ + repo.source_config(ref=ref) + ] + } + if element_attrs: + element = {**element, **element_attrs} + _yaml.dump(element, + os.path.join(element_path, + element_name)) + return element_name, element_path, workspace_dir - # Create our repo object of the given source type with - # the bin files, and then collect the initial ref. - # - repo = create_repo(kind, str(tmpdir)) - ref = repo.create(bin_files_path) - if track: - ref = None + def create_workspace_elements(self, kinds, track, suffixs=None, workspace_dir_usr=None, + element_attrs=None): - # Write out our test target - element = { - 'kind': 'import', - 'sources': [ - repo.source_config(ref=ref) - ] - } - if element_attrs: - element = {**element, **element_attrs} - _yaml.dump(element, - os.path.join(element_path, - element_name)) + element_tuples = [] - # Assert that there is no reference, a track & fetch is needed - state = cli.get_element_state(project_path, element_name) - if track: - assert state == 'no reference' - else: - assert state == 'fetch needed' + if suffixs is None: + suffixs = ['', ] * len(kinds) + else: + if len(suffixs) != len(kinds): + raise "terable error" - # Now open the workspace, this should have the effect of automatically - # tracking & fetching the source from the repo. - args = ['workspace', 'open'] - if track: - args.append('--track') - args.extend([element_name, workspace_dir]) - result = cli.run(project=project_path, args=args) + for suffix, kind in zip(suffixs, kinds): + element_name, element_path, workspace_dir = \ + self.create_workspace_element(kind, track, suffix, workspace_dir_usr, + element_attrs) - result.assert_success() + # Assert that there is no reference, a track & fetch is needed + state = self.cli.get_element_state(self.project_path, element_name) + if track: + assert state == 'no reference' + else: + assert state == 'fetch needed' + element_tuples.append((element_name, workspace_dir)) - # Assert that we are now buildable because the source is - # now cached. - assert cli.get_element_state(project_path, element_name) == 'buildable' + return element_tuples - # Check that the executable hello file is found in the workspace - filename = os.path.join(workspace_dir, 'usr', 'bin', 'hello') - assert os.path.exists(filename) + def open_workspaces(self, kinds, track, suffixs=None, workspace_dir=None, + element_attrs=None): + + element_tuples = self.create_workspace_elements(kinds, track, suffixs, workspace_dir, + element_attrs) + os.makedirs(self.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'] + if track: + args.append('--track') + if workspace_dir is not None: + assert len(element_tuples) == 1, "test logic error" + _, workspace_dir = element_tuples[0] + args.extend(['--directory', workspace_dir]) + + args.extend([element_name for element_name, workspace_dir_suffix in element_tuples]) + result = self.cli.run(cwd=self.workspace_cmd, project=self.project_path, args=args) + + result.assert_success() + + for element_name, workspace_dir in element_tuples: + # Assert that we are now buildable because the source is + # now cached. + assert self.cli.get_element_state(self.project_path, element_name) == 'buildable' + + # Check that the executable hello file is found in the workspace + filename = os.path.join(workspace_dir, 'usr', 'bin', 'hello') + assert os.path.exists(filename) + + return element_tuples - return (element_name, project_path, workspace_dir) + +def open_workspace(cli, tmpdir, datafiles, kind, track, suffix='', workspace_dir=None, + project_path=None, element_attrs=None): + workspace_object = WorkspaceCreater(cli, tmpdir, datafiles, project_path) + workspaces = workspace_object.open_workspaces((kind, ), track, (suffix, ), workspace_dir, + element_attrs) + assert len(workspaces) == 1 + element_name, workspace = workspaces[0] + return element_name, workspace_object.project_path, workspace @pytest.mark.datafiles(DATA_DIR) @@ -129,6 +186,128 @@ def test_open_bzr_customize(cli, tmpdir, datafiles): @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.STREAM, 'directory-with-multiple-elements') + + +@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) +def test_open_defaultlocation_exists(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) + + with open(workspace_dir, 'w') as fl: + fl.write('foo') + + # 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_main_error(ErrorDomain.STREAM, 'bad-directory') + + +@pytest.mark.datafiles(DATA_DIR) @pytest.mark.parametrize("kind", repo_kinds) def test_open_track(cli, tmpdir, datafiles, kind): open_workspace(cli, tmpdir, datafiles, kind, True) @@ -150,7 +329,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() @@ -165,7 +344,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() @@ -196,7 +375,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 @@ -504,7 +683,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() @@ -766,7 +945,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 11c931513..68535bfdc 100644 --- a/tests/integration/shell.py +++ b/tests/integration/shell.py @@ -290,7 +290,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 e4f80ca74..0aeb4a3b2 100644 --- a/tests/integration/workspace.py +++ b/tests/integration/workspace.py @@ -24,7 +24,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]) @@ -41,7 +41,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]) @@ -78,7 +78,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 @@ -134,7 +134,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 @@ -210,7 +210,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 @@ -264,7 +264,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 559815a8b..6dae08544 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")) @@ -116,11 +116,20 @@ def test_filter_workspace_open(datafiles, cli, tmpdir): @pytest.mark.datafiles(os.path.join(DATA_DIR, 'basic')) +def test_filter_workspace_open_multi(datafiles, cli, tmpdir): + project = os.path.join(datafiles.dirname, datafiles.basename) + result = cli.run(cwd=project, project=project, args=['workspace', 'open', 'deps-permitted.bst', + 'output-orphans.bst']) + result.assert_success() + assert os.path.exists(os.path.join(project, "input")) + + +@pytest.mark.datafiles(os.path.join(DATA_DIR, 'basic')) 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 +147,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 +167,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") |