Release new version 0.8
[grml-paste.git] / grml-paste
index fa42dbd..b89a200 100755 (executable)
-#!/usr/bin/python
+#!/usr/bin/python3
 # Filename:      grml-paste
 # Purpose:       XmlRpc interface client to paste.grml.org
 # Author:        Michael Gebetsroither <gebi@grml.org>
 # License:       This file is licensed under the GPL v2.
 ################################################################################
 
-import sys
-import xmlrpclib
-import optparse
-import inspect
 import getpass
+import inspect
+import optparse
+import sys
+from xmlrpc.client import ServerProxy
 
 # program defaults
-DEFAULT_SERVER='http://paste.grml.org/server.pl'
+DEFAULT_SERVER = "https://paste.grml.org/server.pl"
+
 
 class ActionFailedException(Exception):
-    '''Thrown if server returned an error'''
+    """Thrown if server returned an error"""
+
     def __init__(self, errormsg, ret):
         Exception.__init__(self, errormsg, ret)
+
     def what(self):
-        '''Get errormessage'''
+        """Get errormessage"""
         return self.args[0]
+
     def dwhat(self):
-        '''Get more verbose errormessage'''
+        """Get more verbose errormessage"""
         return self.args[1]
 
 
-class Action(object):
-    def __init__(self, args, opts):
-        self.args_ = args
-        self.opts_ = opts
-
-    def _createProxy(self):
-        return xmlrpclib.ServerProxy(self.opts_.server)
-
-    def _callProxy(self, functor, server=None):
-        '''Wrapper for xml-rpc calls to server which throws an
-           ActionFailedException on error'''
-        if server is None:
-            server = self._createProxy()
-        ret = functor(server)
-        if ret['rc'] != 0:
-            raise ActionFailedException(ret['statusmessage'], ret)
-        return ret
-
-    def call(self, method_name):
-        '''External Interface to call the appropriate action'''
-        return self.__getattribute__(method_name)()
-
-    def actionAddPaste(self):
-        '''Add paste to the server: <1.line> <2.line> ...
-
-        default     Read paste from stdin.
-        [text]      Every argument on the commandline will be interpreted as
-                    a seperate line of paste.
-        '''
-        server = self._createProxy()
-        o = self.opts_
-        code = self.args_
-        if len(self.args_) == 0:
-            code = [ i.strip() for i in sys.stdin.readlines() ]
-        code = '\n'.join(code)
-        result = self._callProxy(lambda s: s.paste.addPaste(code, o.name, o.expire * 3600, o.lang, o.private),
-                            server)
-        return (result['statusmessage'], result)
-
-    def actionDelPaste(self):
-        '''Delete paste from server: <digest>
-
-        <digest>    Digest of paste you want to remove.
-        '''
-        digest = self.args_.pop(0)
-        result = self._callProxy(lambda s: s.paste.deletePaste(digest))
-        return (result['statusmessage'], result)
-
-    def actionGetPaste(self):
-        '''Get paste from server: <id>
-
-        <id>        Id of paste you want to receive.
-        '''
-        id = self.args_.pop(0)
-        result = self._callProxy(lambda s: s.paste.getPaste(id))
-        return (result['code'], result)
-
-    def actionGetLangs(self):
-        '''Get supported language highlighting types from server'''
-        result = self._callProxy(lambda s: s.paste.getLanguages())
-        return ('\n'.join(result['langs']), result)
-
-    def actionAddShortUrl(self):
-        '''Add short-URL: <url>
-
-        <url>        Short-URL to add
-        '''
-        url = self.args_.pop(0)
-        result = self._callProxy(lambda s: s.paste.addShortURL(url))
-        return (result['url'], result)
-
-    def actionGetShortUrl(self):
-        '''Resolve short-URL: <url>
-
-        <url>        Short-URL to get clicks of
-        '''
-        url = self.args_.pop(0)
-        result = self._callProxy(lambda s: s.paste.resolveShortURL(url))
-        return (result['url'], result)
-
-    def actionGetShortUrlClicks(self):
-        '''Get clicks of short-URL: <url>
-
-        <url>        Short-URL to get clicks of
-        '''
-        url = self.args_.pop(0)
-        result = self._callProxy(lambda s: s.paste.ShortURLClicks(url))
-        return (result['count'], result)
-
-    def actionHelp(self):
-        '''Print more verbose help about specific action: <action>
-
-        <action>    Topic on which you need more verbose help.
-        '''
-        if len(self.args_) < 1:
-            alias = "help"
-        else:
-            alias = self.args_.pop(0)
-
-        if alias in actions:
-            fun = actions[alias]
-            print inspect.getdoc(self.__getattribute__(fun))
-            print "\naliase: " + " ".join([i for i in actions_r[fun] if i != alias])
-        else:
-            print "Error: No such command - %s" % (alias)
-            OPT_PARSER.print_usage()
-        sys.exit(0)
-
-
-# actionAddPaste -> [add, a]
+def _paste(opts):
+    """Get paste proxy object"""
+    return ServerProxy(opts.server, verbose=False).paste
+
+
+def _check_success(return_data):
+    """Check if call was successful, raise ActionFailedException otherwise"""
+    if return_data["rc"] != 0:
+        raise ActionFailedException(return_data["statusmessage"], return_data)
+    return return_data
+
+
+def action_add_paste(opts, code):
+    """Add paste to the server: <1.line> <2.line> ...
+
+    default     Read paste from stdin.
+    [text]      Every argument on the commandline will be interpreted as
+                a seperate line of paste.
+    """
+    if len(code) == 0:
+        code = [line.rstrip() for line in sys.stdin.readlines()]
+    code = "\n".join(code)
+    result = _check_success(
+        _paste(opts).addPaste(
+            code, opts.name, opts.expire * 3600, opts.lang, opts.private
+        )
+    )
+    return result["statusmessage"], result
+
+
+def action_del_paste(opts, args):
+    """Delete paste from server: <digest>
+
+    <digest>    Digest of paste you want to remove.
+    """
+    digest = args.pop(0)
+    result = _check_success(_paste(opts).deletePaste(digest))
+    return result["statusmessage"], result
+
+
+def action_get_paste(opts, args):
+    """Get paste from server: <id>
+
+    <id>        Id of paste you want to receive.
+    """
+    paste_id = args.pop(0)
+    result = _check_success(_paste(opts).getPaste(paste_id))
+    return result["code"], result
+
+
+def action_get_langs(opts, args):
+    """Get supported language highlighting types from server"""
+    result = _check_success(_paste(opts).getLanguages())
+    return "\n".join(result["langs"]), result
+
+
+def action_add_short_url(opts, args):
+    """Add short-URL: <url>
+
+    <url>        Short-URL to add
+    """
+    url = args.pop(0)
+    result = _check_success(_paste(opts).addShortURL(url))
+    return result["url"], result
+
+
+def action_get_short_url(opts, args):
+    """Resolve short-URL: <url>
+
+    <url>        Short-URL to get clicks of
+    """
+    url = args.pop(0)
+    result = _check_success(_paste(opts).resolveShortURL(url))
+    return result["url"], result
+
+
+def action_get_short_url_clicks(opts, args):
+    """Get clicks of short-URL: <url>
+
+    <url>        Short-URL to get clicks of
+    """
+    url = args.pop(0)
+    result = _check_success(_paste(opts).ShortURLClicks(url))
+    return result["count"], result
+
+
+def action_help(opts, args):
+    """Print more verbose help about specific action: <action>
+
+    <action>    Topic on which you need more verbose help.
+    """
+    if len(args) < 1:
+        alias = "help"
+    else:
+        alias = args.pop(0)
+
+    if alias in actions:
+        function_name = actions[alias]
+        print(inspect.getdoc(globals()[function_name]))
+        print(
+            "\naliases: "
+            + " ".join([i for i in actions_r[function_name] if i != alias])
+        )
+    else:
+        print("Error: No such command - %s" % (alias))
+        OPT_PARSER.print_usage()
+    sys.exit(0)
+
+
+# action_add_paste -> [add, a]
 actions_r = {}
 
