From 1f8c0929bf5013d40c27e9cba84de9c8915c022b Mon Sep 17 00:00:00 2001 From: Marian Beermann Date: Thu, 23 Feb 2017 12:51:57 +0100 Subject: [PATCH] list: --json for archive contents listing --- src/borg/archiver.py | 8 ++++++-- src/borg/helpers.py | 42 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index e380917b4..f0e6d7e08 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -962,10 +962,12 @@ def _list_archive(self, args, repository, manifest, key, write): format = "{path}{NL}" else: format = "{mode} {user:6} {group:6} {size:8} {isomtime} {path}{extra}{NL}" - formatter = ItemFormatter(archive, format) + formatter = ItemFormatter(archive, format, json=args.json) + write(safe_encode(formatter.begin())) for item in archive.iter_items(lambda item: matcher.match(item.path)): write(safe_encode(formatter.format_item(item))) + write(safe_encode(formatter.end())) return self.exit_code def _list_repository(self, args, manifest, write): @@ -2504,7 +2506,9 @@ def process_epilog(epilog): help="""specify format for file listing (default: "{mode} {user:6} {group:6} {size:8d} {isomtime} {path}{extra}{NL}")""") subparser.add_argument('--json', action='store_true', - help='format output as JSON') + help='format output as JSON. The form of --format is ignored, but keys used in it ' + 'are added to the JSON output. Some keys are always present. Note: JSON can only ' + 'represent text. A "bpath" key is therefore not available.') subparser.add_argument('location', metavar='REPOSITORY_OR_ARCHIVE', nargs='?', default='', type=location_validator(), help='repository/archive to list contents of') diff --git a/src/borg/helpers.py b/src/borg/helpers.py index 89b557e57..9964cb448 100644 --- a/src/borg/helpers.py +++ b/src/borg/helpers.py @@ -5,6 +5,7 @@ import hashlib import logging import io +import json import os import os.path import platform @@ -1620,8 +1621,9 @@ def keys_help(cls): assert not keys, str(keys) return "\n".join(help) - def __init__(self, archive, format): + def __init__(self, archive, format, *, json=False): self.archive = archive + self.json = json static_keys = { 'archivename': archive.name, 'archiveid': archive.fpr, @@ -1646,7 +1648,34 @@ def __init__(self, archive, format): for hash_function in hashlib.algorithms_guaranteed: self.add_key(hash_function, partial(self.hash_item, hash_function)) self.used_call_keys = set(self.call_keys) & self.format_keys - self.item_data = static_keys + if self.json: + self.item_data = {} + self.format_item = self.format_item_json + self.first = True + else: + self.item_data = static_keys + + def begin(self): + from borg.archiver import BorgJsonEncoder + if not self.json: + return '' + return textwrap.dedent(""" + {{ + "repository": {repository}, + "files": [ + """).strip().format(repository=BorgJsonEncoder().encode(self.archive.repository)) + + def end(self): + if not self.json: + return '' + return "]}" + + def format_item_json(self, item): + if self.first: + self.first = False + return json.dumps(self.get_item_data(item)) + else: + return ',' + json.dumps(self.get_item_data(item)) def add_key(self, key, callable_with_item): self.call_keys[key] = callable_with_item @@ -1673,12 +1702,15 @@ def get_item_data(self, item): item_data['uid'] = item.uid item_data['gid'] = item.gid item_data['path'] = remove_surrogates(item.path) - item_data['bpath'] = item.path + if self.json: + item_data['healthy'] = 'chunks_healthy' not in item + else: + item_data['bpath'] = item.path + item_data['extra'] = extra + item_data['health'] = 'broken' if 'chunks_healthy' in item else 'healthy' item_data['source'] = source item_data['linktarget'] = source - item_data['extra'] = extra item_data['flags'] = item.get('bsdflags') - item_data['health'] = 'broken' if 'chunks_healthy' in item else 'healthy' for key in self.used_call_keys: item_data[key] = self.call_keys[key](item) return item_data