On 09/17/2010 10:28 AM, Adam Young wrote:

Here’s a little ditty I wrote to et patches in the format we use for the
FreeIPA mailing list:

Attached is my python script to do something similar. It keeps all the patches I've generated in a patch directory, numbers them, sends them as a properly formatted email (optional).

--
John Dennis <jden...@redhat.com>

Looking to carve out IT costs?
www.redhat.com/carveoutcosts/
#!/usr/bin/python

import getopt
import os
import errno
import sys
import subprocess
import re
import smtplib
import email
from cStringIO import StringIO
from email.generator import Generator
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase

#-------------------------------------------------------------------------------

prog_name = sys.argv[0]

config = {
    'patch_dir'             : '/home/jdennis/freeipa-patches',
    'smtp_server'           : 'smtp.corp.redhat.com',
    'email_from_addr'       : 'John Dennis <jden...@redhat.com>',
    #'email_to_addrs'        : ['jden...@redhat.com'],
    'email_to_addrs'        : ['freeipa-devel@redhat.com'],
    'start_number_basename' : 'StartNumber',
    'default_number'        : 2,
    'number'                : None,
    'send'                  : False,
    'run_format'            : True,
    'dry_run'               : False,
    'verbose'               : False,
}

signature = '''
-- 
John Dennis <jden...@redhat.com>

Looking to carve out IT costs?
www.redhat.com/carveoutcosts/
'''


#-------------------------------------------------------------------------------

class CommandError(Exception):
    def __init__(self, cmd, msg):
        self.cmd = cmd
        self.msg = msg

    def __str__(self):
        return "COMMAND ERROR: cmd='%s'\n%s" % (self.cmd, self.msg)

def run_cmd(cmd):
    if config['dry_run']:
        print >>sys.stdout, cmd
        return
    p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, 
stderr=subprocess.PIPE)
    status = os.waitpid(p.pid, 0)[1]
    msg = p.stdout.read().strip()
    if (status != 0):
        err_msg = p.stderr.read().strip()
        raise CommandError(cmd, err_msg)
    print >>sys.stdout, msg

def next_number():
    try:
        f = open(config['start_number_filepath'], 'r')
        number = int(f.read())
        f.close()
        if config['verbose']:
            print "number %d read from '%s'" % (number, 
config['start_number_filepath'])
    except Exception, e:
        if e.errno == errno.ENOENT:
            number = config['default_number']
            if config['verbose']:
                print "'%s' does not exist yet, using default %d" % 
(config['start_number_filepath'], number)
        else:
            raise

    if not config['dry_run']:
        f = open(config['start_number_filepath'], 'w')
        f.write('%d\n' % (number + 1))
        f.close()

    return number

def find_patch(number):
    filename_re = re.compile('^0*%d-(.*).patch$' % number)
    for filename in os.listdir(config['patch_dir']):
        match = filename_re.search(filename)
        if match:
            patch_filename = filename
            return os.path.join(config['patch_dir'], patch_filename)
    return None

def send_patch(filename):
    f = open(filename)
    patch = email.email.message_from_file(f)
    f.close()

    patch_name = os.path.basename(filename)

    # Get the entire raw message, including headers
    if False:
        f = StringIO()
        g = Generator(f, mangle_from_=False, maxheaderlen=0)
        g.flatten(patch)
        raw_msg = f.getvalue()
    else:
        f = open(filename)
        raw_msg = f.read()
        f.close()

    payload = patch.get_payload()
    i = payload.find('\n---\n')
    if i == -1:
        commit_msg = ''
    else:
        commit_msg = payload[:i]

    msg = MIMEMultipart()

    mime_part = MIMEText(commit_msg + '\n' + signature)
    msg.attach(mime_part)

    mime_part = MIMEBase('text', 'x-patch', name=patch_name)
    mime_part.set_charset('utf-8')
    mime_part.add_header('Content-Disposition', 'attachment', 
filename=patch_name)
    mime_part.set_payload(raw_msg)
    email.encoders.encode_base64(mime_part)
    msg.attach(mime_part)

    msg['Subject'] = patch['subject']
    msg['From']    = config['email_from_addr']
    msg['To']      = ', '.join(config['email_to_addrs'])

    if config['dry_run']:
        print msg
    else:
        s = smtplib.SMTP(config['smtp_server'])
        s.sendmail(config['email_from_addr'], config['email_to_addrs'], 
msg.as_string())
        s.quit()
    

def usage():
    '''
    Print command help.
    '''

    print '''\
-h --help               print help
-n --number nn          use this number for patch instead of next sequence 
number
-s --send               send patch using git send-email
-N --dry-run            don't execute, just report what would have been done
-F --no-format          don't run git format-patch

Examples:

Run command at minutes after the hour
%(prog_name)s -n 10
''' % {'prog_name' : prog_name,
      }

#-------------------------------------------------------------------------------

def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'hn:sNF',
                                   ['help', 'number=', 'send', 'dry-run', 
'no-format'])
    except getopt.GetoptError, err:
        print >>sys.stderr, str(err)
        usage()
        sys.exit(2)

    for o, a in opts:
        if o in ('-h', '--help'):
            usage()
            sys.exit()
        elif o in ('-n', '--number'):
            config['number'] = int(a)
        elif o in ('-s', '--send'):
            config['send'] = True
        elif o in ('-N', '--dry-run'):
            config['dry_run'] = True
        elif o in ('-F', '--no-format'):
            config['run_format'] = False
        else:
            assert False, 'unhandled option'

    config['start_number_filepath'] = os.path.join(config['patch_dir'],
                                                   
config['start_number_basename'])

    try:
        if config['number'] is None:
            number = next_number()
        else:
            number = config['number']

        if config['run_format']:
            if len(args) > 0:
                extra_args = ' '.join(args)
            else:
                extra_args = '-1'
            cmd = 'git format-patch --start-number %d -n -o %s' % (number, 
config['patch_dir'])
            cmd += ' ' + extra_args
            run_cmd(cmd)

        if config['send']:
            patch_file = find_patch(number)
            if patch_file is None:
                print >>sys.stderr, "cannot find patch file for patch %d" % 
(number)
            else:
                send_patch(patch_file)

    except Exception, e:
        print >>sys.stderr, e
#-------------------------------------------------------------------------------

if __name__ == '__main__':
    main()
_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to