[PATCH] hgext: add smb extension
Sean Farley
sean at farley.io
Wed Apr 1 18:28:55 UTC 2015
# HG changeset patch
# User Sean Farley <sean at farley.io>
# Date 1427912211 25200
# Wed Apr 01 11:16:51 2015 -0700
# Node ID 35cf765458f06a7651d0e9ba9340d46369741616
# Parent 1b97cc5d2272c272961cc3e1d738e521af012a40
hgext: add smb extension
This extension brings the missing component of DVCS to Mercurial: sound
effects. Who doesn't want the sound of a vine growing when they 'hg log' or the
sound of a warping down a pipe when updating to an ancestor? I'll tell you.
Nobody.
For reference and a screencast, the extension is hosted at:
https://bitbucket.org/seanfarley/smb
diff --git a/hgext/smb.py b/hgext/smb.py
new file mode 100644
--- /dev/null
+++ b/hgext/smb.py
@@ -0,0 +1,209 @@
+import inspect
+import os
+import subprocess
+
+from mercurial import _
+from mercurial import commands
+from mercurial import error
+from mercurial import extensions
+from mercurial import dispatch
+from mercurial import hg
+from mercurial import obsolete
+from mercurial import scmutil
+from mercurial import util
+
+######################
+# audio player methods
+######################
+
+def is_exe(fpath):
+ return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+def which(program):
+ fpath, fname = os.path.split(program)
+ if fpath:
+ if is_exe(program):
+ return program
+ else:
+ for path in os.environ["PATH"].split(os.pathsep):
+ path = path.strip('"')
+ exe_file = os.path.join(path, program)
+ if is_exe(exe_file):
+ return exe_file
+
+ return None
+
+def audioplayer():
+ for p in ('afplay', 'aplay', 'mpg123'):
+ found = which(p)
+ if found is not None:
+ return found
+ return None
+
+def play(repo, sound):
+ if repo is None or not repo.ui.interactive():
+ return
+ player = audioplayer()
+ hasplayed = False
+ if os.path.exists(repo.join('smbrebasehack')):
+ os.remove(repo.join('smbrebasehack'))
+ hasplayed = True
+
+ if player and not hasplayed:
+ datapath = os.path.dirname(os.path.realpath(__file__))
+ datapath = os.path.join(datapath, 'data')
+ if not sound.endswith('.wav'):
+ sound = sound + '.wav'
+ subprocess.Popen([player, os.path.join(datapath, sound)],
+ stdout=open(os.devnull, 'w'),
+ stderr=subprocess.STDOUT)
+
+##############################
+# mercurial extension wrappers
+##############################
+
+def extsetup(ui):
+ extensions.wrapfunction(dispatch, 'runcommand', wrapruncommand)
+ extensions.wrapfunction(hg, 'updaterepo', wrapupdate)
+
+ extensions.wrapcommand(commands.table, 'log', wraplog)
+ extensions.wrapcommand(commands.table, 'commit', wrapcommit)
+
+ try:
+ rebase = extensions.find('rebase')
+ if rebase:
+ extensions.wrapcommand(rebase.cmdtable, 'rebase', wraprebase)
+ except:
+ pass
+
+ try:
+ histedit = extensions.find('histedit')
+ if histedit:
+ extensions.wrapfunction(histedit, 'finishfold', wrapfold)
+ except:
+ pass
+
+ try:
+ purge = extensions.find('purge')
+ if purge:
+ extensions.wrapcommand(purge.cmdtable, 'purge', wrappurge)
+ except:
+ pass
+
+ try:
+ evolve = extensions.find('evolve')
+ if evolve:
+ extensions.wrapcommand(evolve.cmdtable, 'prune', wrapprune)
+ extensions.wrapcommand(evolve.cmdtable, 'amend', wrapamend)
+ except:
+ pass
+
+def wrapruncommand(orig, lui, repo, cmd, fullargs, ui, options, d, cmdpats,
+ cmdoptions):
+ try:
+ ret = orig(lui, repo, cmd, fullargs, ui, options, d, cmdpats,
+ cmdoptions)
+ return ret
+ except Exception as e:
+ # things to skip:
+ # - skip if broken pipe (such as quiting from a pager)
+ # - histedit in progress
+ if ((not util.safehasattr(e, 'errno') or e.errno != 32)
+ and e.message != 'histedit in progress'
+ and e.message != 'rebase in progress'):
+ if isinstance(e, error.InterventionRequired):
+ play(repo, 'smb_pause')
+ else:
+ play(repo, 'smb_gameover')
+ raise
+
+def wrapupdate(orig, repo, node, overwrite):
+ # copied from merge.update which should be extracted
+ wc = repo[None]
+ p1 = wc.parents()[0]
+ if node is None:
+ try:
+ node = repo.branchtip(wc.branch())
+ except error.RepoLookupError:
+ if wc.branch() == 'default':
+ node = repo.lookup('tip')
+ else:
+ raise util.Abort(_("branch %s not found") % wc.branch())
+
+ if p1.obsolete() and not p1.children():
+ # allow updating to successors
+ successors = obsolete.successorssets(repo, p1.node())
+ if successors:
+ successors = [n for sub in successors for n in sub]
+ node = repo.revs('max(%ln)', successors).first()
+
+ current = repo['.']
+ dest = repo[node]
+
+ # things to skip:
+ # - if current == dest
+ # - if we are in histedit
+ # - if we are in a rebase
+ skip = False
+ for frame in inspect.stack():
+ for s in ['rebase', 'hist', 'prune']:
+ if s in frame[3]:
+ skip = s
+ if skip:
+ break
+
+ if current != dest and not skip:
+ # are we moving from an ancestor to a descendant?
+ if current.descendant(dest):
+ play(repo, 'smb_flagpole')
+ # or from a descendat to ancestor?
+ elif dest.descendant(current):
+ play(repo, 'smb_pipe')
+ # or jumping across branches?
+ else:
+ play(repo, 'smb_jump')
+ return orig(repo, node, overwrite)
+
+def wraprebase(orig, ui, repo, **opts):
+ ret = orig(ui, repo, **opts)
+ play(repo, 'smb_die')
+ f = repo.vfs('smbrebasehack', 'w')
+ f.write("True")
+ f.close()
+ return ret
+
+def wraplog(orig, ui, repo, *args, **opts):
+ # double check rev exists so we don't play two sounds
+ rev = opts.get('rev')
+ skip = False
+ if rev and not scmutil.revrange(repo, opts.get('rev')):
+ skip = True
+ if not skip:
+ play(repo, 'smb_vine')
+ return orig(ui, repo, *args, **opts)
+
+def wrapcommit(orig, ui, repo, *args, **opts):
+ if opts.get('amend'):
+ play(repo, 'smb_kick')
+ else:
+ play(repo, 'smb_1up')
+ return orig(ui, repo, *args, **opts)
+
+def wrapfold(orig, ui, repo, ctx, oldctx, newnode, opts, internalchanges):
+ play(repo, 'smb_stomp')
+ return orig(ui, repo, ctx, oldctx, newnode, opts, internalchanges)
+
+def wrappurge(orig, ui, repo, *dirs, **opts):
+ play(repo, 'smb_bowserfire')
+ return orig(ui, repo, *dirs, **opts)
+
+def wrapprune(orig, ui, repo, *revs, **opts):
+ if opts.get('succ'):
+ play(repo, 'smb_kick')
+ else:
+ play(repo, 'smb_fireball')
+ return orig(ui, repo, *revs, **opts)
+
+def wrapamend(orig, ui, repo, *pats, **opts):
+ play(repo, 'smb_kick')
+ return orig(ui, repo, *pats, **opts)
More information about the Mercurial-devel
mailing list