##// END OF EJS Templates
strip: add a delayedstrip method that works in a transaction...
Jun Wu -
r33087:fcd1c483 default
parent child Browse files
Show More
@@ -253,6 +253,63 b' def strip(ui, repo, nodelist, backup=Tru'
253 # extensions can use it
253 # extensions can use it
254 return backupfile
254 return backupfile
255
255
256 def safestriproots(ui, repo, nodes):
257 """return list of roots of nodes where descendants are covered by nodes"""
258 torev = repo.unfiltered().changelog.rev
259 revs = set(torev(n) for n in nodes)
260 # tostrip = wanted - unsafe = wanted - ancestors(orphaned)
261 # orphaned = affected - wanted
262 # affected = descendants(roots(wanted))
263 # wanted = revs
264 tostrip = set(repo.revs('%ld-(::((roots(%ld)::)-%ld))', revs, revs, revs))
265 notstrip = revs - tostrip
266 if notstrip:
267 nodestr = ', '.join(sorted(short(repo[n].node()) for n in notstrip))
268 ui.warn(_('warning: orphaned descendants detected, '
269 'not stripping %s\n') % nodestr)
270 return [c.node() for c in repo.set('roots(%ld)', tostrip)]
271
272 class stripcallback(object):
273 """used as a transaction postclose callback"""
274
275 def __init__(self, ui, repo, backup, topic):
276 self.ui = ui
277 self.repo = repo
278 self.backup = backup
279 self.topic = topic or 'backup'
280 self.nodelist = []
281
282 def addnodes(self, nodes):
283 self.nodelist.extend(nodes)
284
285 def __call__(self, tr):
286 roots = safestriproots(self.ui, self.repo, self.nodelist)
287 if roots:
288 strip(self.ui, self.repo, roots, True, self.topic)
289
290 def delayedstrip(ui, repo, nodelist, topic=None):
291 """like strip, but works inside transaction and won't strip irreverent revs
292
293 nodelist must explicitly contain all descendants. Otherwise a warning will
294 be printed that some nodes are not stripped.
295
296 Always do a backup. The last non-None "topic" will be used as the backup
297 topic name. The default backup topic name is "backup".
298 """
299 tr = repo.currenttransaction()
300 if not tr:
301 nodes = safestriproots(ui, repo, nodelist)
302 return strip(ui, repo, nodes, True, topic)
303 # transaction postclose callbacks are called in alphabet order.
304 # use '\xff' as prefix so we are likely to be called last.
305 callback = tr.getpostclose('\xffstrip')
306 if callback is None:
307 callback = stripcallback(ui, repo, True, topic)
308 tr.addpostclose('\xffstrip', callback)
309 if topic:
310 callback.topic = topic
311 callback.addnodes(nodelist)
312
256 def striptrees(repo, tr, striprev, files):
313 def striptrees(repo, tr, striprev, files):
257 if 'treemanifest' in repo.requirements: # safe but unnecessary
314 if 'treemanifest' in repo.requirements: # safe but unnecessary
258 # otherwise
315 # otherwise
@@ -412,7 +412,7 b' class transaction(object):'
412
412
413 @active
413 @active
414 def addpostclose(self, category, callback):
414 def addpostclose(self, category, callback):
415 """add a callback to be called after the transaction is closed
415 """add or replace a callback to be called after the transaction closed
416
416
417 The transaction will be given as callback's first argument.
417 The transaction will be given as callback's first argument.
418
418
@@ -422,6 +422,11 b' class transaction(object):'
422 self._postclosecallback[category] = callback
422 self._postclosecallback[category] = callback
423
423
424 @active
424 @active
425 def getpostclose(self, category):
426 """return a postclose callback added before, or None"""
427 return self._postclosecallback.get(category, None)
428
429 @active
425 def addabort(self, category, callback):
430 def addabort(self, category, callback):
426 """add a callback to be called when the transaction is aborted.
431 """add a callback to be called when the transaction is aborted.
427
432
@@ -2,6 +2,7 b''
2 $ echo "usegeneraldelta=yes" >> $HGRCPATH
2 $ echo "usegeneraldelta=yes" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
3 $ echo "[extensions]" >> $HGRCPATH
4 $ echo "strip=" >> $HGRCPATH
4 $ echo "strip=" >> $HGRCPATH
5 $ echo "drawdag=$TESTDIR/drawdag.py" >> $HGRCPATH
5
6
6 $ restore() {
7 $ restore() {
7 > hg unbundle -q .hg/strip-backup/*
8 > hg unbundle -q .hg/strip-backup/*
@@ -940,4 +941,52 b' Error during post-close callback of the '
940 abort: boom
941 abort: boom
941 [255]
942 [255]
942
943
944 Use delayedstrip to strip inside a transaction
943
945
946 $ cd $TESTTMP
947 $ hg init delayedstrip
948 $ cd delayedstrip
949 $ hg debugdrawdag <<'EOS'
950 > D
951 > |
952 > C F H # Commit on top of "I",
953 > | |/| # Strip B+D+I+E+G+H+Z
954 > I B E G
955 > \|/
956 > A Z
957 > EOS
958
959 $ hg up -C I
960 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
961 $ echo 3 >> I
962 $ cat > $TESTTMP/delayedstrip.py <<EOF
963 > from mercurial import repair, commands
964 > def reposetup(ui, repo):
965 > def getnodes(expr):
966 > return [repo.changelog.node(r) for r in repo.revs(expr)]
967 > with repo.wlock():
968 > with repo.lock():
969 > with repo.transaction('delayedstrip'):
970 > repair.delayedstrip(ui, repo, getnodes('B+I+Z+D+E'), 'J')
971 > repair.delayedstrip(ui, repo, getnodes('G+H+Z'), 'I')
972 > commands.commit(ui, repo, message='J', date='0 0')
973 > EOF
974 $ hg log -r . -T '\n' --config extensions.t=$TESTTMP/delayedstrip.py
975 warning: orphaned descendants detected, not stripping 08ebfeb61bac, 112478962961, 7fb047a69f22
976 saved backup bundle to $TESTTMP/delayedstrip/.hg/strip-backup/f585351a92f8-81fa23b0-I.hg (glob)
977
978 $ hg log -G -T '{rev}:{node|short} {desc}' -r 'sort(all(), topo)'
979 @ 6:2f2d51af6205 J
980 |
981 o 3:08ebfeb61bac I
982 |
983 | o 5:64a8289d2492 F
984 | |
985 | o 2:7fb047a69f22 E
986 |/
987 | o 4:26805aba1e60 C
988 | |
989 | o 1:112478962961 B
990 |/
991 o 0:426bada5c675 A
992
General Comments 0
You need to be logged in to leave comments. Login now