diff --git a/UTILITIES/pw b/UTILITIES/pw index 890c72b82..2821ef638 100755 --- a/UTILITIES/pw +++ b/UTILITIES/pw @@ -29,13 +29,22 @@ import subprocess import base64 import ConfigParser import datetime +import smtplib +import urllib import re +from email.mime.text import MIMEText + +notify_on_state_change = { + 'Accepted': 'emacs-orgmode@gnu.org', + 'RFC': 'emacs-orgmode@gnu.org' +} + # Default Patchwork remote XML-RPC server URL # This script will check the PW_XMLRPC_URL environment variable # for the URL to access. If that is unspecified, it will fallback to # the hardcoded default value specified here. -DEFAULT_URL = "http://patchwork/xmlrpc/" +DEFAULT_URL = "http://patchwork.newartisans.com/xmlrpc/" CONFIG_FILES = [os.path.expanduser('~/.pwclientrc')] class Filter: @@ -267,7 +276,8 @@ def action_apply(rpc, patch_id): sys.stderr.write("Error: No patch content found\n") sys.exit(1) -def action_update_patch(rpc, patch_id, state = None, commit = None): +def action_update_patch(rpc, patch_id, state = None, commit = None, + delegate_str = "", archived = False): patch = rpc.patch_get(patch_id) if patch == {}: sys.stderr.write("Error getting information on patch ID %d\n" % \ @@ -276,6 +286,16 @@ def action_update_patch(rpc, patch_id, state = None, commit = None): params = {} + delegate_id = None + if delegate_str != "": + params['delegate'] = delegate_str + ids = person_ids_by_name(rpc, delegate_str) + if len(ids) == 0: + sys.stderr.write("Note: Nobody found matching *%s*\n", \ + delegate_str) + else: + delegate_id = ids[0] + if state: state_id = state_id_by_name(rpc, state) if state_id == 0: @@ -283,11 +303,55 @@ def action_update_patch(rpc, patch_id, state = None, commit = None): sys.exit(1) params['state'] = state_id + if state in notify_on_state_change: + if not delegate_id: + sys.stderr.write("Error: Delete (-d) required for this update\n") + sys.exit(1) + + person = rpc.person_get(delegate_id) + submitter = rpc.person_get(patch['submitter_id']) + + from_addr = '%s <%s>' % (person['name'], person['email']) + cc_addr = '%s <%s>' % (submitter['name'], submitter['email']) + to_addr = notify_on_state_change[state] + + longdesc = '''Patch %s (http://patchwork.newartisans.com/patch/%s/) is now %s. + +This relates to the following submission: + +http://mid.gmane.org/%s''' % \ + (patch['id'], patch['id'], state, urllib.quote(patch['msgid'])) + shortdesc = 'Patch %s %s' % (patch['id'], state) + + msg = MIMEText(longdesc) + + msg['Subject'] = 'Patchwork: ' + shortdesc + msg['From'] = from_addr + msg['To'] = to_addr + #msg['Cc'] = cc_addr + msg['References'] = patch['msgid'] + + # Send the message via our own SMTP server, but don't include + # the envelope header. + try: + s = smtplib.SMTP('localhost') + print "Sending e-mail to: %s, %s" % (to_addr, cc_addr) + s.sendmail(from_addr, [to_addr, cc_addr], msg.as_string()) + s.quit() + except: + sys.stderr.write("Warning: Failed to send e-mail " + + "(no SMTP server listening at localhost?)\n") + if commit: params['commit_ref'] = commit + if archived: + params['archived'] = archived + success = False try: + print "Updating patch %d to state '%s', delegate %s" % \ + (patch_id, state, delegate_str) success = rpc.patch_set(patch_id, params) except xmlrpclib.Fault, f: sys.stderr.write("Error updating patch: %s\n" % f.faultString) @@ -308,7 +372,7 @@ def patch_id_from_hash(rpc, project, hash): return patch['id'] -def branch_with(patch_id, rpc): +def branch_with(patch_id, rpc, delegate_str): s = rpc.patch_get_mbox(patch_id) if len(s) > 0: print unicode(s).encode("utf-8") @@ -356,12 +420,45 @@ def branch_with(patch_id, rpc): os.waitpid(proc.pid, 0) return + # If it succeeded this far, mark the patch as "Under Review" by the + # invoking user. + action_update_patch(rpc, patch_id, state = 'Under Review', + delegate_str = delegate_str) + proc = subprocess.Popen(['git', 'rebase', 'master']) sts = os.waitpid(proc.pid, 0) print sha -auth_actions = ['update'] +def merge_with(patch_id, rpc, delegate_str): + s = rpc.patch_get_mbox(patch_id) + if len(s) > 0: + print unicode(s).encode("utf-8") + + proc = subprocess.Popen(['git', 'checkout', 'master']) + sts = os.waitpid(proc.pid, 0) + if sts[1] != 0: + sys.stderr.write("Failed to checkout master branch\n") + return + + proc = subprocess.Popen(['git', 'merge', '--ff', 't/patch%s' % patch_id]) + sts = os.waitpid(proc.pid, 0) + if sts[1] != 0: + sys.stderr.write("Failed to merge t/patch%s into master\n" % patch_id) + return + + proc = subprocess.Popen(['git', 'rev-parse', 'master'], + stdout = subprocess.PIPE) + sha = proc.stdout.read()[:-1] + + # If it succeeded this far, mark the patch as "Accepted" by the invoking + # user. + action_update_patch(rpc, patch_id, state = 'Accepted', commit = sha, + delegate_str = delegate_str, archived = True) + + print sha + +auth_actions = ['update', 'branch', 'merge'] def main(): try: @@ -478,7 +575,16 @@ def main(): sys.stderr.write("Invalid patch ID given\n") sys.exit(1) - branch_with(patch_id, rpc) + branch_with(patch_id, rpc, config.get('auth', 'username')) + + elif action == 'merge': + try: + patch_id = patch_id or int(args[0]) + except: + sys.stderr.write("Invalid patch ID given\n") + sys.exit(1) + + merge_with(patch_id, rpc, config.get('auth', 'username')) elif action == 'view': try: @@ -517,7 +623,7 @@ def main(): sys.exit(1) action_update_patch(rpc, patch_id, state = state_str, - commit = commit_str) + commit = commit_str, delegate_str = delegate_str) else: sys.stderr.write("Unknown action '%s'\n" % action)