Exporting MQ patches
I've been trying to use Mercurial Queues to manage my work on different tasks in several repositories. I try to name all my patches with the name of the bug it's related to; so for my recent work on getting Talos not skipping builds, I would call my patch 'bug468731'.
I noticed that I was running this series of steps a lot:
cd ~/mozilla/buildbot-configs
hg qdiff > ~/patches/bug468731-buildbot-configs.patch
cd ~/mozilla/buildbotcustom
hg qdiff > ~/patches/bug468731-buildbotcustom.patch
...and then uploading the resulting patch files as attachments to the bug. There's a lot of repetition and extra mental work in those steps:
- I have to type the bug number manually twice. This is annoying, and error-prone. I've made a typo on more than one occasion and then wasted a few minutes trying to track down where the file went.
- I have to type the correct repository name for each patch. Again, I've managed to screw this up in the past. Often I have several terminals open, one for each repository, and I can get mixed up as to which repository I've currently got active.
- mercurial already knows the bug number, since I've used it in the name of my patch.
- mercurial already knows which repository I'm in.
import os, hashlib
from mercurial import commands, util
from hgext import mq
def mkpatch(ui, repo, *pats, **opts):
"""Saves the current patch to a file called -.patch
in your patch directory (defaults to ~/patches)
"""
repo_name = os.path.basename(ui.config('paths', 'default'))
if opts.get('patchdir'):
patch_dir = opts.get('patchdir')
del opts['patchdir']
else:
patch_dir = os.path.expanduser(ui.config('mkpatch', 'patchdir', "~/patches"))
ui.pushbuffer()
mq.top(ui, repo)
patch_name = ui.popbuffer().strip()
if not os.path.exists(patch_dir):
os.makedirs(patch_dir)
elif not os.path.isdir(patch_dir):
raise util.Abort("%s is not a directory" % patch_dir)
ui.pushbuffer()
mq.diff(ui, repo, *pats, **opts)
patch_data = ui.popbuffer()
patch_hash = hashlib.new('sha1', patch_data).digest()
full_name = os.path.join(patch_dir, "%s-%s.patch" % (patch_name, repo_name))
i = 0
while os.path.exists(full_name):
file_hash = hashlib.new('sha1', open(full_name).read()).digest()
if file_hash == patch_hash:
ui.status("Patch is identical to ", full_name, "; not saving")
return
full_name = os.path.join(patch_dir, "%s-%s.patch.%i" % (patch_name, repo_name, i))
i += 1
open(full_name, "w").write(patch_data)
ui.status("Patch saved to ", full_name)
mkpatch_options = [
("", "patchdir", '', "patch directory"),
]
cmdtable = {
"mkpatch": (mkpatch, mkpatch_options + mq.cmdtable['^qdiff'][1], "hg mkpatch [OPTION]... [FILE]...")
}