diff --git a/hgext3rd/undo.py b/hgext3rd/undo.py --- a/hgext3rd/undo.py +++ b/hgext3rd/undo.py @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. from __future__ import absolute_import -import os +import weakref from mercurial.i18n import _ @@ -19,6 +19,7 @@ revset, revsetlang, smartset, + transaction, util, ) @@ -31,6 +32,11 @@ cmdtable = {} command = registrar.command(cmdtable) +# Setup + +def extsetup(ui): + extensions.wrapfunction(dispatch, 'runcommand', _runcommandwrapper) + # Wrappers def _runcommandwrapper(orig, lui, repo, cmd, fullargs, *args): @@ -42,7 +48,7 @@ # Check wether undolog is consistent # ie check wether the undo ext was # off before this command - safelog(repo, "") + safelog(repo, [""]) result = orig(lui, repo, cmd, fullargs, *args) @@ -53,10 +59,23 @@ # Write: Log control def safelog(repo, command): + changes = False if repo is not None:# some hg commands don't require repo with repo.lock(): - with repo.transaction("undolog"): - log(repo.filtered('visible'), command) + with lighttransaction(repo): + changes = log(repo.filtered('visible'), command) + return changes + +def lighttransaction(repo): + # full fledged transactions have two serious issues: + # 1. they may cause infite loops through hooks + # that run commands + # 2. they are really expensive performance wise + vfsmap = {'plain': repo.vfs} + tr = transaction.transaction(repo.ui.warn, repo.svfs, vfsmap, + "_undojournal", "_undolog") + repo._transref = weakref.ref(tr) + return tr def log(repo, command): newnodes = { @@ -69,24 +88,24 @@ except IndexError: exsistingnodes = {} if all(newnodes.get(x) == exsistingnodes.get(x) for x in newnodes.keys()): - return + return False else: newnodes.update({ 'date': _logdate(repo), 'command': _logcommand(repo, command), }) _logindex(repo, newnodes) + return True # Write: Logs def writelog(repo, name, revstring): - assert repo.currenttransaction() is not None - # The transaction code doesn't work with vfs + tr = repo.currenttransaction() + assert tr is not None + # the transaction code doesn't work with vfs # specifically, repo.recover() assumes svfs? repo.svfs.makedirs('undolog') - path = os.path.join('undolog', name) - rlog = revlog.revlog(repo.svfs, path) - tr = repo.currenttransaction() + rlog = _getrevlog(repo, name) node = rlog.addrevision(revstring, tr, 1, nullid, nullid) return hex(node) @@ -122,11 +141,10 @@ def _readindex(repo, reverseindex, prefetchedrevlog=None): if prefetchedrevlog is None: - path = os.path.join('undolog', 'index.i') - rlog = revlog.revlog(repo.svfs, path) + rlog = _getrevlog(repo, 'index.i') else: rlog = prefetchedrevlog - index = len(rlog) - reverseindex - 1 + index = _invertindex(rlog, reverseindex) if index < 0 or index > len(rlog) - 1: raise IndexError chunk = rlog.revision(index) @@ -138,8 +156,7 @@ return indexdict def _readnode(repo, filename, hexnode): - path = os.path.join('undolog', filename) - rlog = revlog.revlog(repo.svfs, path) + rlog = _getrevlog(repo, filename) return rlog.revision(bin(hexnode)) # Visualize @@ -154,19 +171,19 @@ ('n', 'index', 0, _("details about specific operation")), ('l', 'list', False, _("list recent undo-able operation")) ]) -def debugundohistory(ui, repo, *args, **kwargs): +def debugundohistory(ui, repo, *args, **opts): """ Print operational history 0 is the most recent operation """ if repo is not None: - if kwargs.get('list'): + if opts.get('list'): if args and args[0].isdigit(): offset = int(args[0]) else: offset = 0 _debugundolist(ui, repo, offset) else: - reverseindex = kwargs.get('index') + reverseindex = opts.get('index') if 0 == reverseindex and args and args[0].isdigit(): reverseindex = int(args[0]) _debugundoindex(ui, repo, reverseindex) @@ -176,9 +193,7 @@ template = "{sub('\0', ' ', undo)}\n" fm = ui.formatter('debugundohistory', {'template': template}) - path = os.path.join('undolog', 'index.i') - - prefetchedrevlog = revlog.revlog(repo.svfs, path) + prefetchedrevlog = _getrevlog(repo, 'index.i') recentrange = min(5, len(prefetchedrevlog) - offset) if 0 == recentrange: fm.startitem() @@ -186,6 +201,8 @@ for i in range(recentrange): nodedict = _readindex(repo, i + offset, prefetchedrevlog) commandstr = _readnode(repo, 'command.i', nodedict['command']) + if "" == commandstr: + commandstr = " -- gap in log -- " fm.startitem() fm.write('undo', '%s', str(i + offset) + ": " + commandstr) fm.end() @@ -211,7 +228,7 @@ try: oldnodes = _readindex(repo, reverseindex + 1) oldheads = _readnode(repo, filename, oldnodes[filename[:-2]]) - except IndexError:# Index is oldest log + except IndexError:# index is oldest log content = rawcontent else: content = "ADDED:\n\t" + "\n\t".join(sorted( @@ -259,7 +276,11 @@ revs = _getolddrafts(repo, reverseindex) return smartset.baseset(revs) -# Setup +# Tools -def extsetup(ui): - extensions.wrapfunction(dispatch, 'runcommand', _runcommandwrapper) +def _invertindex(rlog, indexorreverseindex): + return len(rlog) - 1 - indexorreverseindex + +def _getrevlog(repo, filename): + path = 'undolog/' + filename + return revlog.revlog(repo.svfs, path) diff --git a/tests/test-undo.t b/tests/test-undo.t --- a/tests/test-undo.t +++ b/tests/test-undo.t @@ -121,7 +121,7 @@ $ touch a5 && hg add a5 && hg ci -ma5 $ hg debugundohistory -l 0: ci -ma5 - 1: + 1: -- gap in log -- 2: commit -m words 3: update master 4: commit --amend @@ -148,7 +148,8 @@ [255] Revset tests - $ hg log -G -r 'draft()' --hidden >> c1 + $ hg log -G -r 'draft()' --hidden | head -1 + @ changeset: 8:aa430c8afedf $ hg debugundohistory -n 0 command: ci -ma5