Grabbing git patches via gmail
I’m a rabid gmail user. I pretty much funnel every piece of email I get from my various email addresses into google. Yes, I drank the kool-aide(tm). What’s it you ya? Wanna fight about it?
Anyhoo, I wanted a system where I could use all of the goodness of git-am without having to actually use something other than my beloved gmail. So, using a little python, libgmail and a hacked up “archive.py” script that came with libgmail, I set out to do what I wanted. I am on a Mac, so I do get the added benefit of having all that unix email goodness built right in.
The basic idea is simple. When a patch comes in that I care about, I tag it with “Patches” in gmail. Then I drop to command line and run this script. It basically logs in to gmail, looks for any messages tagged as “Patches” and copies them to my local (and usually unused) unix user’s inbox. It then removes the “Patches” tag and adds the “Old Patches” tag.
The script looks like so:
#!/usr/bin/env python # # Grab email from a gmail label, load it into your local inbox, and # change the label to something else. # # Author: ted@tedkulp.com # Based on code by: follower@myrealbox.com # # License: GPL 2.0 # import os import sys import logging import time import datetime # Allow us to run using installed `libgmail` or the one in parent directory. try: import libgmail logging.warn("Note: Using currently installed `libgmail` version.") except ImportError: # Urghhh... sys.path.insert(1, os.path.realpath(os.path.join(os.path.dirname(__file__),os.path.pardir))) if __name__ == "__main__": import libgmail import sys from getpass import getpass username = 'username' password = 'password' new_label = 'Patches' old_label = 'Old Patches' mbox_dir = '/var/mail/tedkulp' #Change to inbox for your user ga = libgmail.GmailAccount(username, password) print "\nPlease wait, logging in..." try: ga.login() except libgmail.GmailLoginFailure: print "\nLogin failed. (Wrong username/password?)" else: print "Log in successful.\n" result = ga.getMessagesByLabel(new_label, True) print mbox = [] if len(result): for thread in reversed(result): print print thread.id, len(thread), thread.subject for msg in reversed(thread): print " ", msg.id, msg.number, msg.subject source = msg.source.replace("\r","").lstrip() mbox.append(datetime.datetime.now().strftime("From - %a %b %d %H:%m:%S %Y\n")) mbox.append(source) mbox.append("\n\n") #TODO:Check if we need either/both? thread.removeLabel(new_label) thread.addLabel(old_label) open(mbox_dir, "a").writelines(mbox) else: print "No threads found in `%s`." % new_label
And then just like Linus does on http://www.kernel.org/pub/software/scm/git/docs/everyday.html, I can do stuff like:
$ mailx & s 2 3 4 5 ./+to-apply & d 2-5 & q $ git checkout -b topic/one master $ git am -3 -i -s -u ./+to-apply
Beautiful.
Edit
05/20/2008 - I’ve updated the code a bit. There was a nesting issue that was causing messages to be pulled multiple times. I’ve also added the current date at the time of the pull instead of the 1998 date, and also pulling them in opposite order so that they are pushed into the inbox in the order they were received.
Ted @ May 8, 2008