Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/websdk/mercurial/repair.py
diff options
context:
space:
mode:
Diffstat (limited to 'websdk/mercurial/repair.py')
-rw-r--r--[l---------]websdk/mercurial/repair.py159
1 files changed, 158 insertions, 1 deletions
diff --git a/websdk/mercurial/repair.py b/websdk/mercurial/repair.py
index 008f132..c95dff1 120000..100644
--- a/websdk/mercurial/repair.py
+++ b/websdk/mercurial/repair.py
@@ -1 +1,158 @@
-/usr/share/pyshared/mercurial/repair.py \ No newline at end of file
+# repair.py - functions for repository repair for mercurial
+#
+# Copyright 2005, 2006 Chris Mason <mason@suse.com>
+# Copyright 2007 Matt Mackall
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from mercurial import changegroup, bookmarks
+from mercurial.node import short
+from mercurial.i18n import _
+import os
+
+def _bundle(repo, bases, heads, node, suffix, compress=True):
+ """create a bundle with the specified revisions as a backup"""
+ cg = repo.changegroupsubset(bases, heads, 'strip')
+ backupdir = repo.join("strip-backup")
+ if not os.path.isdir(backupdir):
+ os.mkdir(backupdir)
+ name = os.path.join(backupdir, "%s-%s.hg" % (short(node), suffix))
+ if compress:
+ bundletype = "HG10BZ"
+ else:
+ bundletype = "HG10UN"
+ return changegroup.writebundle(cg, name, bundletype)
+
+def _collectfiles(repo, striprev):
+ """find out the filelogs affected by the strip"""
+ files = set()
+
+ for x in xrange(striprev, len(repo)):
+ files.update(repo[x].files())
+
+ return sorted(files)
+
+def _collectbrokencsets(repo, files, striprev):
+ """return the changesets which will be broken by the truncation"""
+ s = set()
+ def collectone(revlog):
+ links = (revlog.linkrev(i) for i in revlog)
+ # find the truncation point of the revlog
+ for lrev in links:
+ if lrev >= striprev:
+ break
+ # see if any revision after this point has a linkrev
+ # less than striprev (those will be broken by strip)
+ for lrev in links:
+ if lrev < striprev:
+ s.add(lrev)
+
+ collectone(repo.manifest)
+ for fname in files:
+ collectone(repo.file(fname))
+
+ return s
+
+def strip(ui, repo, node, backup="all"):
+ cl = repo.changelog
+ # TODO delete the undo files, and handle undo of merge sets
+ striprev = cl.rev(node)
+
+ keeppartialbundle = backup == 'strip'
+
+ # Some revisions with rev > striprev may not be descendants of striprev.
+ # We have to find these revisions and put them in a bundle, so that
+ # we can restore them after the truncations.
+ # To create the bundle we use repo.changegroupsubset which requires
+ # the list of heads and bases of the set of interesting revisions.
+ # (head = revision in the set that has no descendant in the set;
+ # base = revision in the set that has no ancestor in the set)
+ tostrip = set(cl.descendants(striprev))
+ tostrip.add(striprev)
+
+ files = _collectfiles(repo, striprev)
+ saverevs = _collectbrokencsets(repo, files, striprev)
+
+ # compute heads
+ saveheads = set(saverevs)
+ for r in xrange(striprev + 1, len(cl)):
+ if r not in tostrip:
+ saverevs.add(r)
+ saveheads.difference_update(cl.parentrevs(r))
+ saveheads.add(r)
+ saveheads = [cl.node(r) for r in saveheads]
+
+ # compute base nodes
+ if saverevs:
+ descendants = set(cl.descendants(*saverevs))
+ saverevs.difference_update(descendants)
+ savebases = [cl.node(r) for r in saverevs]
+
+ bm = repo._bookmarks
+ updatebm = []
+ for m in bm:
+ rev = repo[bm[m]].rev()
+ if rev in tostrip:
+ updatebm.append(m)
+
+ # create a changegroup for all the branches we need to keep
+ backupfile = None
+ if backup == "all":
+ backupfile = _bundle(repo, [node], cl.heads(), node, 'backup')
+ repo.ui.status(_("saved backup bundle to %s\n") % backupfile)
+ if saveheads or savebases:
+ # do not compress partial bundle if we remove it from disk later
+ chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp',
+ compress=keeppartialbundle)
+
+ mfst = repo.manifest
+
+ tr = repo.transaction("strip")
+ offset = len(tr.entries)
+
+ try:
+ tr.startgroup()
+ cl.strip(striprev, tr)
+ mfst.strip(striprev, tr)
+ for fn in files:
+ repo.file(fn).strip(striprev, tr)
+ tr.endgroup()
+
+ try:
+ for i in xrange(offset, len(tr.entries)):
+ file, troffset, ignore = tr.entries[i]
+ repo.sopener(file, 'a').truncate(troffset)
+ tr.close()
+ except:
+ tr.abort()
+ raise
+
+ if saveheads or savebases:
+ ui.note(_("adding branch\n"))
+ f = open(chgrpfile, "rb")
+ gen = changegroup.readbundle(f, chgrpfile)
+ if not repo.ui.verbose:
+ # silence internal shuffling chatter
+ repo.ui.pushbuffer()
+ repo.addchangegroup(gen, 'strip', 'bundle:' + chgrpfile, True)
+ if not repo.ui.verbose:
+ repo.ui.popbuffer()
+ f.close()
+ if not keeppartialbundle:
+ os.unlink(chgrpfile)
+
+ for m in updatebm:
+ bm[m] = repo['.'].node()
+ bookmarks.write(repo)
+
+ except:
+ if backupfile:
+ ui.warn(_("strip failed, full bundle stored in '%s'\n")
+ % backupfile)
+ elif saveheads:
+ ui.warn(_("strip failed, partial bundle stored in '%s'\n")
+ % chgrpfile)
+ raise
+
+ repo.destroyed()