diff options
author | bst-marge-bot <marge-bot@buildstream.build> | 2019-05-06 12:38:18 +0000 |
---|---|---|
committer | bst-marge-bot <marge-bot@buildstream.build> | 2019-05-06 12:38:18 +0000 |
commit | 5dad01068d3c662c335065015c770f8afc8d282f (patch) | |
tree | 5985d0aa2387fd29be19f72409200ebaaebfea61 | |
parent | 230c749e085374e8ab252c234f623dc346863926 (diff) | |
parent | cb2d26c30f448c29cfd519e3d7809a3c7cd5aeac (diff) | |
download | buildstream-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.py | 22 | ||||
-rw-r--r-- | buildstream/testing/runcli.py | 4 | ||||
-rw-r--r-- | tests/integration/workspace.py | 33 |
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 |