Gökçen Nurlu pushed to branch gokcennurlu/remote_url_override_push_error at BuildStream / buildstream
Commits:
-
1b24148f
by Chandan Singh at 2018-12-03T09:46:13Z
-
8ac1e757
by Chandan Singh at 2018-12-03T09:46:14Z
-
ac60f47a
by Benjamin Schubert at 2018-12-03T09:46:14Z
-
b1430fb5
by Tristan Van Berkom at 2018-12-03T11:01:54Z
-
9022a778
by Javier Jardón at 2018-12-03T11:14:55Z
-
4462892e
by Tristan Van Berkom at 2018-12-03T11:45:07Z
-
4ae2bf56
by Gökçen Nurlu at 2018-12-03T15:34:03Z
-
4b772a9b
by Gökçen Nurlu at 2018-12-03T15:34:03Z
-
1f77d9f3
by Gökçen Nurlu at 2018-12-03T15:34:03Z
7 changed files:
- buildstream/_artifactcache/artifactcache.py
- buildstream/_frontend/cli.py
- buildstream/_stream.py
- buildstream/element.py
- buildstream/plugins/sources/git.py
- buildstream/types.py
- tests/frontend/buildcheckout.py
Changes:
| ... | ... | @@ -110,36 +110,42 @@ class ArtifactCache(): |
| 110 | 110 |
# assume project and element names are not allowed to contain slashes
|
| 111 | 111 |
return '{0}/{1}/{2}'.format(project.name, element_name, key)
|
| 112 | 112 |
|
| 113 |
+ # get_remotes_from_projects()
|
|
| 114 |
+ #
|
|
| 115 |
+ # Generates list artifact caches based on project configuration
|
|
| 116 |
+ #
|
|
| 117 |
+ # Returns:
|
|
| 118 |
+ # (list of (list of ArtifactCacheSpec, Project)): Configurations each are
|
|
| 119 |
+ # ready to be consumed by `self._set_remotes()`
|
|
| 120 |
+ #
|
|
| 121 |
+ # This requires that all of the projects which are to be processed in the session
|
|
| 122 |
+ # have already been loaded and are observable in the Context.
|
|
| 123 |
+ #
|
|
| 124 |
+ def get_remotes_from_projects(self):
|
|
| 125 |
+ return [
|
|
| 126 |
+ (_configured_remote_artifact_cache_specs(self.context, prj), prj)
|
|
| 127 |
+ for prj in self.context.get_projects()
|
|
| 128 |
+ ]
|
|
| 129 |
+ |
|
| 113 | 130 |
# setup_remotes():
|
| 114 | 131 |
#
|
| 115 | 132 |
# Sets up which remotes to use
|
| 116 | 133 |
#
|
| 117 | 134 |
# Args:
|
| 118 |
- # use_config (bool): Whether to use project configuration
|
|
| 119 |
- # remote_url (str): Remote artifact cache URL
|
|
| 135 |
+ # remotes (list of (list of ArtifactCacheSpec, Project)): Configurations each are
|
|
| 136 |
+ # ready to be consumed by `self._set_remotes()`
|
|
| 120 | 137 |
#
|
| 121 | 138 |
# This requires that all of the projects which are to be processed in the session
|
| 122 | 139 |
# have already been loaded and are observable in the Context.
|
| 123 | 140 |
#
|
| 124 |
- def setup_remotes(self, *, use_config=False, remote_url=None):
|
|
| 125 |
- |
|
| 141 |
+ def setup_remotes(self, *, remotes):
|
|
| 126 | 142 |
# Ensure we do not double-initialise since this can be expensive
|
| 127 | 143 |
assert not self._remotes_setup
|
| 128 | 144 |
self._remotes_setup = True
|
| 129 | 145 |
|
| 130 |
- # Initialize remote artifact caches. We allow the commandline to override
|
|
| 131 |
- # the user config in some cases (for example `bst push --remote=...`).
|
|
| 132 |
- has_remote_caches = False
|
|
| 133 |
- if remote_url:
|
|
| 134 |
- self._set_remotes([ArtifactCacheSpec(remote_url, push=True)])
|
|
| 135 |
- has_remote_caches = True
|
|
| 136 |
- if use_config:
|
|
| 137 |
- for project in self.context.get_projects():
|
|
| 138 |
- artifact_caches = _configured_remote_artifact_cache_specs(self.context, project)
|
|
| 139 |
- if artifact_caches: # artifact_caches is a list of ArtifactCacheSpec instances
|
|
| 140 |
- self._set_remotes(artifact_caches, project=project)
|
|
| 141 |
- has_remote_caches = True
|
|
| 142 |
- if has_remote_caches:
|
|
| 146 |
+ if remotes:
|
|
| 147 |
+ for caches, project in remotes:
|
|
| 148 |
+ self._set_remotes(caches, project=project)
|
|
| 143 | 149 |
self._initialize_remotes()
|
| 144 | 150 |
|
| 145 | 151 |
# specs_from_config_node()
|
| ... | ... | @@ -640,7 +640,7 @@ def shell(app, element, sysroot, mount, isolate, build_, command): |
| 640 | 640 |
@click.option('--force', '-f', default=False, is_flag=True,
|
| 641 | 641 |
help="Allow files to be overwritten")
|
| 642 | 642 |
@click.option('--deps', '-d', default='run',
|
| 643 |
- type=click.Choice(['run', 'none']),
|
|
| 643 |
+ type=click.Choice(['run', 'build', 'none']),
|
|
| 644 | 644 |
help='The dependencies to checkout (default: run)')
|
| 645 | 645 |
@click.option('--integrate/--no-integrate', default=True, is_flag=True,
|
| 646 | 646 |
help="Whether to run integration commands")
|
| ... | ... | @@ -657,16 +657,24 @@ def shell(app, element, sysroot, mount, isolate, build_, command): |
| 657 | 657 |
def checkout(app, element, location, force, deps, integrate, hardlinks, tar):
|
| 658 | 658 |
"""Checkout a built artifact to the specified location
|
| 659 | 659 |
"""
|
| 660 |
+ from ..element import Scope
|
|
| 660 | 661 |
|
| 661 | 662 |
if hardlinks and tar:
|
| 662 | 663 |
click.echo("ERROR: options --hardlinks and --tar conflict", err=True)
|
| 663 | 664 |
sys.exit(-1)
|
| 664 | 665 |
|
| 666 |
+ if deps == "run":
|
|
| 667 |
+ scope = Scope.RUN
|
|
| 668 |
+ elif deps == "build":
|
|
| 669 |
+ scope = Scope.BUILD
|
|
| 670 |
+ elif deps == "none":
|
|
| 671 |
+ scope = Scope.NONE
|
|
| 672 |
+ |
|
| 665 | 673 |
with app.initialized():
|
| 666 | 674 |
app.stream.checkout(element,
|
| 667 | 675 |
location=location,
|
| 668 | 676 |
force=force,
|
| 669 |
- deps=deps,
|
|
| 677 |
+ scope=scope,
|
|
| 670 | 678 |
integrate=integrate,
|
| 671 | 679 |
hardlinks=hardlinks,
|
| 672 | 680 |
tar=tar)
|
| ... | ... | @@ -28,6 +28,7 @@ import tarfile |
| 28 | 28 |
from contextlib import contextmanager
|
| 29 | 29 |
from tempfile import TemporaryDirectory
|
| 30 | 30 |
|
| 31 |
+from ._artifactcache import ArtifactCacheSpec
|
|
| 31 | 32 |
from ._exceptions import StreamError, ImplError, BstError, set_last_task_error
|
| 32 | 33 |
from ._message import Message, MessageType
|
| 33 | 34 |
from ._scheduler import Scheduler, SchedStatus, TrackQueue, FetchQueue, BuildQueue, PullQueue, PushQueue
|
| ... | ... | @@ -305,6 +306,7 @@ class Stream(): |
| 305 | 306 |
selection=selection,
|
| 306 | 307 |
use_artifact_config=use_config,
|
| 307 | 308 |
artifact_remote_url=remote,
|
| 309 |
+ artifact_remote_can_push=False,
|
|
| 308 | 310 |
fetch_subprojects=True)
|
| 309 | 311 |
|
| 310 | 312 |
if not self._artifacts.has_fetch_remotes():
|
| ... | ... | @@ -343,6 +345,7 @@ class Stream(): |
| 343 | 345 |
selection=selection,
|
| 344 | 346 |
use_artifact_config=use_config,
|
| 345 | 347 |
artifact_remote_url=remote,
|
| 348 |
+ artifact_remote_can_push=True,
|
|
| 346 | 349 |
fetch_subprojects=True)
|
| 347 | 350 |
|
| 348 | 351 |
if not self._artifacts.has_push_remotes():
|
| ... | ... | @@ -370,7 +373,7 @@ class Stream(): |
| 370 | 373 |
# target (str): Target to checkout
|
| 371 | 374 |
# location (str): Location to checkout the artifact to
|
| 372 | 375 |
# force (bool): Whether files can be overwritten if necessary
|
| 373 |
- # deps (str): The dependencies to checkout
|
|
| 376 |
+ # scope (str): The scope of dependencies to checkout
|
|
| 374 | 377 |
# integrate (bool): Whether to run integration commands
|
| 375 | 378 |
# hardlinks (bool): Whether checking out files hardlinked to
|
| 376 | 379 |
# their artifacts is acceptable
|
| ... | ... | @@ -383,7 +386,7 @@ class Stream(): |
| 383 | 386 |
def checkout(self, target, *,
|
| 384 | 387 |
location=None,
|
| 385 | 388 |
force=False,
|
| 386 |
- deps='run',
|
|
| 389 |
+ scope=Scope.RUN,
|
|
| 387 | 390 |
integrate=True,
|
| 388 | 391 |
hardlinks=False,
|
| 389 | 392 |
tar=False):
|
| ... | ... | @@ -396,7 +399,7 @@ class Stream(): |
| 396 | 399 |
|
| 397 | 400 |
# Stage deps into a temporary sandbox first
|
| 398 | 401 |
try:
|
| 399 |
- with target._prepare_sandbox(Scope.RUN, None, deps=deps,
|
|
| 402 |
+ with target._prepare_sandbox(scope=scope, directory=None,
|
|
| 400 | 403 |
integrate=integrate) as sandbox:
|
| 401 | 404 |
|
| 402 | 405 |
# Copy or move the sandbox to the target directory
|
| ... | ... | @@ -922,7 +925,8 @@ class Stream(): |
| 922 | 925 |
# track_except_targets (list of str): Specified targets to except from fetching
|
| 923 | 926 |
# track_cross_junctions (bool): Whether tracking should cross junction boundaries
|
| 924 | 927 |
# use_artifact_config (bool): Whether to initialize artifacts with the config
|
| 925 |
- # artifact_remote_url (bool): A remote url for initializing the artifacts
|
|
| 928 |
+ # artifact_remote_url (str): A remote url for initializing the artifacts
|
|
| 929 |
+ # artifact_remote_can_push (bool): Whether `artifact_remote_url` can be used to push
|
|
| 926 | 930 |
# fetch_subprojects (bool): Whether to fetch subprojects while loading
|
| 927 | 931 |
#
|
| 928 | 932 |
# Returns:
|
| ... | ... | @@ -937,6 +941,7 @@ class Stream(): |
| 937 | 941 |
track_cross_junctions=False,
|
| 938 | 942 |
use_artifact_config=False,
|
| 939 | 943 |
artifact_remote_url=None,
|
| 944 |
+ artifact_remote_can_push=False,
|
|
| 940 | 945 |
fetch_subprojects=False,
|
| 941 | 946 |
dynamic_plan=False):
|
| 942 | 947 |
|
| ... | ... | @@ -1000,12 +1005,20 @@ class Stream(): |
| 1000 | 1005 |
self._pipeline.resolve_elements(track_selected)
|
| 1001 | 1006 |
return [], track_selected
|
| 1002 | 1007 |
|
| 1003 |
- # ArtifactCache.setup_remotes expects all projects to be fully loaded
|
|
| 1004 |
- for project in self._context.get_projects():
|
|
| 1005 |
- project.ensure_fully_loaded()
|
|
| 1006 |
- |
|
| 1008 |
+ if use_artifact_config:
|
|
| 1009 |
+ # ArtifactCache.get_remotes_from_projects expects all projects to be
|
|
| 1010 |
+ # fully loaded
|
|
| 1011 |
+ for project in self._context.get_projects():
|
|
| 1012 |
+ project.ensure_fully_loaded()
|
|
| 1013 |
+ remotes = self._artifacts.get_remotes_from_projects()
|
|
| 1014 |
+ else:
|
|
| 1015 |
+ # Build the ArtifactCacheSpec instance based on `--remote`
|
|
| 1016 |
+ remotes = [(
|
|
| 1017 |
+ [ArtifactCacheSpec(artifact_remote_url, push=artifact_remote_can_push)],
|
|
| 1018 |
+ None
|
|
| 1019 |
+ )]
|
|
| 1007 | 1020 |
# Connect to remote caches, this needs to be done before resolving element state
|
| 1008 |
- self._artifacts.setup_remotes(use_config=use_artifact_config, remote_url=artifact_remote_url)
|
|
| 1021 |
+ self._artifacts.setup_remotes(remotes=remotes)
|
|
| 1009 | 1022 |
|
| 1010 | 1023 |
# Now move on to loading primary selection.
|
| 1011 | 1024 |
#
|
| ... | ... | @@ -438,7 +438,7 @@ class Element(Plugin): |
| 438 | 438 |
visited=visited, recursed=True)
|
| 439 | 439 |
|
| 440 | 440 |
# Yeild self only at the end, after anything needed has been traversed
|
| 441 |
- if should_yield and (recurse or recursed) and (scope in (Scope.ALL, Scope.RUN)):
|
|
| 441 |
+ if should_yield and (recurse or recursed) and scope != Scope.BUILD:
|
|
| 442 | 442 |
yield self
|
| 443 | 443 |
|
| 444 | 444 |
def search(self, scope, name):
|
| ... | ... | @@ -1339,7 +1339,7 @@ class Element(Plugin): |
| 1339 | 1339 |
# is used to stage things by the `bst checkout` codepath
|
| 1340 | 1340 |
#
|
| 1341 | 1341 |
@contextmanager
|
| 1342 |
- def _prepare_sandbox(self, scope, directory, deps='run', integrate=True):
|
|
| 1342 |
+ def _prepare_sandbox(self, scope, directory, shell=False, integrate=True):
|
|
| 1343 | 1343 |
# bst shell and bst checkout require a local sandbox.
|
| 1344 | 1344 |
bare_directory = True if directory else False
|
| 1345 | 1345 |
with self.__sandbox(directory, config=self.__sandbox_config, allow_remote=False,
|
| ... | ... | @@ -1350,20 +1350,19 @@ class Element(Plugin): |
| 1350 | 1350 |
|
| 1351 | 1351 |
# Stage something if we need it
|
| 1352 | 1352 |
if not directory:
|
| 1353 |
- if scope == Scope.BUILD:
|
|
| 1353 |
+ if shell and scope == Scope.BUILD:
|
|
| 1354 | 1354 |
self.stage(sandbox)
|
| 1355 |
- elif scope == Scope.RUN:
|
|
| 1355 |
+ else:
|
|
| 1356 | 1356 |
# Stage deps in the sandbox root
|
| 1357 |
- if deps == 'run':
|
|
| 1358 |
- with self.timed_activity("Staging dependencies", silent_nested=True):
|
|
| 1359 |
- self.stage_dependency_artifacts(sandbox, scope)
|
|
| 1357 |
+ with self.timed_activity("Staging dependencies", silent_nested=True):
|
|
| 1358 |
+ self.stage_dependency_artifacts(sandbox, scope)
|
|
| 1360 | 1359 |
|
| 1361 |
- # Run any integration commands provided by the dependencies
|
|
| 1362 |
- # once they are all staged and ready
|
|
| 1363 |
- if integrate:
|
|
| 1364 |
- with self.timed_activity("Integrating sandbox"):
|
|
| 1365 |
- for dep in self.dependencies(scope):
|
|
| 1366 |
- dep.integrate(sandbox)
|
|
| 1360 |
+ # Run any integration commands provided by the dependencies
|
|
| 1361 |
+ # once they are all staged and ready
|
|
| 1362 |
+ if integrate:
|
|
| 1363 |
+ with self.timed_activity("Integrating sandbox"):
|
|
| 1364 |
+ for dep in self.dependencies(scope):
|
|
| 1365 |
+ dep.integrate(sandbox)
|
|
| 1367 | 1366 |
|
| 1368 | 1367 |
yield sandbox
|
| 1369 | 1368 |
|
| ... | ... | @@ -1858,7 +1857,7 @@ class Element(Plugin): |
| 1858 | 1857 |
# If directory is not specified, one will be staged using scope
|
| 1859 | 1858 |
def _shell(self, scope=None, directory=None, *, mounts=None, isolate=False, prompt=None, command=None):
|
| 1860 | 1859 |
|
| 1861 |
- with self._prepare_sandbox(scope, directory) as sandbox:
|
|
| 1860 |
+ with self._prepare_sandbox(scope, directory, shell=True) as sandbox:
|
|
| 1862 | 1861 |
environment = self.get_environment()
|
| 1863 | 1862 |
environment = copy.copy(environment)
|
| 1864 | 1863 |
flags = SandboxFlags.INTERACTIVE | SandboxFlags.ROOT_READ_ONLY
|
| ... | ... | @@ -25,6 +25,11 @@ git - stage files from a git repository |
| 25 | 25 |
|
| 26 | 26 |
* git
|
| 27 | 27 |
|
| 28 |
+.. attention::
|
|
| 29 |
+ |
|
| 30 |
+ Note that this plugin **will checkout git submodules by default**; even if
|
|
| 31 |
+ they are not specified in the `.bst` file.
|
|
| 32 |
+ |
|
| 28 | 33 |
**Usage:**
|
| 29 | 34 |
|
| 30 | 35 |
.. code:: yaml
|
| ... | ... | @@ -48,6 +48,12 @@ class Scope(Enum): |
| 48 | 48 |
itself.
|
| 49 | 49 |
"""
|
| 50 | 50 |
|
| 51 |
+ NONE = 4
|
|
| 52 |
+ """Just the element itself, no dependencies.
|
|
| 53 |
+ |
|
| 54 |
+ *Since: 1.4*
|
|
| 55 |
+ """
|
|
| 56 |
+ |
|
| 51 | 57 |
|
| 52 | 58 |
class Consistency():
|
| 53 | 59 |
"""Defines the various consistency states of a :class:`.Source`.
|
| ... | ... | @@ -86,13 +86,14 @@ def test_build_invalid_suffix_dep(datafiles, cli, strict, hardlinks): |
| 86 | 86 |
|
| 87 | 87 |
|
| 88 | 88 |
@pytest.mark.datafiles(DATA_DIR)
|
| 89 |
-@pytest.mark.parametrize("deps", [("run"), ("none")])
|
|
| 89 |
+@pytest.mark.parametrize("deps", [("run"), ("none"), ("build")])
|
|
| 90 | 90 |
def test_build_checkout_deps(datafiles, cli, deps):
|
| 91 | 91 |
project = os.path.join(datafiles.dirname, datafiles.basename)
|
| 92 | 92 |
checkout = os.path.join(cli.directory, 'checkout')
|
| 93 |
+ element_name = "checkout-deps.bst"
|
|
| 93 | 94 |
|
| 94 | 95 |
# First build it
|
| 95 |
- result = cli.run(project=project, args=['build', 'target.bst'])
|
|
| 96 |
+ result = cli.run(project=project, args=['build', element_name])
|
|
| 96 | 97 |
result.assert_success()
|
| 97 | 98 |
|
| 98 | 99 |
# Assert that after a successful build, the builddir is empty
|
| ... | ... | @@ -101,20 +102,25 @@ def test_build_checkout_deps(datafiles, cli, deps): |
| 101 | 102 |
assert not os.listdir(builddir)
|
| 102 | 103 |
|
| 103 | 104 |
# Now check it out
|
| 104 |
- result = cli.run(project=project, args=['checkout', 'target.bst', '--deps', deps, checkout])
|
|
| 105 |
+ result = cli.run(project=project, args=['checkout', element_name, '--deps', deps, checkout])
|
|
| 105 | 106 |
result.assert_success()
|
| 106 | 107 |
|
| 107 |
- # Check that the executable hello file is found in the checkout
|
|
| 108 |
- filename = os.path.join(checkout, 'usr', 'bin', 'hello')
|
|
| 108 |
+ # Verify output of this element
|
|
| 109 |
+ filename = os.path.join(checkout, 'etc', 'buildstream', 'config')
|
|
| 110 |
+ if deps == "build":
|
|
| 111 |
+ assert not os.path.exists(filename)
|
|
| 112 |
+ else:
|
|
| 113 |
+ assert os.path.exists(filename)
|
|
| 109 | 114 |
|
| 110 |
- if deps == "run":
|
|
| 115 |
+ # Verify output of this element's build dependencies
|
|
| 116 |
+ filename = os.path.join(checkout, 'usr', 'include', 'pony.h')
|
|
| 117 |
+ if deps == "build":
|
|
| 111 | 118 |
assert os.path.exists(filename)
|
| 112 | 119 |
else:
|
| 113 | 120 |
assert not os.path.exists(filename)
|
| 114 | 121 |
|
| 115 |
- # Check that the executable hello file is found in the checkout
|
|
| 116 |
- filename = os.path.join(checkout, 'usr', 'include', 'pony.h')
|
|
| 117 |
- |
|
| 122 |
+ # Verify output of this element's runtime dependencies
|
|
| 123 |
+ filename = os.path.join(checkout, 'usr', 'bin', 'hello')
|
|
| 118 | 124 |
if deps == "run":
|
| 119 | 125 |
assert os.path.exists(filename)
|
| 120 | 126 |
else:
|
