summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbst-marge-bot <marge-bot@buildstream.build>2019-05-06 12:38:18 +0000
committerbst-marge-bot <marge-bot@buildstream.build>2019-05-06 12:38:18 +0000
commit5dad01068d3c662c335065015c770f8afc8d282f (patch)
tree5985d0aa2387fd29be19f72409200ebaaebfea61
parent230c749e085374e8ab252c234f623dc346863926 (diff)
parentcb2d26c30f448c29cfd519e3d7809a3c7cd5aeac (diff)
downloadbuildstream-5dad01068d3c662c335065015c770f8afc8d282f.tar.gz
Merge branch 'tristan/fix-missing-workspace-artifact' into 'master'
element.py: Reset workspace state if last successful build is missing. Closes #1017 See merge request BuildStream/buildstream!1328
-rw-r--r--buildstream/element.py22
-rw-r--r--buildstream/testing/runcli.py4
-rw-r--r--tests/integration/workspace.py33
3 files changed, 54 insertions, 5 deletions
diff --git a/buildstream/element.py b/buildstream/element.py
index 8cc25fec6..cc31d3f02 100644
--- a/buildstream/element.py
+++ b/buildstream/element.py
@@ -738,8 +738,24 @@ class Element(Plugin):
context = self._get_context()
if self.__can_build_incrementally() and workspace.last_successful:
- last_successful = Artifact(self, context, strong_key=workspace.last_successful)
- old_dep_keys = last_successful.get_metadata_dependencies()
+
+ # Try to perform an incremental build if the last successful
+ # build is still in the artifact cache
+ #
+ if self.__artifacts.contains(self, workspace.last_successful):
+ last_successful = Artifact(self, context, strong_key=workspace.last_successful)
+ old_dep_keys = last_successful.get_metadata_dependencies()
+ else:
+ # Last successful build is no longer in the artifact cache,
+ # so let's reset it and perform a full build now.
+ workspace.prepared = False
+ workspace.last_successful = None
+
+ self.info("Resetting workspace state, last successful build is no longer in the cache")
+
+ # In case we are staging in the main process
+ if utils._is_main_process():
+ context.get_workspaces().save_config()
for dep in self.dependencies(scope):
# If we are workspaced, and we therefore perform an
@@ -764,7 +780,7 @@ class Element(Plugin):
# In case we are running `bst shell`, this happens in the
# main process and we need to update the workspace config
if utils._is_main_process():
- self._get_context().get_workspaces().save_config()
+ context.get_workspaces().save_config()
result = dep.stage_artifact(sandbox,
path=path,
diff --git a/buildstream/testing/runcli.py b/buildstream/testing/runcli.py
index 72bdce09e..934c31236 100644
--- a/buildstream/testing/runcli.py
+++ b/buildstream/testing/runcli.py
@@ -637,8 +637,8 @@ class TestArtifact():
def remove_artifact_from_cache(self, cache_dir, element_name):
cache_dir = os.path.join(cache_dir, 'cas', 'refs', 'heads')
-
- cache_dir = os.path.splitext(os.path.join(cache_dir, 'test', element_name))[0]
+ normal_name = element_name.replace(os.sep, '-')
+ cache_dir = os.path.splitext(os.path.join(cache_dir, 'test', normal_name))[0]
shutil.rmtree(cache_dir)
# is_cached():
diff --git a/tests/integration/workspace.py b/tests/integration/workspace.py
index 4ee0050d7..134ed6385 100644
--- a/tests/integration/workspace.py
+++ b/tests/integration/workspace.py
@@ -271,3 +271,36 @@ def test_incremental_configure_commands_run_only_once(cli, datafiles):
res = cli.run(project=project, args=['build', element_name])
res.assert_success()
assert not os.path.exists(os.path.join(workspace, 'prepared-again'))
+
+
+# Test that rebuilding an already built workspaced element does
+# not crash after the last successfully built artifact is removed
+# from the cache
+#
+# A user can remove their artifact cache, or manually remove the
+# artifact with `bst artifact delete`, or BuildStream can delete
+# the last successfully built artifact for this workspace as a
+# part of a cleanup job.
+#
+@pytest.mark.datafiles(DATA_DIR)
+@pytest.mark.skipif(not HAVE_SANDBOX, reason='Only available with a functioning sandbox')
+def test_workspace_missing_last_successful(cli, datafiles):
+ project = str(datafiles)
+ workspace = os.path.join(cli.directory, 'workspace')
+ element_name = 'workspace/workspace-commanddir.bst'
+
+ # Open workspace
+ res = cli.run(project=project, args=['workspace', 'open', '--directory', workspace, element_name])
+ assert res.exit_code == 0
+
+ # Build first, this will record the last successful build in local state
+ res = cli.run(project=project, args=['build', element_name])
+ assert res.exit_code == 0
+
+ # Remove the artifact from the cache, invalidating the last successful build
+ res = cli.run(project=project, args=['artifact', 'delete', element_name])
+ assert res.exit_code == 0
+
+ # Build again, ensure we dont crash just because the artifact went missing
+ res = cli.run(project=project, args=['build', element_name])
+ assert res.exit_code == 0