diff --git a/src/borg/archive.py b/src/borg/archive.py index 956c718872..830f392156 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -473,6 +473,7 @@ def __init__( self.name = name # overwritten later with name from archive metadata self.name_in_manifest = name # can differ from .name later (if borg check fixed duplicate archive names) self.comment = None + self.tags = None self.numeric_ids = numeric_ids self.noatime = noatime self.noctime = noctime @@ -495,6 +496,7 @@ def __init__( self.create = create if self.create: self.items_buffer = CacheChunkBuffer(self.cache, self.key, self.stats) + self.tags = set() else: if name_is_id: # we also go over the manifest here to avoid quick&dirty deleted archives @@ -521,6 +523,7 @@ def load(self, id): self.metadata = self._load_meta(self.id) self.name = self.metadata.name self.comment = self.metadata.get("comment", "") + self.tags = set(self.metadata.get("tags", [])) @property def ts(self): @@ -573,6 +576,7 @@ def info(self): "hostname": self.metadata.hostname, "username": self.metadata.username, "comment": self.metadata.get("comment", ""), + "tags": sorted(self.tags), "chunker_params": self.metadata.get("chunker_params", ""), } ) @@ -632,6 +636,7 @@ def save(self, name=None, comment=None, timestamp=None, stats=None, additional_m "version": 2, "name": name, "comment": comment or "", + "tags": list(sorted(self.tags)), "item_ptrs": item_ptrs, # see #1473 "command_line": join_cmd(sys.argv), "hostname": hostname, diff --git a/src/borg/archiver/info_cmd.py b/src/borg/archiver/info_cmd.py index aaaf1766fa..0afbb00096 100644 --- a/src/borg/archiver/info_cmd.py +++ b/src/borg/archiver/info_cmd.py @@ -32,6 +32,7 @@ def do_info(self, args, repository, manifest, cache): output_data.append(info) else: info["duration"] = format_timedelta(timedelta(seconds=info["duration"])) + info["tags"] = ",".join(info["tags"]) print( textwrap.dedent( """ @@ -40,6 +41,7 @@ def do_info(self, args, repository, manifest, cache): Comment: {comment} Hostname: {hostname} Username: {username} + Tags: {tags} Time (start): {start} Time (end): {end} Duration: {duration} diff --git a/src/borg/constants.py b/src/borg/constants.py index e24214e1ef..6d042d013e 100644 --- a/src/borg/constants.py +++ b/src/borg/constants.py @@ -12,6 +12,7 @@ # this set must be kept complete, otherwise rebuild_manifest might malfunction: # fmt: off ARCHIVE_KEYS = frozenset(['version', 'name', 'hostname', 'username', 'time', 'time_end', + 'tags', # v2+ archives 'items', # legacy v1 archives 'item_ptrs', # v2+ archives 'comment', 'chunker_params', diff --git a/src/borg/item.pyx b/src/borg/item.pyx index ff50912d49..e34c60f7f6 100644 --- a/src/borg/item.pyx +++ b/src/borg/item.pyx @@ -511,6 +511,7 @@ cdef class ArchiveItem(PropDict): time = PropDictProperty(str) time_end = PropDictProperty(str) comment = PropDictProperty(str, 'surrogate-escaped str') + tags = PropDictProperty(list) # list of s-e-str chunker_params = PropDictProperty(tuple) recreate_cmdline = PropDictProperty(list) # legacy, list of s-e-str recreate_command_line = PropDictProperty(str, 'surrogate-escaped str') diff --git a/src/borg/testsuite/archiver/info_cmd.py b/src/borg/testsuite/archiver/info_cmd.py index d94487bd13..d41f801c6e 100644 --- a/src/borg/testsuite/archiver/info_cmd.py +++ b/src/borg/testsuite/archiver/info_cmd.py @@ -32,6 +32,7 @@ def test_info_json(archivers, request): assert isinstance(archive["command_line"], str) assert isinstance(archive["duration"], float) assert len(archive["id"]) == 64 + assert archive["tags"] == [] assert "stats" in archive checkts(archive["start"]) checkts(archive["end"])