##// END OF EJS Templates
censor: add a command flag to skip the head checks...
censor: add a command flag to skip the head checks In some case we spend hours of time checking the heads to censors a simple file is not a good behavior. Especially when censors is used to removed corrupted content.

File last commit:

r52161:622f00b3 default
r52161:622f00b3 default
Show More
censor.py
140 lines | 4.5 KiB | text/x-python | PythonLexer
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347 # Copyright (C) 2015 - Mike Edgar <adgar@google.com>
#
# This extension enables removal of file content at a given revision,
# rewriting the data/metadata of successive revisions to preserve revision log
# integrity.
"""erase file content at a given revision
The censor command instructs Mercurial to erase all content of a file at a given
revision *without updating the changeset hash.* This allows existing history to
remain valid while preventing future clones/pulls from receiving the erased
data.
Typical uses for censor are due to security or legal requirements, including::
Mads Kiilerich
spelling: trivial spell checking
r26781 * Passwords, private keys, cryptographic material
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347 * Licensed data/code/libraries for which the license has expired
* Personally Identifiable Information or other private data
Censored nodes can interrupt mercurial's typical operation whenever the excised
data needs to be materialized. Some commands, like ``hg cat``/``hg revert``,
simply fail when asked to produce censored data. Others, like ``hg verify`` and
``hg update``, must be capable of tolerating censored data to continue to
function in a meaningful way. Such commands only tolerate censored file
censor: mention that we check the heads in the help...
r52159 As having a censored version in a checkout is impractical. The current head
revisions of the repository are checked. If the revision to be censored is in
any of them the command will abort.
Jordi Gutiérrez Hermoso
censor: document that some commands simply ignore censored data...
r43623
A few informative commands such as ``hg grep`` will unconditionally
ignore censored data and merely report that it was encountered.
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347 """
Gregory Szorc
censor: use absolute_import
r28092
from mercurial.i18n import _
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347 from mercurial.node import short
Gregory Szorc
censor: use absolute_import
r28092
from mercurial import (
error,
Martin von Zweigbergk
errors: raise InputError from revsingle() iff revset provided by the user...
r48930 logcmdutil,
Yuya Nishihara
registrar: move cmdutil.command to registrar module (API)...
r32337 registrar,
Gregory Szorc
censor: use absolute_import
r28092 scmutil,
)
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347
cmdtable = {}
Yuya Nishihara
registrar: move cmdutil.command to registrar module (API)...
r32337 command = registrar.command(cmdtable)
Augie Fackler
extensions: change magic "shipped with hg" string...
r29841 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
Augie Fackler
extensions: document that `testedwith = 'internal'` is special...
r25186 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 testedwith = b'ships-with-hg-core'
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347
Augie Fackler
formatting: blacken the codebase...
r43346
@command(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'censor',
Augie Fackler
formatting: blacken the codebase...
r43346 [
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (
b'r',
b'rev',
b'',
_(b'censor file from specified revision'),
_(b'REV'),
),
censor: add a command flag to skip the head checks...
r52161 (
b'',
b'check-heads',
True,
_(b'check that repository heads are not affected'),
),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (b't', b'tombstone', b'', _(b'replacement tombstone data'), _(b'TEXT')),
Augie Fackler
formatting: blacken the codebase...
r43346 ],
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'-r REV [-t TEXT] [FILE]'),
Augie Fackler
formatting: blacken the codebase...
r43346 helpcategory=command.CATEGORY_MAINTENANCE,
)
censor: add a command flag to skip the head checks...
r52161 def censor(ui, repo, path, rev=b'', tombstone=b'', check_heads=True, **opts):
Matt Harbison
censor: use context manager for lock management
r38460 with repo.wlock(), repo.lock():
censor: add a command flag to skip the head checks...
r52161 return _docensor(
ui,
repo,
path,
rev,
tombstone,
check_heads=check_heads,
**opts,
)
FUJIWARA Katsunori
censor: make censor acquire locks before processing...
r27290
Augie Fackler
formatting: blacken the codebase...
r43346
censor: add a command flag to skip the head checks...
r52161 def _docensor(ui, repo, path, rev=b'', tombstone=b'', check_heads=True, **opts):
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347 if not path:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'must specify file path to censor'))
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347 if not rev:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'must specify revision to censor'))
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347
FUJIWARA Katsunori
censor: make various path forms available like other Mercurial commands...
r25806 wctx = repo[None]
m = scmutil.match(wctx, (path,))
if m.anypats() or len(m.files()) != 1:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'can only specify an explicit filename'))
FUJIWARA Katsunori
censor: make various path forms available like other Mercurial commands...
r25806 path = m.files()[0]
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347 flog = repo.file(path)
if not len(flog):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'cannot censor file with no history'))
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347
Martin von Zweigbergk
errors: raise InputError from revsingle() iff revset provided by the user...
r48930 rev = logcmdutil.revsingle(repo, rev, rev).rev()
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347 try:
ctx = repo[rev]
except KeyError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'invalid revision identifier %s') % rev)
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347
try:
fctx = ctx.filectx(path)
except error.LookupError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'file does not exist at revision %s') % rev)
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347
fnode = fctx.filenode()
censor: add a command flag to skip the head checks...
r52161 if check_heads:
heads = []
repo_heads = repo.heads()
msg = b'checking for the censored content in %d heads\n'
msg %= len(repo_heads)
ui.status(msg)
for headnode in repo_heads:
hc = repo[headnode]
if path in hc and hc.filenode(path) == fnode:
heads.append(hc)
if heads:
headlist = b', '.join([short(c.node()) for c in heads])
raise error.Abort(
_(b'cannot censor file in heads (%s)') % headlist,
hint=_(b'clean/delete and commit first'),
)
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347
wp = wctx.parents()
if ctx.node() in [p.node() for p in wp]:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'cannot censor working directory'),
hint=_(b'clean/delete/update first'),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Mike Edgar
censor: add censor command to hgext with basic client-side tests...
r24347
Gregory Szorc
revlog: move censor logic out of censor extension...
r39814 with repo.transaction(b'censor') as tr:
flog.censorrevision(tr, fnode, tombstone=tombstone)