summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin David <valentin.david@codethink.co.uk>2018-11-06 18:54:41 +0100
committerValentin David <valentin.david@codethink.co.uk>2018-11-06 19:00:35 +0100
commita9618e26775a26db3f084f9cb5709e23b2f48f95 (patch)
tree994f378c10e5b2ac72662e5e83aef5f506d6413a
parent1f7acf748babea91909489d696ce1dcce2232f60 (diff)
downloadbuildstream-valentindavid/script-artifact-corruption.tar.gz
Fix cache corruption by scripts when layout and integration commands are usedvalentindavid/script-artifact-corruption
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
-rw-r--r--buildstream/scriptelement.py15
-rw-r--r--tests/integration/project/elements/script/corruption-image.bst4
-rw-r--r--tests/integration/project/elements/script/corruption-integration.bst7
-rw-r--r--tests/integration/project/elements/script/corruption.bst21
-rw-r--r--tests/integration/project/files/canary1
-rw-r--r--tests/integration/script.py29
6 files changed, 70 insertions, 7 deletions
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'