-# add -> actionAddPaste
-# a   -> actionAddPaste
-actions   = {}
+# add -> action_add_paste
+# a   -> action_add_paste
+actions = {}
 
 # option parser
 OPT_PARSER = None
@@ -150,55 +154,77 @@ OPT_PARSER = None
 # MAIN
 ##
 if __name__ == "__main__":
-    action_spec = ['actionAddPaste add a',
-                   'actionDelPaste del d rm',
-                   'actionGetPaste get g',
-                   'actionGetLangs getlangs gl langs l',
-                   'actionAddShortUrl addurl',
-                   'actionGetShortUrl geturl',
-                   'actionGetShortUrlClicks getclicks',
-                   'actionHelp     help']
-    for i in action_spec:
-        aliases = i.split()
+    action_specs = [
+        "action_add_paste add a",
+        "action_del_paste del d rm",
+        "action_get_paste get g",
+        "action_get_langs getlangs gl langs l",
+        "action_add_short_url addurl",
+        "action_get_short_url geturl",
+        "action_get_short_url_clicks getclicks",
+        "action_help     help",
+    ]
+    for action_spec in action_specs:
+        aliases = action_spec.split()
         cmd = aliases.pop(0)
         actions_r[cmd] = aliases
-    for (k,v) in actions_r.items():
+    for (action_name, v) in actions_r.items():
         for i in v:
