From 6ccfab0b1b25990e406446d5cbe5aee83a5e158a Mon Sep 17 00:00:00 2001 From: Valentin David Date: Tue, 6 Nov 2018 18:54:41 +0100 Subject: Fix cache corruption by scripts when layout and integration commands are used Root directory was marked as a non-artifact mount, so not using SafeHardLink. However integration commands executed with write access to the root directory. Fixes #749 --- buildstream/scriptelement.py | 15 +++++------ .../project/elements/script/corruption-image.bst | 4 +++ .../elements/script/corruption-integration.bst | 7 ++++++ .../project/elements/script/corruption.bst | 21 ++++++++++++++++ tests/integration/project/files/canary | 1 + tests/integration/script.py | 29 ++++++++++++++++++++++ 6 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 tests/integration/project/elements/script/corruption-image.bst create mode 100644 tests/integration/project/elements/script/corruption-integration.bst create mode 100644 tests/integration/project/elements/script/corruption.bst create mode 100644 tests/integration/project/files/canary diff --git a/buildstream/scriptelement.py b/buildstream/scriptelement.py index 3a5d914d0..e9ad60c37 100644 --- a/buildstream/scriptelement.py +++ b/buildstream/scriptelement.py @@ -201,16 +201,17 @@ class ScriptElement(Element): # Setup environment sandbox.set_environment(self.get_environment()) + # Tell the sandbox to mount the install root + directories = {'/': False} + # Mark the artifact directories in the layout for item in self.__layout: - if item['destination'] != '/': - if item['element']: - sandbox.mark_directory(item['destination'], artifact=True) - else: - sandbox.mark_directory(item['destination']) + destination = item['destination'] + was_artifact = directories.get(destination, False) + directories[destination] = item['element'] or was_artifact - # Tell the sandbox to mount the install root - sandbox.mark_directory(self.__install_root) + for directory, artifact in directories.items(): + sandbox.mark_directory(directory, artifact=artifact) def stage(self, sandbox): diff --git a/tests/integration/project/elements/script/corruption-image.bst b/tests/integration/project/elements/script/corruption-image.bst new file mode 100644 index 000000000..a1035f929 --- /dev/null +++ b/tests/integration/project/elements/script/corruption-image.bst @@ -0,0 +1,4 @@ +kind: import +sources: +- kind: local + path: files/canary diff --git a/tests/integration/project/elements/script/corruption-integration.bst b/tests/integration/project/elements/script/corruption-integration.bst new file mode 100644 index 000000000..c0f1d12df --- /dev/null +++ b/tests/integration/project/elements/script/corruption-integration.bst @@ -0,0 +1,7 @@ +kind: stack + +public: + bst: + integration-commands: + - echo smashed >>/canary + diff --git a/tests/integration/project/elements/script/corruption.bst b/tests/integration/project/elements/script/corruption.bst new file mode 100644 index 000000000..037d4daca --- /dev/null +++ b/tests/integration/project/elements/script/corruption.bst @@ -0,0 +1,21 @@ +kind: script + +depends: +- filename: base.bst + type: build +- filename: script/corruption-image.bst + type: build +- filename: script/corruption-integration.bst + type: build + +variables: + install-root: "/" + +config: + layout: + - element: base.bst + destination: "/" + - element: script/corruption-image.bst + destination: "/" + - element: script/corruption-integration.bst + destination: "/" diff --git a/tests/integration/project/files/canary b/tests/integration/project/files/canary new file mode 100644 index 000000000..715cb3983 --- /dev/null +++ b/tests/integration/project/files/canary @@ -0,0 +1 @@ +alive diff --git a/tests/integration/script.py b/tests/integration/script.py index 88226c0b7..67bdd9642 100644 --- a/tests/integration/script.py +++ b/tests/integration/script.py @@ -155,3 +155,32 @@ def test_script_layout(cli, tmpdir, datafiles): text = f.read() assert text == "Hi\n" + + +@pytest.mark.datafiles(DATA_DIR) +def test_regression_cache_corruption(cli, tmpdir, datafiles): + project = str(datafiles) + checkout_original = os.path.join(cli.directory, 'checkout-original') + checkout_after = os.path.join(cli.directory, 'checkout-after') + element_name = 'script/corruption.bst' + canary_element_name = 'script/corruption-image.bst' + + res = cli.run(project=project, args=['build', canary_element_name]) + assert res.exit_code == 0 + + res = cli.run(project=project, args=['checkout', canary_element_name, + checkout_original]) + assert res.exit_code == 0 + + with open(os.path.join(checkout_original, 'canary')) as f: + assert f.read() == 'alive\n' + + res = cli.run(project=project, args=['build', element_name]) + assert res.exit_code == 0 + + res = cli.run(project=project, args=['checkout', canary_element_name, + checkout_after]) + assert res.exit_code == 0 + + with open(os.path.join(checkout_after, 'canary')) as f: + assert f.read() == 'alive\n' -- cgit v1.2.1