mercurial/revlogutils/censor.py
changeset 47391 33d626910374
parent 47389 e6292eb33384
child 47392 8089d0fa8400
equal deleted inserted replaced
47390:65b86f516ba2 47391:33d626910374
       
     1 # censor code related to censoring revision
       
     2 #
       
     3 # Copyright 2021 Pierre-Yves David <pierre-yves.david@octobus.net>
       
     4 # Copyright 2015 Google, Inc <martinvonz@google.com>
       
     5 #
       
     6 # This software may be used and distributed according to the terms of the
       
     7 # GNU General Public License version 2 or any later version.
       
     8 
       
     9 from ..node import (
       
    10     nullrev,
       
    11 )
       
    12 from ..i18n import _
       
    13 from .. import (
       
    14     error,
       
    15 )
       
    16 from ..utils import (
       
    17     storageutil,
       
    18 )
       
    19 from . import constants
       
    20 
       
    21 
       
    22 def v1_censor(rl, tr, censornode, tombstone=b''):
       
    23     """censors a revision in a "version 1" revlog"""
       
    24     assert rl._format_version == constants.REVLOGV1, rl._format_version
       
    25 
       
    26     # avoid cycle
       
    27     from .. import revlog
       
    28 
       
    29     censorrev = rl.rev(censornode)
       
    30     tombstone = storageutil.packmeta({b'censored': tombstone}, b'')
       
    31 
       
    32     if len(tombstone) > rl.rawsize(censorrev):
       
    33         raise error.Abort(
       
    34             _(b'censor tombstone must be no longer than censored data')
       
    35         )
       
    36 
       
    37     # Rewriting the revlog in place is hard. Our strategy for censoring is
       
    38     # to create a new revlog, copy all revisions to it, then replace the
       
    39     # revlogs on transaction close.
       
    40     #
       
    41     # This is a bit dangerous. We could easily have a mismatch of state.
       
    42     newrl = revlog.revlog(
       
    43         rl.opener,
       
    44         target=rl.target,
       
    45         radix=rl.radix,
       
    46         postfix=b'tmpcensored',
       
    47         censorable=True,
       
    48     )
       
    49     newrl._format_version = rl._format_version
       
    50     newrl._format_flags = rl._format_flags
       
    51     newrl._generaldelta = rl._generaldelta
       
    52     newrl._parse_index = rl._parse_index
       
    53 
       
    54     for rev in rl.revs():
       
    55         node = rl.node(rev)
       
    56         p1, p2 = rl.parents(node)
       
    57 
       
    58         if rev == censorrev:
       
    59             newrl.addrawrevision(
       
    60                 tombstone,
       
    61                 tr,
       
    62                 rl.linkrev(censorrev),
       
    63                 p1,
       
    64                 p2,
       
    65                 censornode,
       
    66                 constants.REVIDX_ISCENSORED,
       
    67             )
       
    68 
       
    69             if newrl.deltaparent(rev) != nullrev:
       
    70                 m = _(b'censored revision stored as delta; cannot censor')
       
    71                 h = _(
       
    72                     b'censoring of revlogs is not fully implemented;'
       
    73                     b' please report this bug'
       
    74                 )
       
    75                 raise error.Abort(m, hint=h)
       
    76             continue
       
    77 
       
    78         if rl.iscensored(rev):
       
    79             if rl.deltaparent(rev) != nullrev:
       
    80                 m = _(
       
    81                     b'cannot censor due to censored '
       
    82                     b'revision having delta stored'
       
    83                 )
       
    84                 raise error.Abort(m)
       
    85             rawtext = rl._chunk(rev)
       
    86         else:
       
    87             rawtext = rl.rawdata(rev)
       
    88 
       
    89         newrl.addrawrevision(
       
    90             rawtext, tr, rl.linkrev(rev), p1, p2, node, rl.flags(rev)
       
    91         )
       
    92 
       
    93     tr.addbackup(rl._indexfile, location=b'store')
       
    94     if not rl._inline:
       
    95         tr.addbackup(rl._datafile, location=b'store')
       
    96 
       
    97     rl.opener.rename(newrl._indexfile, rl._indexfile)
       
    98     if not rl._inline:
       
    99         rl.opener.rename(newrl._datafile, rl._datafile)
       
   100 
       
   101     rl.clearcaches()
       
   102     rl._loadindex()