hgext/censor.py
branchstable
changeset 40404 956ec6f1320d
parent 40293 c303d65d2e34
child 43076 2372284d9457
--- a/hgext/censor.py	Wed Oct 10 12:25:28 2018 -0400
+++ b/hgext/censor.py	Mon Oct 22 14:46:06 2018 -0400
@@ -33,9 +33,7 @@
 from mercurial import (
     error,
     registrar,
-    revlog,
     scmutil,
-    util,
 )
 
 cmdtable = {}
@@ -49,7 +47,8 @@
 @command('censor',
     [('r', 'rev', '', _('censor file from specified revision'), _('REV')),
      ('t', 'tombstone', '', _('replacement tombstone data'), _('TEXT'))],
-    _('-r REV [-t TEXT] [FILE]'))
+    _('-r REV [-t TEXT] [FILE]'),
+    helpcategory=command.CATEGORY_MAINTENANCE)
 def censor(ui, repo, path, rev='', tombstone='', **opts):
     with repo.wlock(), repo.lock():
         return _docensor(ui, repo, path, rev, tombstone, **opts)
@@ -82,8 +81,11 @@
         raise error.Abort(_('file does not exist at revision %s') % rev)
 
     fnode = fctx.filenode()
-    headctxs = [repo[c] for c in repo.heads()]
-    heads = [c for c in headctxs if path in c and c.filenode(path) == fnode]
+    heads = []
+    for headnode in repo.heads():
+        hc = repo[headnode]
+        if path in hc and hc.filenode(path) == fnode:
+            heads.append(hc)
     if heads:
         headlist = ', '.join([short(c.node()) for c in heads])
         raise error.Abort(_('cannot censor file in heads (%s)') % headlist,
@@ -94,90 +96,5 @@
         raise error.Abort(_('cannot censor working directory'),
             hint=_('clean/delete/update first'))
 
-    flogv = flog.version & 0xFFFF
-    if flogv != revlog.REVLOGV1:
-        raise error.Abort(
-            _('censor does not support revlog version %d') % (flogv,))
-
-    tombstone = revlog.packmeta({"censored": tombstone}, "")
-
-    crev = fctx.filerev()
-
-    if len(tombstone) > flog.rawsize(crev):
-        raise error.Abort(_(
-            'censor tombstone must be no longer than censored data'))
-
-    # Using two files instead of one makes it easy to rewrite entry-by-entry
-    idxread = repo.svfs(flog.indexfile, 'r')
-    idxwrite = repo.svfs(flog.indexfile, 'wb', atomictemp=True)
-    if flog.version & revlog.FLAG_INLINE_DATA:
-        dataread, datawrite = idxread, idxwrite
-    else:
-        dataread = repo.svfs(flog.datafile, 'r')
-        datawrite = repo.svfs(flog.datafile, 'wb', atomictemp=True)
-
-    # Copy all revlog data up to the entry to be censored.
-    rio = revlog.revlogio()
-    offset = flog.start(crev)
-
-    for chunk in util.filechunkiter(idxread, limit=crev * rio.size):
-        idxwrite.write(chunk)
-    for chunk in util.filechunkiter(dataread, limit=offset):
-        datawrite.write(chunk)
-
-    def rewriteindex(r, newoffs, newdata=None):
-        """Rewrite the index entry with a new data offset and optional new data.
-
-        The newdata argument, if given, is a tuple of three positive integers:
-        (new compressed, new uncompressed, added flag bits).
-        """
-        offlags, comp, uncomp, base, link, p1, p2, nodeid = flog.index[r]
-        flags = revlog.gettype(offlags)
-        if newdata:
-            comp, uncomp, nflags = newdata
-            flags |= nflags
-        offlags = revlog.offset_type(newoffs, flags)
-        e = (offlags, comp, uncomp, r, link, p1, p2, nodeid)
-        idxwrite.write(rio.packentry(e, None, flog.version, r))
-        idxread.seek(rio.size, 1)
-
-    def rewrite(r, offs, data, nflags=revlog.REVIDX_DEFAULT_FLAGS):
-        """Write the given full text to the filelog with the given data offset.
-
-        Returns:
-            The integer number of data bytes written, for tracking data offsets.
-        """
-        flag, compdata = flog.compress(data)
-        newcomp = len(flag) + len(compdata)
-        rewriteindex(r, offs, (newcomp, len(data), nflags))
-        datawrite.write(flag)
-        datawrite.write(compdata)
-        dataread.seek(flog.length(r), 1)
-        return newcomp
-
-    # Rewrite censored revlog entry with (padded) tombstone data.
-    pad = ' ' * (flog.rawsize(crev) - len(tombstone))
-    offset += rewrite(crev, offset, tombstone + pad, revlog.REVIDX_ISCENSORED)
-
-    # Rewrite all following filelog revisions fixing up offsets and deltas.
-    for srev in xrange(crev + 1, len(flog)):
-        if crev in flog.parentrevs(srev):
-            # Immediate children of censored node must be re-added as fulltext.
-            try:
-                revdata = flog.revision(srev)
-            except error.CensoredNodeError as e:
-                revdata = e.tombstone
-            dlen = rewrite(srev, offset, revdata)
-        else:
-            # Copy any other revision data verbatim after fixing up the offset.
-            rewriteindex(srev, offset)
-            dlen = flog.length(srev)
-            for chunk in util.filechunkiter(dataread, limit=dlen):
-                datawrite.write(chunk)
-        offset += dlen
-
-    idxread.close()
-    idxwrite.close()
-    if dataread is not idxread:
-        dataread.close()
-        datawrite.close()
+    with repo.transaction(b'censor') as tr:
+        flog.censorrevision(tr, fnode, tombstone=tombstone)