From 5fef3f01185ee0ad1a6b47eefd6718c93c551aa9 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 21 Oct 2025 21:14:04 +0200 Subject: [PATCH] json: include archive keys in JSON lines when requested via --format, fixes #9095 Add a test to ensure correct behavior. (cherry picked from commit 0c27bd304718123c084e0927388c356405b66df0) --- src/borg/helpers/parseformat.py | 9 ++++++++ src/borg/testsuite/archiver/list_cmd_test.py | 23 ++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/borg/helpers/parseformat.py b/src/borg/helpers/parseformat.py index ae0f54e49..3d8d637cc 100644 --- a/src/borg/helpers/parseformat.py +++ b/src/borg/helpers/parseformat.py @@ -898,6 +898,7 @@ class ItemFormatter(BaseFormatter): super().__init__(format, static_data) self.xxh64 = StreamingXXH64 self.archive = archive + # track which keys were requested in the format string self.format_keys = {f[1] for f in Formatter().parse(format)} self.call_keys = { "size": self.calculate_size, @@ -942,6 +943,14 @@ class ItemFormatter(BaseFormatter): item_data["inode"] = item.get("inode") for key in self.used_call_keys: item_data[key] = self.call_keys[key](item) + # When producing JSON lines, include selected static archive-level keys if they were + # requested via --format. This mirrors text output behavior and fixes #9095. + if jsonline: + # Include selected static archive-level keys when requested via --format. + # Keep implementation style aligned with 1.4-maint. + for k in ("archivename", "archiveid"): + if k in self.format_keys: + item_data[k] = self.static_data[k] return item_data def calculate_num_chunks(self, item): diff --git a/src/borg/testsuite/archiver/list_cmd_test.py b/src/borg/testsuite/archiver/list_cmd_test.py index 2ebbf6e04..c0f66ec5b 100644 --- a/src/borg/testsuite/archiver/list_cmd_test.py +++ b/src/borg/testsuite/archiver/list_cmd_test.py @@ -79,6 +79,29 @@ def test_list_json(archivers, request): assert file1["sha256"] == "b2915eb69f260d8d3c25249195f2c8f4f716ea82ec760ae929732c0262442b2b" +def test_list_json_lines_includes_archive_keys_in_format(archivers, request): + # Issue #9095 / PR #9096: archivename/archiveid should be available in JSON lines when + # requested via --format. + archiver = request.getfixturevalue(archivers) + create_regular_file(archiver.input_path, "file1", size=1024) + cmd(archiver, "repo-create", RK_ENCRYPTION) + cmd(archiver, "create", "test", "input") + + # Query archive info to obtain expected name and id + info_archive = json.loads(cmd(archiver, "info", "--json", "-a", "test")) + assert len(info_archive["archives"]) == 1 + archive_info = info_archive["archives"][0] + expected_name = archive_info["name"] + expected_id = archive_info["id"] + + out = cmd(archiver, "list", "test", "--json-lines", "--format={archivename} {archiveid}") + rows = [json.loads(s) for s in out.splitlines() if s] + assert len(rows) >= 2 # directory + file + row = rows[-1] + assert row["archivename"] == expected_name + assert row["archiveid"] == expected_id + + def test_list_depth(archivers, request): """Test the --depth option for the list command.""" archiver = request.getfixturevalue(archivers)