332 lines
10 KiB
Python
332 lines
10 KiB
Python
|
#!/usr/bin/env python
|
||
|
"""
|
||
|
LodgeIt!
|
||
|
~~~~~~~~
|
||
|
|
||
|
A script that pastes stuff into the lodgeit pastebin.
|
||
|
|
||
|
.lodgeitrc / _lodgeitrc
|
||
|
-----------------------
|
||
|
|
||
|
Under UNIX create a file called ``~/.lodgeitrc``, under Windows
|
||
|
create a file ``%APPDATA%/_lodgeitrc`` to override defaults::
|
||
|
|
||
|
language=default_language
|
||
|
clipboard=true/false
|
||
|
open_browser=true/false
|
||
|
encoding=fallback_charset
|
||
|
|
||
|
:authors: 2007-2010 Georg Brandl <georg@python.org>,
|
||
|
2006 Armin Ronacher <armin.ronacher@active-4.com>,
|
||
|
2006 Matt Good <matt@matt-good.net>,
|
||
|
2005 Raphael Slinckx <raphael@slinckx.net>
|
||
|
"""
|
||
|
from __future__ import print_function
|
||
|
import os
|
||
|
import sys
|
||
|
from six import text_type
|
||
|
from optparse import OptionParser
|
||
|
|
||
|
|
||
|
SCRIPT_NAME = os.path.basename(sys.argv[0])
|
||
|
VERSION = '0.3'
|
||
|
SETTING_KEYS = ['author', 'title', 'language', 'private', 'clipboard',
|
||
|
'open_browser']
|
||
|
|
||
|
# global server proxy
|
||
|
_xmlrpc_service = None
|
||
|
_server_name = None
|
||
|
|
||
|
|
||
|
def fail(msg, code):
|
||
|
"""Bail out with an error message."""
|
||
|
print('ERROR: %s' % msg, file=sys.stderr)
|
||
|
sys.exit(code)
|
||
|
|
||
|
|
||
|
def load_default_settings():
|
||
|
"""Load the defaults from the lodgeitrc file."""
|
||
|
settings = {
|
||
|
'language': None,
|
||
|
'clipboard': True,
|
||
|
'open_browser': False,
|
||
|
'encoding': 'iso-8859-15',
|
||
|
'server_name': 'http://paste.openstack.org',
|
||
|
}
|
||
|
rcfile = None
|
||
|
if os.name == 'posix':
|
||
|
rcfile = os.path.expanduser('~/.lodgeitrc')
|
||
|
elif os.name == 'nt' and 'APPDATA' in os.environ:
|
||
|
rcfile = os.path.expandvars(r'$APPDATA\_lodgeitrc')
|
||
|
if rcfile:
|
||
|
try:
|
||
|
f = open(rcfile)
|
||
|
for line in f:
|
||
|
if line.strip()[:1] in '#;':
|
||
|
continue
|
||
|
p = line.split('=', 1)
|
||
|
if len(p) == 2:
|
||
|
key = p[0].strip().lower()
|
||
|
if key in settings:
|
||
|
if key in ('clipboard', 'open_browser'):
|
||
|
settings[key] = p[1].strip().lower() in \
|
||
|
('true', '1', 'on', 'yes')
|
||
|
else:
|
||
|
settings[key] = p[1].strip()
|
||
|
f.close()
|
||
|
except IOError:
|
||
|
pass
|
||
|
settings['tags'] = []
|
||
|
settings['title'] = None
|
||
|
return settings
|
||
|
|
||
|
|
||
|
def make_utf8(text, encoding):
|
||
|
"""Convert a text to UTF-8, brute-force."""
|
||
|
try:
|
||
|
u = text_type(text, 'utf-8')
|
||
|
uenc = 'utf-8'
|
||
|
except UnicodeError:
|
||
|
try:
|
||
|
u = text_type(text, encoding)
|
||
|
uenc = 'utf-8'
|
||
|
except UnicodeError:
|
||
|
u = text_type(text, 'iso-8859-15', 'ignore')
|
||
|
uenc = 'iso-8859-15'
|
||
|
try:
|
||
|
import chardet
|
||
|
except ImportError:
|
||
|
return u.encode('utf-8')
|
||
|
d = chardet.detect(text)
|
||
|
if d['encoding'] == uenc:
|
||
|
return u.encode('utf-8')
|
||
|
return text_type(text, d['encoding'], 'ignore').encode('utf-8')
|
||
|
|
||
|
|
||
|
def get_xmlrpc_service():
|
||
|
"""Create the XMLRPC server proxy and cache it."""
|
||
|
global _xmlrpc_service
|
||
|
import xmlrpclib
|
||
|
if _xmlrpc_service is None:
|
||
|
try:
|
||
|
_xmlrpc_service = xmlrpclib.ServerProxy(_server_name + 'xmlrpc/',
|
||
|
allow_none=True)
|
||
|
except Exception as err:
|
||
|
fail('Could not connect to Pastebin: %s' % err, -1)
|
||
|
return _xmlrpc_service
|
||
|
|
||
|
|
||
|
def copy_url(url):
|
||
|
"""Copy the url into the clipboard."""
|
||
|
# try windows first
|
||
|
try:
|
||
|
import win32clipboard
|
||
|
except ImportError:
|
||
|
# then give pbcopy a try. do that before gtk because
|
||
|
# gtk might be installed on os x but nobody is interested
|
||
|
# in the X11 clipboard there.
|
||
|
from subprocess import Popen, PIPE
|
||
|
for prog in 'pbcopy', 'xclip':
|
||
|
try:
|
||
|
client = Popen([prog], stdin=PIPE)
|
||
|
except OSError:
|
||
|
continue
|
||
|
else:
|
||
|
client.stdin.write(url)
|
||
|
client.stdin.close()
|
||
|
client.wait()
|
||
|
break
|
||
|
else:
|
||
|
try:
|
||
|
import pygtk
|
||
|
pygtk.require('2.0')
|
||
|
import gtk
|
||
|
import gobject
|
||
|
except ImportError:
|
||
|
return
|
||
|
gtk.clipboard_get(gtk.gdk.SELECTION_CLIPBOARD).set_text(url)
|
||
|
gobject.idle_add(gtk.main_quit)
|
||
|
gtk.main()
|
||
|
else:
|
||
|
win32clipboard.OpenClipboard()
|
||
|
win32clipboard.EmptyClipboard()
|
||
|
win32clipboard.SetClipboardText(url)
|
||
|
win32clipboard.CloseClipboard()
|
||
|
|
||
|
|
||
|
def open_webbrowser(url):
|
||
|
"""Open a new browser window."""
|
||
|
import webbrowser
|
||
|
webbrowser.open(url)
|
||
|
|
||
|
|
||
|
def language_exists(language):
|
||
|
"""Check if a language alias exists."""
|
||
|
xmlrpc = get_xmlrpc_service()
|
||
|
langs = xmlrpc.pastes.getLanguages()
|
||
|
return language in langs
|
||
|
|
||
|
|
||
|
def get_mimetype(data, filename):
|
||
|
"""Try to get MIME type from data."""
|
||
|
try:
|
||
|
import gnomevfs
|
||
|
except ImportError:
|
||
|
from mimetypes import guess_type
|
||
|
if filename:
|
||
|
return guess_type(filename)[0]
|
||
|
else:
|
||
|
if filename:
|
||
|
return gnomevfs.get_mime_type(os.path.abspath(filename))
|
||
|
return gnomevfs.get_mime_type_for_data(data)
|
||
|
|
||
|
|
||
|
def print_languages():
|
||
|
"""Print a list of all supported languages, with description."""
|
||
|
xmlrpc = get_xmlrpc_service()
|
||
|
languages = xmlrpc.pastes.getLanguages().items()
|
||
|
languages.sort(key=lambda a: a[1].lower())
|
||
|
print('Supported Languages:')
|
||
|
for alias, name in languages:
|
||
|
print(' %-30s%s' % (alias, name))
|
||
|
|
||
|
|
||
|
def download_paste(uid):
|
||
|
"""Download a paste given by ID."""
|
||
|
xmlrpc = get_xmlrpc_service()
|
||
|
paste = xmlrpc.pastes.getPaste(uid)
|
||
|
if not paste:
|
||
|
fail('Paste "%s" does not exist.' % uid, 5)
|
||
|
print(paste['code'].encode('utf-8'))
|
||
|
|
||
|
|
||
|
def create_paste(code, language, filename, mimetype, private):
|
||
|
"""Create a new paste."""
|
||
|
xmlrpc = get_xmlrpc_service()
|
||
|
rv = xmlrpc.pastes.newPaste(language, code, None, filename, mimetype,
|
||
|
private)
|
||
|
if not rv:
|
||
|
fail('Could not create paste. Something went wrong '
|
||
|
'on the server side.', 4)
|
||
|
return rv
|
||
|
|
||
|
|
||
|
def compile_paste(filenames, langopt):
|
||
|
"""Create a single paste out of zero, one or multiple files."""
|
||
|
def read_file(f):
|
||
|
try:
|
||
|
return f.read()
|
||
|
finally:
|
||
|
f.close()
|
||
|
mime = ''
|
||
|
lang = langopt or ''
|
||
|
if not filenames:
|
||
|
data = read_file(sys.stdin)
|
||
|
print('Pasting...')
|
||
|
if not langopt:
|
||
|
mime = get_mimetype(data, '') or ''
|
||
|
fname = ''
|
||
|
elif len(filenames) == 1:
|
||
|
fname = filenames[0]
|
||
|
data = read_file(open(filenames[0], 'rb'))
|
||
|
if not langopt:
|
||
|
mime = get_mimetype(data, filenames[0]) or ''
|
||
|
else:
|
||
|
result = []
|
||
|
for fname in filenames:
|
||
|
data = read_file(open(fname, 'rb'))
|
||
|
if langopt:
|
||
|
result.append('### %s [%s]\n\n' % (fname, langopt))
|
||
|
else:
|
||
|
result.append('### %s\n\n' % fname)
|
||
|
result.append(data)
|
||
|
result.append('\n\n')
|
||
|
data = ''.join(result)
|
||
|
lang = 'multi'
|
||
|
fname = ''
|
||
|
return data, lang, fname, mime
|
||
|
|
||
|
|
||
|
def main():
|
||
|
"""Main script entry point."""
|
||
|
global _server_name
|
||
|
|
||
|
usage = ('Usage: %%prog [options] [FILE ...]\n\n'
|
||
|
'Read the files and paste their contents to LodgeIt pastebin.\n'
|
||
|
'If no file is given, read from standard input.\n'
|
||
|
'If multiple files are given, they are put into a single paste.')
|
||
|
parser = OptionParser(usage=usage)
|
||
|
|
||
|
settings = load_default_settings()
|
||
|
|
||
|
parser.add_option('-v', '--version', action='store_true',
|
||
|
help='Print script version')
|
||
|
parser.add_option('-L', '--languages', action='store_true', default=False,
|
||
|
help='Retrieve a list of supported languages')
|
||
|
parser.add_option('-l', '--language', default=settings['language'],
|
||
|
help='Used syntax highlighter for the file')
|
||
|
parser.add_option('-e', '--encoding', default=settings['encoding'],
|
||
|
help='Specify the encoding of a file (default is '
|
||
|
'utf-8 or guessing if available)')
|
||
|
parser.add_option('-b', '--open-browser', dest='open_browser',
|
||
|
action='store_true',
|
||
|
default=settings['open_browser'],
|
||
|
help='Open the paste in a web browser')
|
||
|
parser.add_option('-p', '--private', action='store_true', default=False,
|
||
|
help='Paste as private')
|
||
|
parser.add_option('--no-clipboard', dest='clipboard',
|
||
|
action='store_false',
|
||
|
default=settings['clipboard'],
|
||
|
help="Don't copy the url into the clipboard")
|
||
|
parser.add_option('--download', metavar='UID',
|
||
|
help='Download a given paste')
|
||
|
parser.add_option('-s', '--server', default=settings['server_name'],
|
||
|
dest='server_name',
|
||
|
help="Specify the pastebin to send data")
|
||
|
opts, args = parser.parse_args()
|
||
|
|
||
|
# The global available server name
|
||
|
_server_name = opts.server_name
|
||
|
if not _server_name.endswith('/'):
|
||
|
_server_name += '/'
|
||
|
|
||
|
# special modes of operation:
|
||
|
# - paste script version
|
||
|
if opts.version:
|
||
|
print('%s: version %s' % (SCRIPT_NAME, VERSION))
|
||
|
sys.exit()
|
||
|
# - print list of languages
|
||
|
elif opts.languages:
|
||
|
print_languages()
|
||
|
sys.exit()
|
||
|
# - download Paste
|
||
|
elif opts.download:
|
||
|
download_paste(opts.download)
|
||
|
sys.exit()
|
||
|
|
||
|
# check language if given
|
||
|
if opts.language and not language_exists(opts.language):
|
||
|
fail('Language %s is not supported.' % opts.language, 3)
|
||
|
|
||
|
# load file(s)
|
||
|
try:
|
||
|
data, language, filename, mimetype = compile_paste(args, opts.language)
|
||
|
except Exception as err:
|
||
|
fail('Error while reading the file(s): %s' % err, 2)
|
||
|
if not data:
|
||
|
fail('Aborted, no content to paste.', 4)
|
||
|
|
||
|
# create paste
|
||
|
code = make_utf8(data, opts.encoding)
|
||
|
pid = create_paste(code, language, filename, mimetype, opts.private)
|
||
|
url = '%sshow/%s/' % (_server_name, pid)
|
||
|
print(url)
|
||
|
if opts.open_browser:
|
||
|
open_webbrowser(url)
|
||
|
if opts.clipboard:
|
||
|
copy_url(url)
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
sys.exit(main())
|