diff options
author | Tom Pollard <tom.pollard@codethink.co.uk> | 2019-01-30 16:18:17 +0000 |
---|---|---|
committer | Tom Pollard <tom.pollard@codethink.co.uk> | 2019-02-05 11:22:01 +0000 |
commit | cd8e5e272fef36358f1e36885d7db69ee5f97dc2 (patch) | |
tree | c612a1a7f47b82399c3ddabdbf2b10694f80aa0a | |
parent | 3ab096510186842afb90c16a1c1bb7e58035265f (diff) | |
download | buildstream-cd8e5e272fef36358f1e36885d7db69ee5f97dc2.tar.gz |
Add --remote, -r option to bst build, inline with pull & push
Providing a remote will limit build's pull/push remote actions to
the given remote specifically, ignoring those defined via user or
project configuration.
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | buildstream/_frontend/cli.py | 9 | ||||
-rw-r--r-- | buildstream/_stream.py | 14 | ||||
-rw-r--r-- | tests/frontend/completions.py | 3 | ||||
-rw-r--r-- | tests/frontend/pull.py | 53 | ||||
-rw-r--r-- | tests/frontend/push.py | 30 |
6 files changed, 107 insertions, 6 deletions
@@ -122,6 +122,10 @@ buildstream 1.3.1 'shell', 'show', 'source-checkout', 'track', 'workspace close' and 'workspace reset' commands are affected. + o bst 'build' now has '--remote, -r' option, inline with bst 'push' & 'pull'. + Providing a remote will limit build's pull/push remote actions to the given + remote specifically, ignoring those defined via user or project configuration. + ================= buildstream 1.1.5 diff --git a/buildstream/_frontend/cli.py b/buildstream/_frontend/cli.py index 163a05790..49d5717b4 100644 --- a/buildstream/_frontend/cli.py +++ b/buildstream/_frontend/cli.py @@ -338,10 +338,12 @@ def init(app, project_name, format_version, element_path, force): help="Allow tracking to cross junction boundaries") @click.option('--track-save', default=False, is_flag=True, help="Deprecated: This is ignored") +@click.option('--remote', '-r', default=None, + help="The URL of the remote cache (defaults to the first configured cache)") @click.argument('elements', nargs=-1, type=click.Path(readable=False)) @click.pass_obj -def build(app, elements, all_, track_, track_save, track_all, track_except, track_cross_junctions): +def build(app, elements, all_, track_, track_save, track_all, track_except, track_cross_junctions, remote): """Build elements in a pipeline Specifying no elements will result in building the default targets @@ -376,7 +378,8 @@ def build(app, elements, all_, track_, track_save, track_all, track_except, trac track_except=track_except, track_cross_junctions=track_cross_junctions, ignore_junction_targets=ignore_junction_targets, - build_all=all_) + build_all=all_, + remote=remote) ################################################################## @@ -1012,7 +1015,7 @@ def artifact_checkout(app, force, deps, integrate, hardlinks, tar, directory, el @click.option('--deps', '-d', default='none', type=click.Choice(['none', 'all']), help='The dependency artifacts to pull (default: none)') -@click.option('--remote', '-r', +@click.option('--remote', '-r', default=None, help="The URL of the remote cache (defaults to the first configured cache)") @click.argument('elements', nargs=-1, type=click.Path(readable=False)) diff --git a/buildstream/_stream.py b/buildstream/_stream.py index af736c96a..588780558 100644 --- a/buildstream/_stream.py +++ b/buildstream/_stream.py @@ -197,26 +197,36 @@ class Stream(): # ignore_junction_targets (bool): Whether junction targets should be filtered out # build_all (bool): Whether to build all elements, or only those # which are required to build the target. + # remote (str): The URL of a specific remote server to push to, or None + # + # If `remote` specified as None, then regular configuration will be used + # to determine where to push artifacts to. # def build(self, targets, *, track_targets=None, track_except=None, track_cross_junctions=False, ignore_junction_targets=False, - build_all=False): + build_all=False, + remote=None): if build_all: selection = PipelineSelection.ALL else: selection = PipelineSelection.PLAN + use_config = True + if remote: + use_config = False + elements, track_elements = \ self._load(targets, track_targets, selection=selection, track_selection=PipelineSelection.ALL, track_except_targets=track_except, track_cross_junctions=track_cross_junctions, ignore_junction_targets=ignore_junction_targets, - use_artifact_config=True, + use_artifact_config=use_config, + artifact_remote_url=remote, fetch_subprojects=True, dynamic_plan=True) diff --git a/tests/frontend/completions.py b/tests/frontend/completions.py index 007064f89..93b908f60 100644 --- a/tests/frontend/completions.py +++ b/tests/frontend/completions.py @@ -141,7 +141,8 @@ def test_commands(cli, cmd, word_idx, expected): ('bst --no-colors build -', 3, ['--all ', '--track ', '--track-all ', '--track-except ', '--track-cross-junctions ', '-J ', - '--track-save ']), + '--track-save ', + '--remote ', '-r ']), # Test the behavior of completing after an option that has a # parameter that cannot be completed, vs an option that has diff --git a/tests/frontend/pull.py b/tests/frontend/pull.py index 20b740948..a2c710fb8 100644 --- a/tests/frontend/pull.py +++ b/tests/frontend/pull.py @@ -408,3 +408,56 @@ def test_pull_missing_notifies_user(caplog, cli, tmpdir, datafiles): assert "INFO Remote ({}) does not have".format(share.repo) in result.stderr assert "SKIPPED Pull" in result.stderr + + +@pytest.mark.datafiles(DATA_DIR) +def test_build_remote_option(caplog, cli, tmpdir, datafiles): + project = os.path.join(datafiles.dirname, datafiles.basename) + caplog.set_level(1) + + with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare1')) as shareuser,\ + create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2')) as shareproject,\ + create_artifact_share(os.path.join(str(tmpdir), 'artifactshare3')) as sharecli: + + # Add shareproject repo url to project.conf + with open(os.path.join(project, "project.conf"), "a") as projconf: + projconf.write("artifacts:\n url: {}\n push: True".format(shareproject.repo)) + + # Configure shareuser remote in user conf + cli.configure({ + 'artifacts': {'url': shareuser.repo, 'push': True} + }) + + # Push the artifacts to the shareuser and shareproject remotes. + # Assert that shareuser and shareproject have the artfifacts cached, + # but sharecli doesn't, then delete locally cached elements + result = cli.run(project=project, args=['build', 'target.bst']) + result.assert_success() + all_elements = ['target.bst', 'import-bin.bst', 'compose-all.bst'] + for element_name in all_elements: + assert element_name in result.get_pushed_elements() + assert_not_shared(cli, sharecli, project, element_name) + assert_shared(cli, shareuser, project, element_name) + assert_shared(cli, shareproject, project, element_name) + cli.remove_artifact_from_cache(project, element_name) + + # Now check that a build with cli set as sharecli results in nothing being pulled, + # as it doesn't have them cached and shareuser/shareproject should be ignored. This + # will however result in the artifacts being built and pushed to it + result = cli.run(project=project, args=['build', '--remote', sharecli.repo, 'target.bst']) + result.assert_success() + for element_name in all_elements: + assert element_name not in result.get_pulled_elements() + assert_shared(cli, sharecli, project, element_name) + cli.remove_artifact_from_cache(project, element_name) + + # Now check that a clean build with cli set as sharecli should result in artifacts only + # being pulled from it, as that was provided via the cli and is populated + result = cli.run(project=project, args=['build', '--remote', sharecli.repo, 'target.bst']) + result.assert_success() + for element_name in all_elements: + assert cli.get_element_state(project, element_name) == 'cached' + assert element_name in result.get_pulled_elements() + assert shareproject.repo not in result.stderr + assert shareuser.repo not in result.stderr + assert sharecli.repo in result.stderr diff --git a/tests/frontend/push.py b/tests/frontend/push.py index f3f9b52f1..729df9ae9 100644 --- a/tests/frontend/push.py +++ b/tests/frontend/push.py @@ -416,3 +416,33 @@ def test_push_already_cached(caplog, cli, tmpdir, datafiles): assert not result.get_pushed_elements(), "No elements should have been pushed since the cache was populated" assert "INFO Remote ({}) already has ".format(share.repo) in result.stderr assert "SKIPPED Push" in result.stderr + + +@pytest.mark.datafiles(DATA_DIR) +def test_build_remote_option(caplog, cli, tmpdir, datafiles): + project = os.path.join(datafiles.dirname, datafiles.basename) + caplog.set_level(1) + + with create_artifact_share(os.path.join(str(tmpdir), 'artifactshare1')) as shareuser,\ + create_artifact_share(os.path.join(str(tmpdir), 'artifactshare2')) as shareproject,\ + create_artifact_share(os.path.join(str(tmpdir), 'artifactshare3')) as sharecli: + + # Add shareproject repo url to project.conf + with open(os.path.join(project, "project.conf"), "a") as projconf: + projconf.write("artifacts:\n url: {}\n push: True".format(shareproject.repo)) + + # Configure shareuser remote in user conf + cli.configure({ + 'artifacts': {'url': shareuser.repo, 'push': True} + }) + + result = cli.run(project=project, args=['build', '--remote', sharecli.repo, 'target.bst']) + + # Artifacts should have only been pushed to sharecli, as that was provided via the cli + result.assert_success() + all_elements = ['target.bst', 'import-bin.bst', 'compose-all.bst'] + for element_name in all_elements: + assert element_name in result.get_pushed_elements() + assert_shared(cli, sharecli, project, element_name) + assert_not_shared(cli, shareuser, project, element_name) + assert_not_shared(cli, shareproject, project, element_name) |