From: Rob Browning Date: Sat, 14 Oct 2017 17:03:31 +0000 (-0500) Subject: Port rm and prune-older to vfs2 X-Git-Tag: 0.30~137 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=bup.git;a=commitdiff_plain;h=ce1c10b9366083a7c9e231a2b9d861d88432ff21 Port rm and prune-older to vfs2 Signed-off-by: Rob Browning Tested-by: Rob Browning --- diff --git a/cmd/prune-older-cmd.py b/cmd/prune-older-cmd.py index 12a440a..58c4d94 100755 --- a/cmd/prune-older-cmd.py +++ b/cmd/prune-older-cmd.py @@ -15,6 +15,7 @@ import re, sys from bup import git, options from bup.gc import bup_gc from bup.helpers import die_if_errors, log, partition, period_as_secs +from bup.repo import LocalRepo from bup.rm import bup_rm @@ -149,7 +150,8 @@ for branch, branch_id in branches(roots): if not opt.pretend: die_if_errors() - bup_rm(removals, compression=opt.compress, verbosity=opt.verbose) + repo = LocalRepo() + bup_rm(repo, removals, compression=opt.compress, verbosity=opt.verbose) if opt.gc: die_if_errors() bup_gc(threshold=opt.gc_threshold, diff --git a/cmd/rm-cmd.py b/cmd/rm-cmd.py index b4c2142..13cb058 100755 --- a/cmd/rm-cmd.py +++ b/cmd/rm-cmd.py @@ -10,6 +10,7 @@ import sys from bup.git import check_repo_or_die from bup.options import Options from bup.helpers import die_if_errors, handle_ctrl_c, log +from bup.repo import LocalRepo from bup.rm import bup_rm optspec = """ @@ -32,5 +33,6 @@ if len(extra) < 1: o.fatal('no paths specified') check_repo_or_die() -bup_rm(extra, compression=opt.compress, verbosity=opt.verbose) +repo = LocalRepo() +bup_rm(repo, extra, compression=opt.compress, verbosity=opt.verbose) die_if_errors() diff --git a/lib/bup/rm.py b/lib/bup/rm.py index 4f5742d..dfcdc01 100644 --- a/lib/bup/rm.py +++ b/lib/bup/rm.py @@ -1,7 +1,8 @@ import sys -from bup import git, vfs +from bup import git +from bup import vfs2 as vfs from bup.client import ClientError from bup.git import get_commit_items from bup.helpers import add_error, die_if_errors, log, saved_errors @@ -38,14 +39,19 @@ def filter_branch(tip_commit_hex, exclude, writer): last_c, tree = append_commit(c.encode('hex'), last_c, git.cp(), writer) return last_c +def commit_oid(item): + if isinstance(item, vfs.Commit): + return item.coid + assert isinstance(item, vfs.RevList) + return item.oid def rm_saves(saves, writer): assert(saves) - branch_node = saves[0].parent - for save in saves: # Be certain they're all on the same branch - assert(save.parent == branch_node) - rm_commits = frozenset([x.dereference().hash for x in saves]) - orig_tip = branch_node.hash + first_branch_item = saves[0][1] + for save, branch in saves: # Be certain they're all on the same branch + assert(branch == first_branch_item) + rm_commits = frozenset([commit_oid(save) for save, branch in saves]) + orig_tip = commit_oid(first_branch_item) new_tip = filter_branch(orig_tip.encode('hex'), lambda x: x in rm_commits, writer) @@ -54,7 +60,7 @@ def rm_saves(saves, writer): return orig_tip, new_tip -def dead_items(vfs_top, paths): +def dead_items(repo, paths): """Return an optimized set of removals, reporting errors via add_error, and if there are any errors, return None, None.""" dead_branches = {} @@ -62,41 +68,46 @@ def dead_items(vfs_top, paths): # Scan for bad requests, and opportunities to optimize for path in paths: try: - n = vfs_top.lresolve(path) - except vfs.NodeError as e: - add_error('unable to resolve %s: %s' % (path, e)) + resolved = vfs.lresolve(repo, path) + except vfs.IOError as e: + add_error(e) + continue else: - if isinstance(n, vfs.BranchList): # rm /foo - branchname = n.name - dead_branches[branchname] = n - dead_saves.pop(branchname, None) # rm /foo obviates rm /foo/bar - elif isinstance(n, vfs.FakeSymlink) and isinstance(n.parent, - vfs.BranchList): - if n.name == 'latest': + leaf_name, leaf_item = resolved[-1] + if not leaf_item: + add_error('error: cannot access %r in %r' + % ('/'.join(name for name, item in resolved), + path)) + continue + if isinstance(leaf_item, vfs.RevList): # rm /foo + branchname = leaf_name + dead_branches[branchname] = leaf_item + dead_saves.pop(branchname, None) # rm /foo obviates rm /foo/bar + elif isinstance(leaf_item, vfs.Commit): # rm /foo/bar + if leaf_name == 'latest': add_error("error: cannot delete 'latest' symlink") else: - branchname = n.parent.name + branchname, branchitem = resolved[-2] if branchname not in dead_branches: - dead_saves.setdefault(branchname, []).append(n) + dead = leaf_item, branchitem + dead_saves.setdefault(branchname, []).append(dead) else: - add_error("don't know how to remove %r yet" % n.fullname()) + add_error("don't know how to remove %r yet" % path) if saved_errors: return None, None return dead_branches, dead_saves -def bup_rm(paths, compression=6, verbosity=None): - root = vfs.RefList(None) - - dead_branches, dead_saves = dead_items(root, paths) +def bup_rm(repo, paths, compression=6, verbosity=None): + dead_branches, dead_saves = dead_items(repo, paths) die_if_errors('not proceeding with any removals\n') updated_refs = {} # ref_name -> (original_ref, tip_commit(bin)) - for branch, node in dead_branches.iteritems(): - ref = 'refs/heads/' + branch + for branchname, branchitem in dead_branches.iteritems(): + ref = 'refs/heads/' + branchname assert(not ref in updated_refs) - updated_refs[ref] = (node.hash, None) + updated_refs[ref] = (branchitem.oid, None) if dead_saves: writer = git.PackWriter(compression_level=compression)