]> git.ozlabs.org Git - patchwork/blobdiff - apps/patchwork/bin/pwclient.py
Add usage info for pwclient 'update' action
[patchwork] / apps / patchwork / bin / pwclient.py
index 765e66b3db277d81b1dc5b45ed30e2372e40d9b5..5b2c2daf2090cd36381722762c02fa2a0d60ae92 100755 (executable)
@@ -26,16 +26,15 @@ import getopt
 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."""
@@ -80,6 +79,24 @@ class Filter:
         """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])))
@@ -93,7 +110,9 @@ def usage():
                         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)
@@ -237,9 +256,39 @@ 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):
+    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()
@@ -249,19 +298,36 @@ def main():
 
     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))
@@ -276,10 +342,31 @@ def main():
         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':
@@ -322,6 +409,16 @@ def main():
 
         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()