diff --git a/marty/commands/diff.py b/marty/commands/diff.py new file mode 100644 index 0000000..e189170 --- /dev/null +++ b/marty/commands/diff.py @@ -0,0 +1,77 @@ +from marty.printer import printer +from marty.commands import Command + + +class Diff(Command): + + """ Make a diff of two backups or tree for a remote. + """ + + help = 'Make a diff of two backups or tree for a remote' + + def prepare(self): + self._aparser.add_argument('remote', nargs='?') + self._aparser.add_argument('ref_name') + self._aparser.add_argument('name') + + def _print_diff_tree(self, storage, ref_tree, tree, level=()): + last = False + next_level = level + (True,) + + ref_tree_set = set(ref_tree.names()) if ref_tree else set() + tree_set = set(tree.names()) + adds = tree_set.difference(ref_tree_set) + deletions = ref_tree_set.difference(tree_set) + + all_items = tree_set.union(ref_tree_set) + + for i, (name) in enumerate(sorted(all_items)): + if len(tree) == i + 1: + last = True + next_level = level + (False,) + header = ''.join([u'│ ' if x else ' ' for x in level]) + if last: + header += '└── ' + else: + header += '├── ' + + # setup filename colors + color = 'yellow' + ref_item = None + item = None + if name in adds: + item = tree[name] + color = 'green' + elif name in deletions: + item = ref_tree[name] + ref_item = ref_tree[name] + color = 'red' + else: + item = tree[name] + ref_item = ref_tree[name] + + filename = name.decode('utf-8', 'replace') + # only print filename when there is a diff + if name in adds or name in deletions or item.ref != ref_item.ref: + if item.type == 'tree': + printer.p('{h}{f}', + h=header, f=filename, color=color) + ref_object = storage.get_tree(ref_item.ref) if ref_item else None + self._print_diff_tree(storage, ref_object, + storage.get_tree(item.ref), + level=next_level) + elif item.get('filetype') == 'link': + link = item.get('link', '?').decode('utf-8', 'replace') + printer.p('{h}{f} -> {l}', + h=header, f=filename, l=link, + color=color) + else: + printer.p('{h}{f}', + h=header, color=color, f=filename) + + def run(self, args, config, storage, remotes): + ref_name = '%s/%s' % (args.remote, args.ref_name) if args.remote else args.ref_name + other_name = '%s/%s' % (args.remote, args.name) if args.remote else args.name + ref_tree = storage.get_tree(ref_name) + other_tree = storage.get_tree(other_name) + self._print_diff_tree(storage, ref_tree, other_tree) diff --git a/setup.py b/setup.py index 228a436..9062d15 100644 --- a/setup.py +++ b/setup.py @@ -34,7 +34,8 @@ 'restore = marty.commands.restore:Restore', 'check = marty.commands.check:Check', 'mount = marty.commands.mount:Mount', - 'explore = marty.commands.mount:Explore'], + 'explore = marty.commands.mount:Explore', + 'diff = marty.commands.diff:Diff'], 'marty.storages': ['filesystem = marty.storages.filesystem:Filesystem'], 'marty.remotemethods': ['local = marty.remotemethods.local:Local', 'ssh = marty.remotemethods.ssh:SSH',