Mercurial > hg
comparison hgext/censor.py @ 27290:525d9b3f0a31
censor: make censor acquire locks before processing
Before this patch, "hg censor" executes below:
- without acquisition of wlock, examine whether the working
directory refers the revision of the file to be censored or not
- without acquisition of store lock (slock), replace existing
filelog of file to be censored with censored one,
Replacement consists of steps below, and it is assumed that the
destination filelog at (1) isn't changed before renaming at (3).
1. read existing filelog in
2. write filelog entries (both censored and not) into temporary file
3. rename from temporary file to existing filelog to be censored
It may cause unintentional result, if another command runs parallelly
(see also issue4368).
This patch makes "hg censor" acquire wlock and slock before
processing.
author | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> |
---|---|
date | Wed, 09 Dec 2015 08:28:53 +0900 |
parents | 1aee2ab0f902 |
children | 5166b7a84b72 |
comparison
equal
deleted
inserted
replaced
27289:ee33e677f0ac | 27290:525d9b3f0a31 |
---|---|
26 """ | 26 """ |
27 | 27 |
28 from mercurial.node import short | 28 from mercurial.node import short |
29 from mercurial import cmdutil, error, filelog, revlog, scmutil, util | 29 from mercurial import cmdutil, error, filelog, revlog, scmutil, util |
30 from mercurial.i18n import _ | 30 from mercurial.i18n import _ |
31 from mercurial import lock as lockmod | |
31 | 32 |
32 cmdtable = {} | 33 cmdtable = {} |
33 command = cmdutil.command(cmdtable) | 34 command = cmdutil.command(cmdtable) |
34 # Note for extension authors: ONLY specify testedwith = 'internal' for | 35 # Note for extension authors: ONLY specify testedwith = 'internal' for |
35 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | 36 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should |
40 @command('censor', | 41 @command('censor', |
41 [('r', 'rev', '', _('censor file from specified revision'), _('REV')), | 42 [('r', 'rev', '', _('censor file from specified revision'), _('REV')), |
42 ('t', 'tombstone', '', _('replacement tombstone data'), _('TEXT'))], | 43 ('t', 'tombstone', '', _('replacement tombstone data'), _('TEXT'))], |
43 _('-r REV [-t TEXT] [FILE]')) | 44 _('-r REV [-t TEXT] [FILE]')) |
44 def censor(ui, repo, path, rev='', tombstone='', **opts): | 45 def censor(ui, repo, path, rev='', tombstone='', **opts): |
46 wlock = lock = None | |
47 try: | |
48 wlock = repo.wlock() | |
49 lock = repo.lock() | |
50 return _docensor(ui, repo, path, rev, tombstone, **opts) | |
51 finally: | |
52 lockmod.release(lock, wlock) | |
53 | |
54 def _docensor(ui, repo, path, rev='', tombstone='', **opts): | |
45 if not path: | 55 if not path: |
46 raise error.Abort(_('must specify file path to censor')) | 56 raise error.Abort(_('must specify file path to censor')) |
47 if not rev: | 57 if not rev: |
48 raise error.Abort(_('must specify revision to censor')) | 58 raise error.Abort(_('must specify revision to censor')) |
49 | 59 |