-            actions[i] = k
-
-    usage = "usage: %prog [options] ACTION <args>\n\n" +\
-            "actions:\n" +\
-            "\n".join(["%12s\t%s" % (v[0], inspect.getdoc(getattr(Action, k)).split('\n')[0]) \
-                for (k,v) in actions_r.items()])
+            actions[i] = action_name
+
+    usage = (
+        "usage: %prog [options] ACTION <args>\n\n"
+        + "actions:\n"
+        + "\n".join(
+            [
+                "%12s\t%s"
+                % (v[0], inspect.getdoc(globals()[action_name]).splitlines()[0])
+                for (action_name, v) in actions_r.items()
+            ]
+        )
+    )
     running_user = getpass.getuser()
     parser = optparse.OptionParser(usage=usage)
-    parser.add_option('-n', '--name', default=running_user, help="Name of poster")
-    parser.add_option('-e', '--expire', type=int, default=72, metavar='HOURS',
-            help='Time at wich paste should expire')
-    parser.add_option('-l', '--lang', default='Plain', help='Type of language to highlight')
-    parser.add_option("-p", "--private", action="count", dest="private", default=0,
-                        help='Create hidden paste'),
-    parser.add_option('-s', '--server', default=DEFAULT_SERVER,
-            help='Paste server')
-    parser.add_option('-v', '--verbose', action='count', default=0, help='More output')
+    parser.add_option("-n", "--name", default=running_user, help="Name of poster")
+    parser.add_option(
+        "-e",
+        "--expire",
+        type=int,
+        default=72,
+        metavar="HOURS",
+        help="Time at which paste should expire",
+    )
+    parser.add_option(
+        "-l", "--lang", default="Plain", help="Type of language to highlight"
+    )
+    parser.add_option(
+        "-p",
+        "--private",
+        action="count",
+        dest="private",
+        default=0,
+        help="Create hidden paste",
+    ),
+    parser.add_option("-s", "--server", default=DEFAULT_SERVER, help="Paste server")
+    parser.add_option("-v", "--verbose", action="count", default=0, help="More output")
     (opts, args) = parser.parse_args()
     OPT_PARSER = parser
 
     if len(args) == 0:
-        parser.error('Please provide me with an action')
+        parser.error("Please provide me with an action")
     elif args[0] in actions:
         cmd = args.pop(0)
-        action = Action(args, opts)
+        action = actions[cmd]
         try:
-            (msg, ret) = action.call(actions[cmd])
+            (msg, ret) = globals()[action](opts, args)
             if opts.verbose == 0:
-                print msg
+                print(msg)
             else:
-                print ret
-        except ActionFailedException, e:
-            sys.stderr.write('Server Error: %s\n' % e.what())
-            if opts.verbose >0:
-                print e.dwhat()
+                print(ret)
+        except ActionFailedException as except_inst:
+            sys.stderr.write("Server Error: %s\n" % except_inst.what())
+            if opts.verbose > 0:
+                print(except_inst.dwhat())
             sys.exit(1)
     else:
-        parser.error('Unknown action: %s' % args[0])
+        parser.error("Unknown action: %s" % args[0])