Skip to content

Commit 435a56b

Browse files
author
Adrien Plazas
committed
_frontend/widget: Add artifact-cas-digest show format
This adds the artifact-cas-digest format string to the show command, allowing to show the CAS digest of the built artifact.
1 parent 70fa523 commit 435a56b

File tree

4 files changed

+79
-2
lines changed

4 files changed

+79
-2
lines changed

man/bst-show.1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Show elements in the pipeline
4545
%{deps} A list of all dependencies
4646
%{build-deps} A list of build dependencies
4747
%{runtime-deps} A list of runtime dependencies
48+
%{artifact-cas-digest} The CAS digest of the built artifact
4849
.PP
4950
The value of the %{symbol} without the leading '%' character is understood
5051
as a pythonic formatting string, so python formatting features apply,

src/buildstream/_frontend/cli.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,7 @@ def show(app, elements, deps, except_, order, format_):
613613
%{deps} A list of all dependencies
614614
%{build-deps} A list of build dependencies
615615
%{runtime-deps} A list of runtime dependencies
616+
%{artifact-cas-digest} The CAS digest of the built artifact
616617
617618
The value of the %{symbol} without the leading '%' character is understood
618619
as a pythonic formatting string, so python formatting features apply,
@@ -638,7 +639,8 @@ def show(app, elements, deps, except_, order, format_):
638639
state_match = re.search(r"%(\{(state)[^%]*?\})", format_)
639640
key_match = re.search(r"%(\{(key)[^%]*?\})", format_)
640641
full_key_match = re.search(r"%(\{(full-key)[^%]*?\})", format_)
641-
need_state = bool(state_match or key_match or full_key_match)
642+
artifact_cas_digest_match = re.search(r"%(\{(artifact-cas-digest)[^%]*?\})", format_)
643+
need_state = bool(state_match or key_match or full_key_match or artifact_cas_digest_match)
642644

643645
if not elements:
644646
elements = app.project.get_default_targets()

src/buildstream/_frontend/widget.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,21 @@ def show_pipeline(self, dependencies, format_):
437437
runtime_deps = [e._get_full_name() for e in element._dependencies(_Scope.RUN, recurse=False)]
438438
line = p.fmt_subst(line, "runtime-deps", _yaml.roundtrip_dump_string(runtime_deps).rstrip("\n"))
439439

440+
# Artifact CAS Digest
441+
if "%{artifact-cas-digest" in format_:
442+
artifact = element._get_artifact()
443+
if not artifact.query_cache():
444+
artifact = None
445+
if artifact is not None:
446+
artifact_files = artifact.get_files()
447+
# We call the private CasBasedDirectory._get_digest() for
448+
# the moment, we should make it public on Directory.
449+
artifact_digest = artifact_files._get_digest()
450+
formated_artifact_digest = "{}/{}".format(artifact_digest.hash, artifact_digest.size_bytes)
451+
line = p.fmt_subst(line, "artifact-cas-digest", formated_artifact_digest)
452+
else:
453+
line = p.fmt_subst(line, "artifact-cas-digest", "(no artifact CAS digest)", fg="yellow")
454+
440455
report += line + "\n"
441456

442457
return report.rstrip("\n")

tests/frontend/show.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,8 +438,9 @@ def setup_test():
438438
("%{deps}", "- import-dev.bst\n- import-links.bst\n- import-bin.bst"),
439439
("%{build-deps}", "- import-dev.bst\n- import-links.bst"),
440440
("%{runtime-deps}", "- import-links.bst\n- import-bin.bst"),
441+
("%{artifact-cas-digest}", "(no artifact CAS digest)"),
441442
],
442-
ids=["deps", "build-deps", "runtime-deps"],
443+
ids=["deps", "build-deps", "runtime-deps", "artifact-cas-digest"],
443444
)
444445
def test_format_deps(cli, datafiles, dep_kind, expected_deps):
445446
project = str(datafiles)
@@ -553,6 +554,64 @@ def test_strict_dependencies(cli, datafiles, target, expected_state):
553554
assert states[target] == expected_state
554555

555556

557+
# This tests that cache keys behave as expected when
558+
# dependencies have been specified as `strict` and
559+
# when building in strict mode.
560+
#
561+
# This test will:
562+
#
563+
# * Build the target once (and assert that it is cached)
564+
# * Modify some local files which are imported
565+
# by an import element which the target depends on
566+
# * Assert that the cached state of the target element
567+
# is as expected
568+
#
569+
# We run the test twice, once with an element which strict
570+
# depends on the changing import element, and one which
571+
# depends on it regularly.
572+
#
573+
@pytest.mark.datafiles(os.path.join(DATA_DIR, "project"))
574+
@pytest.mark.parametrize(
575+
"target, expected_digests",
576+
[
577+
("target.bst", {
578+
"compose-all.bst": "c742f599e198f348ba7600bf50194ae45af6cba759e0005dcd980ad596c51959/78",
579+
"import-bin.bst": "594334e3e9f15c9eac5b8325befc3f53af8ffbaa664424bb308484abb892944f/77",
580+
"import-dev.bst": "42203f9284db4817a2fc2d57714c6c92ec318f82a23a25e5325852e5dd6effc3/77",
581+
"target.bst": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855/0",
582+
}),
583+
],
584+
)
585+
def test_format_artifact_cas_digest(cli, datafiles, target, expected_digests):
586+
project = str(datafiles)
587+
expected_no_digest = "(no artifact CAS digest)"
588+
589+
result = cli.run(project=project, silent=True, args=["show", "--format", "%{name},%{artifact-cas-digest}", target])
590+
result.assert_success()
591+
592+
digests = dict(line.split(",", 2) for line in result.output.splitlines())
593+
594+
assert len(digests) == len(expected_digests)
595+
for component, received in sorted(digests.items()):
596+
expected = expected_no_digest
597+
if received != expected:
598+
raise AssertionError("Expected output:\n{}\nInstead received output:\n{}".format(expected, received))
599+
600+
result = cli.run(project=project, silent=True, args=["build", target])
601+
result.assert_success()
602+
603+
result = cli.run(project=project, silent=True, args=["show", "--format", "%{name},%{artifact-cas-digest}", target])
604+
result.assert_success()
605+
606+
digests = dict(line.split(",", 2) for line in result.output.splitlines())
607+
608+
assert len(digests) == len(expected_digests)
609+
for component, received in sorted(digests.items()):
610+
expected = expected_digests[component]
611+
if received != expected:
612+
raise AssertionError("Expected output:\n{}\nInstead received output:\n{}".format(expected, received))
613+
614+
556615
@pytest.mark.datafiles(os.path.join(DATA_DIR, "project"))
557616
@pytest.mark.parametrize("fatal", [True, False], ids=["fatal", "non-fatal"])
558617
def test_unaliased_url(cli, tmpdir, datafiles, fatal):

0 commit comments

Comments
 (0)