Chandan Singh pushed to branch chandan/bst-checkout-build at BuildStream / buildstream
Commits:
-
da7e038b
by Jürg Billeter at 2018-09-24T13:58:55Z
-
86ea1173
by Jürg Billeter at 2018-09-24T13:59:59Z
-
a76339de
by Jürg Billeter at 2018-09-24T16:02:38Z
-
c8dfe7f7
by Chandan Singh at 2018-09-25T00:08:15Z
8 changed files:
- buildstream/_frontend/cli.py
- buildstream/element.py
- buildstream/element_enums.py
- tests/frontend/buildcheckout.py
- + tests/frontend/project/elements/checkout-deps.bst
- + tests/frontend/project/elements/rebuild-target.bst
- + tests/frontend/project/files/etc-files/etc/buildstream/config
- + tests/frontend/rebuild.py
Changes:
... | ... | @@ -630,7 +630,7 @@ def shell(app, element, sysroot, mount, isolate, build_, command): |
630 | 630 |
@click.option('--force', '-f', default=False, is_flag=True,
|
631 | 631 |
help="Allow files to be overwritten")
|
632 | 632 |
@click.option('--deps', '-d', default='run',
|
633 |
- type=click.Choice(['run', 'none']),
|
|
633 |
+ type=click.Choice(['run', 'build', 'none']),
|
|
634 | 634 |
help='The dependencies to checkout (default: run)')
|
635 | 635 |
@click.option('--integrate/--no-integrate', default=True, is_flag=True,
|
636 | 636 |
help="Whether to run integration commands")
|
... | ... | @@ -423,7 +423,7 @@ class Element(Plugin): |
423 | 423 |
visited=visited, recursed=True)
|
424 | 424 |
|
425 | 425 |
# Yeild self only at the end, after anything needed has been traversed
|
426 |
- if should_yield and (recurse or recursed) and (scope == Scope.ALL or scope == Scope.RUN):
|
|
426 |
+ if should_yield and (recurse or recursed) and scope != Scope.BUILD:
|
|
427 | 427 |
yield self
|
428 | 428 |
|
429 | 429 |
def search(self, scope, name):
|
... | ... | @@ -671,37 +671,37 @@ class Element(Plugin): |
671 | 671 |
if self.__can_build_incrementally() and workspace.last_successful:
|
672 | 672 |
old_dep_keys = self.__get_artifact_metadata_dependencies(workspace.last_successful)
|
673 | 673 |
|
674 |
- for dep in self.dependencies(scope):
|
|
674 |
+ for element in self.dependencies(scope):
|
|
675 | 675 |
# If we are workspaced, and we therefore perform an
|
676 | 676 |
# incremental build, we must ensure that we update the mtimes
|
677 | 677 |
# of any files created by our dependencies since the last
|
678 | 678 |
# successful build.
|
679 | 679 |
to_update = None
|
680 | 680 |
if workspace and old_dep_keys:
|
681 |
- dep.__assert_cached()
|
|
681 |
+ element.__assert_cached()
|
|
682 | 682 |
|
683 |
- if dep.name in old_dep_keys:
|
|
684 |
- key_new = dep._get_cache_key()
|
|
685 |
- key_old = old_dep_keys[dep.name]
|
|
683 |
+ if element.name in old_dep_keys:
|
|
684 |
+ key_new = element._get_cache_key()
|
|
685 |
+ key_old = old_dep_keys[element.name]
|
|
686 | 686 |
|
687 | 687 |
# We only need to worry about modified and added
|
688 | 688 |
# files, since removed files will be picked up by
|
689 | 689 |
# build systems anyway.
|
690 |
- to_update, _, added = self.__artifacts.diff(dep, key_old, key_new, subdir='files')
|
|
691 |
- workspace.add_running_files(dep.name, to_update + added)
|
|
692 |
- to_update.extend(workspace.running_files[dep.name])
|
|
690 |
+ to_update, _, added = self.__artifacts.diff(element, key_old, key_new, subdir='files')
|
|
691 |
+ workspace.add_running_files(element.name, to_update + added)
|
|
692 |
+ to_update.extend(workspace.running_files[element.name])
|
|
693 | 693 |
|
694 | 694 |
# In case we are running `bst shell`, this happens in the
|
695 | 695 |
# main process and we need to update the workspace config
|
696 | 696 |
if utils._is_main_process():
|
697 | 697 |
self._get_context().get_workspaces().save_config()
|
698 | 698 |
|
699 |
- result = dep.stage_artifact(sandbox,
|
|
700 |
- path=path,
|
|
701 |
- include=include,
|
|
702 |
- exclude=exclude,
|
|
703 |
- orphans=orphans,
|
|
704 |
- update_mtimes=to_update)
|
|
699 |
+ result = element.stage_artifact(sandbox,
|
|
700 |
+ path=path,
|
|
701 |
+ include=include,
|
|
702 |
+ exclude=exclude,
|
|
703 |
+ orphans=orphans,
|
|
704 |
+ update_mtimes=to_update)
|
|
705 | 705 |
if result.overwritten:
|
706 | 706 |
for overwrite in result.overwritten:
|
707 | 707 |
# Completely new overwrite
|
... | ... | @@ -710,13 +710,13 @@ class Element(Plugin): |
710 | 710 |
# written the element before
|
711 | 711 |
for elm, contents in files_written.items():
|
712 | 712 |
if overwrite in contents:
|
713 |
- overlaps[overwrite] = [elm, dep.name]
|
|
713 |
+ overlaps[overwrite] = [elm, element.name]
|
|
714 | 714 |
else:
|
715 |
- overlaps[overwrite].append(dep.name)
|
|
716 |
- files_written[dep.name] = result.files_written
|
|
715 |
+ overlaps[overwrite].append(element.name)
|
|
716 |
+ files_written[element.name] = result.files_written
|
|
717 | 717 |
|
718 | 718 |
if result.ignored:
|
719 |
- ignored[dep.name] = result.ignored
|
|
719 |
+ ignored[element.name] = result.ignored
|
|
720 | 720 |
|
721 | 721 |
if overlaps:
|
722 | 722 |
overlap_warning = False
|
... | ... | @@ -1318,17 +1318,24 @@ class Element(Plugin): |
1318 | 1318 |
if scope == Scope.BUILD:
|
1319 | 1319 |
self.stage(sandbox)
|
1320 | 1320 |
elif scope == Scope.RUN:
|
1321 |
+ |
|
1322 |
+ if deps == 'build':
|
|
1323 |
+ dependency_scope = Scope.BUILD
|
|
1324 |
+ elif deps == 'run':
|
|
1325 |
+ dependency_scope = Scope.RUN
|
|
1326 |
+ else:
|
|
1327 |
+ dependency_scope = Scope.NONE
|
|
1328 |
+ |
|
1321 | 1329 |
# Stage deps in the sandbox root
|
1322 |
- if deps == 'run':
|
|
1323 |
- with self.timed_activity("Staging dependencies", silent_nested=True):
|
|
1324 |
- self.stage_dependency_artifacts(sandbox, scope)
|
|
1330 |
+ with self.timed_activity("Staging dependencies", silent_nested=True):
|
|
1331 |
+ self.stage_dependency_artifacts(sandbox, dependency_scope)
|
|
1325 | 1332 |
|
1326 |
- # Run any integration commands provided by the dependencies
|
|
1327 |
- # once they are all staged and ready
|
|
1328 |
- if integrate:
|
|
1329 |
- with self.timed_activity("Integrating sandbox"):
|
|
1330 |
- for dep in self.dependencies(scope):
|
|
1331 |
- dep.integrate(sandbox)
|
|
1333 |
+ # Run any integration commands provided by the dependencies
|
|
1334 |
+ # once they are all staged and ready
|
|
1335 |
+ if integrate:
|
|
1336 |
+ with self.timed_activity("Integrating sandbox"):
|
|
1337 |
+ for dep in self.dependencies(dependency_scope):
|
|
1338 |
+ dep.integrate(sandbox)
|
|
1332 | 1339 |
|
1333 | 1340 |
yield sandbox
|
1334 | 1341 |
|
... | ... | @@ -2084,7 +2091,7 @@ class Element(Plugin): |
2084 | 2091 |
#
|
2085 | 2092 |
# Raises an error if the artifact is not cached.
|
2086 | 2093 |
#
|
2087 |
- def __assert_cached(self, keystrength=_KeyStrength.STRONG):
|
|
2094 |
+ def __assert_cached(self, keystrength=None):
|
|
2088 | 2095 |
assert self.__is_cached(keystrength=keystrength), "{}: Missing artifact {}".format(
|
2089 | 2096 |
self, self._get_brief_display_key())
|
2090 | 2097 |
|
... | ... | @@ -59,3 +59,7 @@ class Scope(Enum): |
59 | 59 |
"""All elements required for running the element. Including the element
|
60 | 60 |
itself.
|
61 | 61 |
"""
|
62 |
+ |
|
63 |
+ NONE = 4
|
|
64 |
+ """Just the element itself, no dependencies.
|
|
65 |
+ """
|
... | ... | @@ -61,13 +61,14 @@ def test_build_checkout(datafiles, cli, strict, hardlinks): |
61 | 61 |
|
62 | 62 |
|
63 | 63 |
@pytest.mark.datafiles(DATA_DIR)
|
64 |
-@pytest.mark.parametrize("deps", [("run"), ("none")])
|
|
64 |
+@pytest.mark.parametrize("deps", [("run"), ("none"), ("build")])
|
|
65 | 65 |
def test_build_checkout_deps(datafiles, cli, deps):
|
66 | 66 |
project = os.path.join(datafiles.dirname, datafiles.basename)
|
67 | 67 |
checkout = os.path.join(cli.directory, 'checkout')
|
68 |
+ element_name = 'checkout-deps.bst'
|
|
68 | 69 |
|
69 | 70 |
# First build it
|
70 |
- result = cli.run(project=project, args=['build', 'target.bst'])
|
|
71 |
+ result = cli.run(project=project, args=['build', element_name])
|
|
71 | 72 |
result.assert_success()
|
72 | 73 |
|
73 | 74 |
# Assert that after a successful build, the builddir is empty
|
... | ... | @@ -76,20 +77,25 @@ def test_build_checkout_deps(datafiles, cli, deps): |
76 | 77 |
assert not os.listdir(builddir)
|
77 | 78 |
|
78 | 79 |
# Now check it out
|
79 |
- result = cli.run(project=project, args=['checkout', 'target.bst', '--deps', deps, checkout])
|
|
80 |
+ result = cli.run(project=project, args=['checkout', element_name, '--deps', deps, checkout])
|
|
80 | 81 |
result.assert_success()
|
81 | 82 |
|
82 |
- # Check that the executable hello file is found in the checkout
|
|
83 |
- filename = os.path.join(checkout, 'usr', 'bin', 'hello')
|
|
83 |
+ # Verify output of this element
|
|
84 |
+ filename = os.path.join(checkout, 'etc', 'buildstream', 'config')
|
|
85 |
+ if deps == "build":
|
|
86 |
+ assert not os.path.exists(filename)
|
|
87 |
+ else:
|
|
88 |
+ assert os.path.exists(filename)
|
|
84 | 89 |
|
85 |
- if deps == "run":
|
|
90 |
+ # Verify output of this element's build dependencies
|
|
91 |
+ filename = os.path.join(checkout, 'usr', 'include', 'pony.h')
|
|
92 |
+ if deps == "build":
|
|
86 | 93 |
assert os.path.exists(filename)
|
87 | 94 |
else:
|
88 | 95 |
assert not os.path.exists(filename)
|
89 | 96 |
|
90 |
- # Check that the executable hello file is found in the checkout
|
|
91 |
- filename = os.path.join(checkout, 'usr', 'include', 'pony.h')
|
|
92 |
- |
|
97 |
+ # Verify output of this element's runtime dependencies
|
|
98 |
+ filename = os.path.join(checkout, 'usr', 'bin', 'hello')
|
|
93 | 99 |
if deps == "run":
|
94 | 100 |
assert os.path.exists(filename)
|
95 | 101 |
else:
|
1 |
+kind: import
|
|
2 |
+description: It is important for this element to have both build and runtime dependencies
|
|
3 |
+sources:
|
|
4 |
+- kind: local
|
|
5 |
+ path: files/etc-files
|
|
6 |
+depends:
|
|
7 |
+- filename: import-dev.bst
|
|
8 |
+ type: build
|
|
9 |
+- filename: import-bin.bst
|
|
10 |
+ type: runtime
|
1 |
+kind: compose
|
|
2 |
+ |
|
3 |
+build-depends:
|
|
4 |
+- target.bst
|
1 |
+config
|
1 |
+import os
|
|
2 |
+import pytest
|
|
3 |
+from tests.testutils import cli
|
|
4 |
+ |
|
5 |
+# Project directory
|
|
6 |
+DATA_DIR = os.path.join(
|
|
7 |
+ os.path.dirname(os.path.realpath(__file__)),
|
|
8 |
+ "project",
|
|
9 |
+)
|
|
10 |
+ |
|
11 |
+ |
|
12 |
+def strict_args(args, strict):
|
|
13 |
+ if strict != "strict":
|
|
14 |
+ return ['--no-strict'] + args
|
|
15 |
+ return args
|
|
16 |
+ |
|
17 |
+ |
|
18 |
+@pytest.mark.datafiles(DATA_DIR)
|
|
19 |
+@pytest.mark.parametrize("strict", ["strict", "non-strict"])
|
|
20 |
+def test_rebuild(datafiles, cli, strict):
|
|
21 |
+ project = os.path.join(datafiles.dirname, datafiles.basename)
|
|
22 |
+ checkout = os.path.join(cli.directory, 'checkout')
|
|
23 |
+ |
|
24 |
+ # First build intermediate target.bst
|
|
25 |
+ result = cli.run(project=project, args=strict_args(['build', 'target.bst'], strict))
|
|
26 |
+ result.assert_success()
|
|
27 |
+ |
|
28 |
+ # Modify base import
|
|
29 |
+ with open(os.path.join(project, 'files', 'dev-files', 'usr', 'include', 'new.h'), "w") as f:
|
|
30 |
+ f.write("#define NEW")
|
|
31 |
+ |
|
32 |
+ # Rebuild base import and build top-level rebuild-target.bst
|
|
33 |
+ # In non-strict mode, this does not rebuild intermediate target.bst,
|
|
34 |
+ # which means that a weakly cached target.bst will be staged as dependency.
|
|
35 |
+ result = cli.run(project=project, args=strict_args(['build', 'rebuild-target.bst'], strict))
|
|
36 |
+ result.assert_success()
|