58b06dbe838d — Alain Leufroy 5 years ago
🎉 version 0.1
3 files changed, 164 insertions(+), 0 deletions(-)

A => README
A => hgext3rd/autoshelve/__init__.py
A => hgext3rd/autoshelve/metadata.py
A => README +21 -0
@@ 0,0 1,21 @@ 
+========================================================
+Automatic dirty working directory shelving for Mercurial
+========================================================
+
+AutoShelve is a Mercurial extension that shelves modified files
+before applying changes to the repository then unshelve them.
+
+Why would I use it ?
+
+I not sure that there is a valid reason for using it. But it's a
+pragmatic solution for durty use cases. Autoshelve will avoid you
+wasting time until you meet and find a good solution.
+
+Note: Shelve operations may be very long for certain repositories. In
+      this cases you may want to disable or enable autoshelve in the
+      configuration file of the repository.
+
+
+
+
+

          
A => hgext3rd/autoshelve/__init__.py +78 -0
@@ 0,0 1,78 @@ 
+# Copyright 2019 Alain Leufroy
+#                Pythonian <contact@pythonian.fr>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+import random
+from functools import partial
+
+from mercurial import cmdutil, commands, extensions
+from mercurial.i18n import _
+
+from . import metadata
+
+__version__ = metadata.__version__
+__doc__ = metadata.__doc__
+testedwith = metadata.testedwith
+minimumhgversion = metadata.minimumhgversion
+buglink = metadata.buglink
+
+
+def extsetup(ui):
+    for cmd in metadata.COMMANDS:
+        _wrap_cmd(commands.table, cmd)
+    for extension, cmds in metadata.EXTENSIONS.items():
+        _uisetup_extension(extension, cmds)
+
+
+def _uisetup_extension(name, cmds):
+    extensions.afterloaded(
+        name,
+        partial(_wrap_extension_cmd, name=name, cmds=cmds)
+    )
+
+
+def _wrap_extension_cmd(name, cmds, loaded=None):
+    try:
+        extension = extensions.find(name)
+    except KeyError:
+        return
+    for cmd in cmds:
+        _wrap_cmd(extension.cmdtable, cmd)
+
+
+def _wrap_cmd(table, cmd):
+    entry = extensions.wrapcommand(
+        table, cmd, _autoshelve_cmd,
+        synopsis=metadata.SYNOPSIS, docstring=metadata.DOCSTRING
+    )
+    entry[1].append(
+        (b'', 'noshelve', None, _(b'Disable autoshelve')))
+
+
+def _autoshelve_cmd(orig, ui, repo, *values, **opts):
+    shelve_name = _generate_shelve_name(15)
+    shelved = False
+    if not opts.get('abort') and not opts.pop('noshelve', False):
+        shelved = _shelve(ui, repo, shelve_name) is None
+    output = orig(ui, repo, *values, **opts)
+    if shelved:
+        _unshelve(ui, repo, shelve_name)
+    return output
+
+
+def _generate_shelve_name(length):
+    urandom = random.SystemRandom()
+    str_format = 'autoshelve-%%0%dx' % length
+    return str_format % urandom.getrandbits(length * 4)
+
+
+def _shelve(ui, repo, shelve_name):
+    _alias, shelvecmd = cmdutil.findcmd(b'shelve', commands.table)
+    return shelvecmd[0](ui, repo, name=shelve_name, keep=False)
+
+
+def _unshelve(ui, repo, shelve_name):
+    _alias, unshelvecmd = cmdutil.findcmd(b'unshelve', commands.table)
+    unshelvecmd[0](ui, repo, name=shelve_name, keep=False)

          
A => hgext3rd/autoshelve/metadata.py +65 -0
@@ 0,0 1,65 @@ 
+# Copyright 2019 Alain Leufroy
+#                Pythonian <contact@pythonian.fr>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+__all__ = ['__version__', 'testedwith', 'minimumhgversion', 'buglink']
+
+__version__ = b'0.1'
+testedwith = b'5.1'
+minimumhgversion = b'5.1'
+buglink = b''
+
+SYNOPSIS = b'[--noshelve]'
+
+DOCSTRING = b'''
+    The autoshelve extension is activated. Dirty working directory
+    will be shelved before all then unshelved after all. You
+    can use --noshelve to inhibite this behaviour.'''
+
+COMMANDS = [
+    b'pull',
+    b'backout',
+    b'graft', b'merge',
+    b'bisect', b'update', b'import', b'unbundle'
+]
+
+EXTENSIONS = {
+    b'histedit': [b'histedit'],
+    b'rebase': [b'rebase'],
+    b'evolve': [
+        b'prune', b'rewind', b'touch', b'uncommit', b'split', b'pick',
+        b'metaedit', b'fold'
+    ]
+}
+__doc__ = b"""Automatic dirty working directory shelving.
+
+Automatically call `shelve` before a command then `unshelve`
+once it's done.
+
+Wrapped commands are %s.
+
+A `--noshelve` options is added to them to disable the feature.
+
+The unshelve operation is not performed when the main
+command fails. For example, rebasing a commit that results
+in conflicts will stop the unshelve operation. You will need
+to perform the unshelve manually afterward (`hg unshelve`)
+
+The unshelve operation may results in merge conflict. For example,
+updating to a commit onto which the shelved content cannot apply will
+results in merge conflicts. You have to:
+
+* fix the conflicts (`hg resolve --mark`) then continue the unshelve
+  operation (`hg unshelve --continue`)
+
+* or abort it (`hg unshelve --abort`).
+
+Shelves are named as `autoshelve-RANDOMHEX`, with an `autoshelve-`
+prefix flollwed by a random hex. They are removed immediatly, unless
+the command fails as explained previously. You can delete them using
+`hg shelve --delete --name autoshelve-RADOMEHEX`.
+""" % ', '.join(
+    "'%s'" % cmd for cmd in sorted(
+        COMMANDS + [cmd for cmds in EXTENSIONS.values() for cmd in cmds]))