import string
import tempfile
import subprocess
+import base64
+import ConfigParser
# 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:80/xmlrpc/"
-
-PW_XMLRPC_URL = os.getenv("PW_XMLRPC_URL")
-if not PW_XMLRPC_URL:
- PW_XMLRPC_URL = DEFAULT_URL
+DEFAULT_URL = "http://patchwork/xmlrpc/"
+CONFIG_FILES = [os.path.expanduser('~/.pwclientrc')]
class Filter:
"""Filter for selecting patches."""
"""Return human-readable description of the filter."""
return str(self.d)
+class BasicHTTPAuthTransport(xmlrpclib.Transport):
+
+ def __init__(self, username = None, password = None):
+ self.username = username
+ self.password = password
+ xmlrpclib.Transport.__init__(self)
+
+ def authenticated(self):
+ return self.username != None and self.password != None
+
+ def send_host(self, connection, host):
+ xmlrpclib.Transport.send_host(self, connection, host)
+ if not self.authenticated():
+ return
+ credentials = '%s:%s' % (self.username, self.password)
+ auth = 'Basic ' + base64.encodestring(credentials).strip()
+ connection.putheader('Authorization', auth)
+
def usage():
sys.stderr.write("Usage: %s <action> [options]\n\n" % \
(os.path.basename(sys.argv[0])))
below and an optional substring to search for patches
by name
search [str] : Same as 'list'
- view <ID> : View a patch\n""")
+ view <ID> : View a patch
+ update [-s state] [-c commit-ref] <ID>
+ : Update patch\n""")
sys.stderr.write("""\nFilter options for 'list' and 'search':
-s <state> : Filter by patch state (e.g., 'New', 'Accepted', etc.)
-p <project> : Filter by project name (see 'projects' for list)
sys.stderr.write("Error: No patch content found\n")
sys.exit(1)
+def action_update_patch(rpc, patch_id, state = None, commit = None):
+ patch = rpc.patch_get(patch_id)
+ if patch == {}:
+ sys.stderr.write("Error getting information on patch ID %d\n" % \
+ patch_id)
+ sys.exit(1)
+
+ params = {}
+
+ if state:
+ state_id = state_id_by_name(rpc, state)
+ if state_id == 0:
+ sys.stderr.write("Error: No State found matching %s*\n" % state)
+ sys.exit(1)
+ params['state'] = state_id
+
+ if commit:
+ params['commit_ref'] = commit
+
+ success = False
+ try:
+ success = rpc.patch_set(patch_id, params)
+ except xmlrpclib.Fault, f:
+ sys.stderr.write("Error updating patch: %s\n" % f.faultString)
+
+ if not success:
+ sys.stderr.write("Patch not updated\n")
+
+auth_actions = ['update']
+
def main():
try:
- opts, args = getopt.getopt(sys.argv[2:], 's:p:w:d:n:')
+ opts, args = getopt.getopt(sys.argv[2:], 's:p:w:d:n:c:')
except getopt.GetoptError, err:
print str(err)
usage()
action = sys.argv[1].lower()
+ # set defaults
filt = Filter()
submitter_str = ""
delegate_str = ""
+ project_str = ""
+ commit_str = ""
+ state_str = ""
+ url = DEFAULT_URL
+
+ config = ConfigParser.ConfigParser()
+ config.read(CONFIG_FILES)
+
+ # grab settings from config files
+ if config.has_option('base', 'url'):
+ url = config.get('base', 'url')
+
+ if config.has_option('base', 'project'):
+ project_str = config.get('base', 'project')
for name, value in opts:
if name == '-s':
- filt.add("state", value)
+ state_str = value
elif name == '-p':
- filt.add("project", value)
+ project_str = value
elif name == '-w':
submitter_str = value
elif name == '-d':
delegate_str = value
+ elif name == '-c':
+ commit_str = value
elif name == '-n':
try:
filt.add("max_count", int(value))
sys.stderr.write("Too many arguments specified\n")
usage()
+ (username, password) = (None, None)
+ transport = None
+ if action in auth_actions:
+ if config.has_option('auth', 'username') and \
+ config.has_option('auth', 'password'):
+
+ transport = BasicHTTPAuthTransport( \
+ config.get('auth', 'username'),
+ config.get('auth', 'password'))
+
+ else:
+ sys.stderr.write(("The %s action requires authentication, "
+ "but no username or password\nis configured\n") % action)
+ sys.exit(1)
+
+ if project_str:
+ filt.add("project", project_str)
+
+ if state_str:
+ filt.add("state", state_str)
+
try:
- rpc = xmlrpclib.Server(PW_XMLRPC_URL)
+ rpc = xmlrpclib.Server(url, transport = transport)
except:
- sys.stderr.write("Unable to connect to %s\n" % PW_XMLRPC_URL)
+ sys.stderr.write("Unable to connect to %s\n" % url)
sys.exit(1)
if action == 'list' or action == 'search':
action_apply(rpc, patch_id)
+ elif action == 'update':
+ try:
+ patch_id = int(args[0])
+ except:
+ sys.stderr.write("Invalid patch ID given\n")
+ sys.exit(1)
+
+ action_update_patch(rpc, patch_id, state = state_str,
+ commit = commit_str)
+
else:
sys.stderr.write("Unknown action '%s'\n" % action)
usage()