cba61081bd356457306a4d0e6821af07a795cd1c
[grml-paste.git] / grml-paste
1 #!/usr/bin/python
2 # Filename:      grml-paste
3 # Purpose:       XmlRpc interface client to paste.grml.org
4 # Author:        Michael Gebetsroither <gebi@grml.org>
5 # License:       This file is licensed under the GPL v2.
6 ################################################################################
7
8 import sys
9 import xmlrpclib
10 import optparse
11 from pprint import pprint
12 import inspect
13
14
15 class ActionFailedException(Exception):
16     '''Thrown if server returned an error'''
17     def __init__(self, errormsg, ret):
18         Exception.__init__(self, errormsg, ret)
19     def what(self):
20         '''Get errormessage'''
21         return self.args[0]
22     def dwhat(self):
23         '''Get more verbose errormessage'''
24         return self.args[1]
25
26
27 class Action(object):
28     def __init__(self, args, opts):
29         self.args_ = args
30         self.opts_ = opts
31
32     def _createProxy(self):
33         return xmlrpclib.ServerProxy(self.opts_.server)
34
35     def _callProxy(self, functor, server=None):
36         '''Wrapper for xml-rpc calls to server which throws an
37            ActionFailedException on error'''
38         if server is None:
39             server = self._createProxy()
40         ret = functor(server)
41         if ret['rc'] != 0:
42             raise ActionFailedException(ret['statusmessage'], ret)
43         return ret
44
45     def call(self, method_name):
46         '''External Interface to call the appropriate action'''
47         return self.__getattribute__(method_name)()
48
49     def actionAddPaste(self):
50         '''Add paste to the server: <1.line> <2.line> ...
51
52         default     Read paste from stdin.
53         [text]      Every argument on the commandline will be interpreted as
54                     a seperate line of paste.
55         '''
56         server = self._createProxy()
57         o = self.opts_
58         code = self.args_
59         if len(self.args_) == 0:
60             code = [ i.strip() for i in sys.stdin.readlines() ]
61         code = '\n'.join(code)
62         result = self._callProxy(lambda s: s.paste.addPaste(code, o.name, o.expire * 3600, o.lang),
63                             server)
64         return (result['statusmessage'], result)
65
66     def actionDelPaste(self):
67         '''Delete paste from server: <digest>
68
69         <digest>    Digest of paste you want to remove.
70         '''
71         digest = self.args_.pop(0)
72
73         result = self._callProxy(lambda s: s.paste.deletePaste(digest))
74         return (result['statusmessage'], result)
75
76     def actionGetPaste(self):
77         '''Get paste from server: <id>
78
79         <id>        Id of paste you want to receive.
80         '''
81         id = self.args_.pop(0)
82
83         result = self._callProxy(lambda s: s.paste.getPaste(id))
84         return (result['code'], result)
85
86     def actionGetLangs(self):
87         '''Get supported language highlighting types from server'''
88         result = self._callProxy(lambda s: s.paste.getLanguages())
89         return ('\n'.join(result['langs']), result)
90
91     def actionHelp(self):
92         '''Print more verbose help about specific action: <action>
93
94         <action>    Topic on which you need more verbose help.
95         '''
96         alias = self.args_.pop(0)
97
98         fun = actions[alias]
99         print inspect.getdoc(self.__getattribute__(fun))
100         print "\naliase: " + " ".join([i for i in actions_r[fun] if i != alias])
101         sys.exit(0)
102
103
104 # actionAddPaste -> [add, a]
105 actions_r = {}
106
107 # add -> actionAddPaste
108 # a   -> actionAddPaste
109 actions   = {}
110
111 ##
112 # MAIN
113 ##
114 if __name__ == "__main__":
115     action_spec = ['actionAddPaste add a',
116                    'actionDelPaste del d rm',
117                    'actionGetPaste get g',
118                    'actionGetLangs getlangs gl langs l',
119                    'actionHelp     help']
120     for i in action_spec:
121         tmp = i.split()
122         cmd = tmp.pop(0)
123         actions_r[cmd] = tmp
124     for (k,v) in actions_r.items():
125         for i in v:
126             actions[i] = k
127
128     usage = "usage: %prog [options] ACTION <args>\n\n" +\
129             "actions:\n" +\
130             "\n".join(["%12s\t%s" % (v[0], inspect.getdoc(getattr(Action, k)).split('\n')[0]) \
131                 for (k,v) in actions_r.items()])
132     parser = optparse.OptionParser(usage=usage)
133     parser.add_option('-n', '--name', default='anonymous', help="Name of poster")
134     parser.add_option('-e', '--expire', type=int, default=72, metavar='HOURS',
135             help='Time at wich paste should expire')
136     parser.add_option('-l', '--lang', default='Plain', help='Type of language to highlight')
137     parser.add_option('-s', '--server', default='http://paste.grml.org/server.pl',
138             help='Paste server')
139     parser.add_option('-v', '--verbose', action='count', default=0, help='More output')
140     (opts, args) = parser.parse_args()
141
142     if len(args) == 0:
143         parser.error('Please provide me with an action')
144     elif args[0] in actions:
145         cmd = args.pop(0)
146         action = Action(args, opts)
147         try:
148             (msg, ret) = action.call(actions[cmd])
149             if opts.verbose == 0:
150                 print msg
151             else:
152                 pprint(ret)
153         except ActionFailedException, e:
154             sys.stderr.write('Server Error: %s\n' % e.what())
155             if opts.verbose >0:
156                 pprint(e.dwhat())
157             sys.exit(1)
158     else:
159         parser.error('Unknown action: %s' % args[0])