1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
|
# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# Copyright (c) 2012, Peter Levi <peterlevi@peterlevi.com>
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
### END LICENSE
import gettext
import logging
import datetime
gettext.textdomain('variety')
import os
import sys
def _u(s):
if s is None:
return s
if isinstance(s, unicode):
return s
else:
return unicode(s, 'utf8')
def _str(s):
if s is None:
return s
if isinstance(s, unicode):
return s.encode('utf8')
else:
return str(s)
def _(text):
# Use "from locale import gettext" if we are deploying to /opt/extras
# Use "from gettext import gettext" when using standard Debian deployment
from gettext import gettext as _
return _u(_(text))
def safe_print(text, ascii_text=None):
"""
Python's print throws UnicodeEncodeError if the terminal encoding is borked. This version tries print, then logging, then printing the ascii text when one is present.
If does not throw exceptions even if it fails.
:param text: Text to print, str or unicode, possibly with non-ascii symbols in it
:param ascii_text: optional. Original untranslated ascii version of the text when present.
"""
try:
print(text)
except: # UnicodeEncodeError can happen here if the terminal is strangely configured, but we are playing safe and catching everything
try:
logging.getLogger("variety").error('Error printing non-ascii text, terminal encoding is %s' % sys.stdout.encoding)
if ascii_text:
try:
print ascii_text
return
except:
pass
logging.getLogger("variety").warning(text)
except:
pass
class SafeLogger(logging.Logger):
"""
Fixes UnicodeDecodeErrors errors in logging calls:
Accepts lambda instead of string messages. Catches errors when evaluatiating the passed lambda.
"""
def makeRecord(self, name, level, fn, lno, msg, args, exc_info, func=None, extra=None):
try:
new_msg = msg if isinstance(msg, basestring) else msg()
except:
locale_info = 'Unknown'
try:
import os
locale_info = 'Terminal encoding=%s, LANG=%s, LANGUAGE=%s' % (
sys.stdout.encoding, os.getenv('LANG'), os.getenv('LANGUAGE'))
logging.getLogger("variety").exception('Errors while logging. Locale info: %s' % locale_info)
# TODO gather and log more info here
except:
pass
new_msg = 'Errors while logging. Locale info: %s' % locale_info
return super(SafeLogger, self).makeRecord(name, level, fn, lno, new_msg, args, exc_info, func, extra)
logging.setLoggerClass(SafeLogger)
# # Change default encoding from ascii to UTF8 - works OK on Linux and prevents various UnicodeEncodeErrors/UnicodeDecodeErrors
# Still, generally considerd bad practice, may cause some deep hidden errors, as various Python stuff depends on it
# reload(sys)
# sys.setdefaultencoding('UTF8')
import signal
import dbus, dbus.service, dbus.glib
import logging
from gi.repository import Gtk, Gdk, GObject # pylint: disable=E0611
from variety import VarietyWindow
from variety import ThumbsManager
from variety import ThumbsWindow
from variety.Util import Util
from variety_lib import set_up_logging
DBUS_KEY = 'com.peterlevi.Variety'
DBUS_PATH = '/com/peterlevi/Variety'
class VarietyService(dbus.service.Object):
def __init__(self, variety_window):
self.variety_window = variety_window
bus_name = dbus.service.BusName(DBUS_KEY, bus = dbus.SessionBus())
dbus.service.Object.__init__(self, bus_name, DBUS_PATH)
@dbus.service.method(dbus_interface=DBUS_KEY, in_signature='as', out_signature='s')
def process_command(self, arguments):
result = self.variety_window.process_command(arguments, initial_run=False)
return "" if result is None else result
VARIETY_WINDOW = None
terminate = False
def sigint_handler(*args):
global terminate
terminate = True
def check_quit():
global terminate
if not terminate:
GObject.timeout_add(1000, check_quit)
return
logging.getLogger("variety").info("Terminating signal received, quitting...")
safe_print(_("Terminating signal received, quitting..."),
"Terminating signal received, quitting...")
global VARIETY_WINDOW
if VARIETY_WINDOW:
GObject.idle_add(VARIETY_WINDOW.on_quit)
Util.start_force_exit_thread(10)
def monkeypatch_ssl():
"""
HTTPS connections may fail on Ubuntu 12.04 to servers with disabled SSL with this error:
URLError: <urlopen error [Errno 1] _ssl.c:504: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure>.
This monkeypatching routine fixes the issue by forcing it to use TLSv1 instead of SSL.
Solution copied from http://askubuntu.com/questions/116020/python-https-requests-urllib2-to-some-sites-fail-on-ubuntu-12-04-without-proxy
"""
import functools
import ssl
old_init = ssl.SSLSocket.__init__
@functools.wraps(old_init)
def ubuntu_openssl_bug_965371(self, *args, **kwargs):
kwargs['ssl_version'] = ssl.PROTOCOL_TLSv1
old_init(self, *args, **kwargs)
ssl.SSLSocket.__init__ = ubuntu_openssl_bug_965371
REL_DATE = "2016-10-30"
def main():
# Ctrl-C
signal.signal(signal.SIGINT, sigint_handler)
signal.signal(signal.SIGTERM, sigint_handler)
signal.signal(signal.SIGQUIT, sigint_handler)
Util.makedirs(os.path.expanduser(u"~/.config/variety/"))
arguments = map(_u, sys.argv[1:])
# validate arguments and set up logging
options, args = VarietyWindow.VarietyWindow.parse_options(arguments)
set_up_logging(options.verbose)
monkeypatch_ssl()
if options.verbose > 2:
Util.log_all(VarietyWindow.VarietyWindow)
if options.verbose > 3:
Util.log_all(ThumbsManager.ThumbsManager)
Util.log_all(ThumbsWindow.ThumbsWindow)
bus = dbus.SessionBus()
# ensure singleton
if bus.request_name(DBUS_KEY) != dbus.bus.REQUEST_NAME_REPLY_PRIMARY_OWNER:
if not arguments:
arguments = ["--preferences"]
safe_print(_("Variety is already running. Sending the command to the running instance."),
"Variety is already running. Sending the command to the running instance.")
method = bus.get_object(DBUS_KEY, DBUS_PATH).get_dbus_method("process_command")
result = method(arguments)
if result:
safe_print(result)
return
# Run the application.
window = VarietyWindow.VarietyWindow()
global VARIETY_WINDOW
VARIETY_WINDOW = window
service = VarietyService(window)
bus.call_on_disconnection(window.on_quit)
window.start(arguments)
GObject.timeout_add(2000, check_quit)
GObject.threads_init()
Gdk.threads_init()
Gdk.threads_enter()
Gtk.main()
Gdk.threads_leave()
|