Remove various scripts
[grml-scripts.git] / usr_bin / lodgeit
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 """
4     LodgeIt!
5     ~~~~~~~~
6
7     A script that pastes stuff into the lodgeit pastebin.
8
9     .lodgeitrc / _lodgeitrc
10     -----------------------
11
12     Under UNIX create a file called ``~/.lodgeitrc``, under Windows
13     create a file ``%APPDATA%/_lodgeitrc`` to override defaults::
14
15         language=default_language
16         clipboard=true/false
17         open_browser=true/false
18         encoding=fallback_charset
19
20     :authors: 2007-2010 Georg Brandl <georg@python.org>,
21               2006 Armin Ronacher <armin.ronacher@active-4.com>,
22               2006 Matt Good <matt@matt-good.net>,
23               2005 Raphael Slinckx <raphael@slinckx.net>
24 """
25 import os
26 import sys
27 from optparse import OptionParser
28
29
30 SCRIPT_NAME = os.path.basename(sys.argv[0])
31 VERSION = '0.3'
32 SETTING_KEYS = ['author', 'title', 'language', 'private', 'clipboard',
33                 'open_browser']
34
35 # global server proxy
36 _xmlrpc_service = None
37 _server_name = None
38
39
40 def fail(msg, code):
41     """Bail out with an error message."""
42     print >> sys.stderr, 'ERROR: %s' % msg
43     sys.exit(code)
44
45
46 def load_default_settings():
47     """Load the defaults from the lodgeitrc file."""
48     settings = {
49         'language':     None,
50         'clipboard':    True,
51         'open_browser': False,
52         'encoding':     'iso-8859-15',
53         'server_name':  'http://paste.pocoo.org',
54     }
55     rcfile = None
56     if os.name == 'posix':
57         rcfile = os.path.expanduser('~/.lodgeitrc')
58     elif os.name == 'nt' and 'APPDATA' in os.environ:
59         rcfile = os.path.expandvars(r'$APPDATA\_lodgeitrc')
60     if rcfile:
61         try:
62             f = open(rcfile)
63             for line in f:
64                 if line.strip()[:1] in '#;':
65                     continue
66                 p = line.split('=', 1)
67                 if len(p) == 2:
68                     key = p[0].strip().lower()
69                     if key in settings:
70                         if key in ('clipboard', 'open_browser'):
71                             settings[key] = p[1].strip().lower() in \
72                                             ('true', '1', 'on', 'yes')
73                         else:
74                             settings[key] = p[1].strip()
75             f.close()
76         except IOError:
77             pass
78     settings['tags'] = []
79     settings['title'] = None
80     return settings
81
82
83 def make_utf8(text, encoding):
84     """Convert a text to UTF-8, brute-force."""
85     try:
86         u = unicode(text, 'utf-8')
87         uenc = 'utf-8'
88     except UnicodeError:
89         try:
90             u = unicode(text, encoding)
91             uenc = 'utf-8'
92         except UnicodeError:
93             u = unicode(text, 'iso-8859-15', 'ignore')
94             uenc = 'iso-8859-15'
95     try:
96         import chardet
97     except ImportError:
98         return u.encode('utf-8')
99     d = chardet.detect(text)
100     if d['encoding'] == uenc:
101         return u.encode('utf-8')
102     return unicode(text, d['encoding'], 'ignore').encode('utf-8')
103
104
105 def get_xmlrpc_service():
106     """Create the XMLRPC server proxy and cache it."""
107     global _xmlrpc_service
108     import xmlrpclib
109     if _xmlrpc_service is None:
110         try:
111             _xmlrpc_service = xmlrpclib.ServerProxy(_server_name + 'xmlrpc/',
112                                                     allow_none=True)
113         except Exception, err:
114             fail('Could not connect to Pastebin: %s' % err, -1)
115     return _xmlrpc_service
116
117
118 def copy_url(url):
119     """Copy the url into the clipboard."""
120     # try windows first
121     try:
122         import win32clipboard
123     except ImportError:
124         # then give pbcopy a try.  do that before gtk because
125         # gtk might be installed on os x but nobody is interested
126         # in the X11 clipboard there.
127         from subprocess import Popen, PIPE
128         for prog in 'pbcopy', 'xclip':
129             try:
130                 client = Popen([prog], stdin=PIPE)
131             except OSError:
132                 continue
133             else:
134                 client.stdin.write(url)
135                 client.stdin.close()
136                 client.wait()
137                 break
138         else:
139             try:
140                 import pygtk
141                 pygtk.require('2.0')
142                 import gtk
143                 import gobject
144             except ImportError:
145                 return
146             gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD).set_text(url)
147             gobject.idle_add(gtk.main_quit)
148             gtk.main()
149     else:
150         win32clipboard.OpenClipboard()
151         win32clipboard.EmptyClipboard()
152         win32clipboard.SetClipboardText(url)
153         win32clipboard.CloseClipboard()
154
155
156 def open_webbrowser(url):
157     """Open a new browser window."""
158     import webbrowser
159     webbrowser.open(url)
160
161
162 def language_exists(language):
163     """Check if a language alias exists."""
164     xmlrpc = get_xmlrpc_service()
165     langs = xmlrpc.pastes.getLanguages()
166     return language in langs
167
168
169 def get_mimetype(data, filename):
170     """Try to get MIME type from data."""
171     try:
172         import gnomevfs
173     except ImportError:
174         from mimetypes import guess_type
175         if filename:
176             return guess_type(filename)[0]
177     else:
178         if filename:
179             return gnomevfs.get_mime_type(os.path.abspath(filename))
180         return gnomevfs.get_mime_type_for_data(data)
181
182
183 def print_languages():
184     """Print a list of all supported languages, with description."""
185     xmlrpc = get_xmlrpc_service()
186     languages = xmlrpc.pastes.getLanguages().items()
187     languages.sort(lambda a, b: cmp(a[1].lower(), b[1].lower()))
188     print 'Supported Languages:'
189     for alias, name in languages:
190         print '    %-30s%s' % (alias, name)
191
192
193 def download_paste(uid):
194     """Download a paste given by ID."""
195     xmlrpc = get_xmlrpc_service()
196     paste = xmlrpc.pastes.getPaste(uid)
197     if not paste:
198         fail('Paste "%s" does not exist.' % uid, 5)
199     print paste['code'].encode('utf-8')
200
201
202 def create_paste(code, language, filename, mimetype, private):
203     """Create a new paste."""
204     xmlrpc = get_xmlrpc_service()
205     rv = xmlrpc.pastes.newPaste(language, code, None, filename, mimetype,
206                                 private)
207     if not rv:
208         fail('Could not create paste. Something went wrong '
209              'on the server side.', 4)
210     return rv
211
212
213 def compile_paste(filenames, langopt):
214     """Create a single paste out of zero, one or multiple files."""
215     def read_file(f):
216         try:
217             return f.read()
218         finally:
219             f.close()
220     mime = ''
221     lang = langopt or ''
222     if not filenames:
223         data = read_file(sys.stdin)
224         print 'Pasting...'
225         if not langopt:
226             mime = get_mimetype(data, '') or ''
227         fname = ''
228     elif len(filenames) == 1:
229         fname = filenames[0]
230         data = read_file(open(filenames[0], 'rb'))
231         if not langopt:
232             mime = get_mimetype(data, filenames[0]) or ''
233     else:
234         result = []
235         for fname in filenames:
236             data = read_file(open(fname, 'rb'))
237             if langopt:
238                 result.append('### %s [%s]\n\n' % (fname, langopt))
239             else:
240                 result.append('### %s\n\n' % fname)
241             result.append(data)
242             result.append('\n\n')
243         data = ''.join(result)
244         lang = 'multi'
245         fname = ''
246     return data, lang, fname, mime
247
248
249 def main():
250     """Main script entry point."""
251     global _server_name
252
253     usage = ('Usage: %%prog [options] [FILE ...]\n\n'
254              'Read the files and paste their contents to LodgeIt pastebin.\n'
255              'If no file is given, read from standard input.\n'
256              'If multiple files are given, they are put into a single paste.')
257     parser = OptionParser(usage=usage)
258
259     settings = load_default_settings()
260
261     parser.add_option('-v', '--version', action='store_true',
262                       help='Print script version')
263     parser.add_option('-L', '--languages', action='store_true', default=False,
264                       help='Retrieve a list of supported languages')
265     parser.add_option('-l', '--language', default=settings['language'],
266                       help='Used syntax highlighter for the file')
267     parser.add_option('-e', '--encoding', default=settings['encoding'],
268                       help='Specify the encoding of a file (default is '
269                            'utf-8 or guessing if available)')
270     parser.add_option('-b', '--open-browser', dest='open_browser',
271                       action='store_true',
272                       default=settings['open_browser'],
273                       help='Open the paste in a web browser')
274     parser.add_option('-p', '--private', action='store_true', default=False,
275                       help='Paste as private')
276     parser.add_option('--no-clipboard', dest='clipboard',
277                       action='store_false',
278                       default=settings['clipboard'],
279                       help="Don't copy the url into the clipboard")
280     parser.add_option('--download', metavar='UID',
281                       help='Download a given paste')
282     parser.add_option('-s', '--server', default=settings['server_name'],
283                       dest='server_name',
284                       help="Specify the pastebin to send data")
285     opts, args = parser.parse_args()
286
287     # The global available server name
288     _server_name = opts.server_name
289     if not _server_name.endswith('/'):
290         _server_name += '/'
291
292     # special modes of operation:
293     # - paste script version
294     if opts.version:
295         print '%s: version %s' % (SCRIPT_NAME, VERSION)
296         sys.exit()
297     # - print list of languages
298     elif opts.languages:
299         print_languages()
300         sys.exit()
301     # - download Paste
302     elif opts.download:
303         download_paste(opts.download)
304         sys.exit()
305
306     # check language if given
307     if opts.language and not language_exists(opts.language):
308         fail('Language %s is not supported.' % opts.language, 3)
309
310     # load file(s)
311     try:
312         data, language, filename, mimetype = compile_paste(args, opts.language)
313     except Exception, err:
314         fail('Error while reading the file(s): %s' % err, 2)
315     if not data:
316         fail('Aborted, no content to paste.', 4)
317
318     # create paste
319     code = make_utf8(data, opts.encoding)
320     pid = create_paste(code, language, filename, mimetype, opts.private)
321     url = '%sshow/%s/' % (_server_name, pid)
322     print url
323     if opts.open_browser:
324         open_webbrowser(url)
325     if opts.clipboard:
326         copy_url(url)
327
328
329 if __name__ == '__main__':
330     sys.exit(main())