Sanitize the ImageMagick environment variables before launching external utilities. See #1389449 (ImageMagick scripts error when run from within Calibre)

This commit is contained in:
Kovid Goyal 2014-11-05 09:03:41 +05:30
parent 0858094226
commit 0869226e51

View File

@ -2,6 +2,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
""" The GUI """ """ The GUI """
import os, sys, Queue, threading, glob import os, sys, Queue, threading, glob
from contextlib import contextmanager
from threading import RLock, Lock from threading import RLock, Lock
from urllib import unquote from urllib import unquote
from PyQt5.Qt import ( from PyQt5.Qt import (
@ -678,7 +679,7 @@ class FileDialog(QObject):
initial_dir = select_initial_dir(initial_dir) initial_dir = select_initial_dir(initial_dir)
self.selected_files = [] self.selected_files = []
use_native_dialog = 'CALIBRE_NO_NATIVE_FILEDIALOGS' not in os.environ use_native_dialog = 'CALIBRE_NO_NATIVE_FILEDIALOGS' not in os.environ
with SanitizeLibraryPath(): with sanitize_env_vars():
opts = QFileDialog.Option() opts = QFileDialog.Option()
if not use_native_dialog: if not use_native_dialog:
opts |= QFileDialog.DontUseNativeDialog opts |= QFileDialog.DontUseNativeDialog
@ -1078,30 +1079,42 @@ class Application(QApplication):
_store_app = None _store_app = None
class SanitizeLibraryPath(object): @contextmanager
'''Remove the bundled calibre libraries from LD_LIBRARY_PATH on linux. This def sanitize_env_vars():
'''Unset various environment variables that calibre uses. This
is needed to prevent library conflicts when launching external utilities.''' is needed to prevent library conflicts when launching external utilities.'''
env_vars = {'LD_LIBRARY_PATH':'/lib', 'QT_PLUGIN_PATH':'/lib/qt_plugins'} if islinux and isfrozen:
env_vars = {'LD_LIBRARY_PATH':'/lib', 'QT_PLUGIN_PATH':'/lib/qt_plugins', 'MAGICK_CODER_MODULE_PATH':None, 'MAGICK_CODER_FILTER_PATH':None}
elif iswindows:
env_vars = {k:None for k in 'MAGICK_HOME MAGICK_CONFIGURE_PATH MAGICK_CODER_MODULE_PATH MAGICK_FILTER_MODULE_PATH QT_PLUGIN_PATH'.split()}
elif isosx:
env_vars = {k:None for k in
'FONTCONFIG_FILE FONTCONFIG_PATH MAGICK_CONFIGURE_PATH MAGICK_CODER_MODULE_PATH MAGICK_FILTER_MODULE_PATH QT_PLUGIN_PATH'.split()}
else:
env_vars = {}
def __enter__(self): originals = {x:os.environ.get(x, '') for x in env_vars}
self.originals = {x:os.environ.get(x, '') for x in self.env_vars} changed = {x:False for x in env_vars}
self.changed = {x:False for x in self.env_vars} for var, suffix in env_vars.iteritems():
if isfrozen and islinux: paths = [x for x in originals[var].split(os.pathsep) if x]
for var, suffix in self.env_vars.iteritems(): npaths = [] if suffix is None else [x for x in paths if x != (sys.frozen_path + suffix)]
paths = [x for x in self.originals[var].split(os.pathsep) if x] if len(npaths) < len(paths):
npaths = [x for x in paths if x != sys.frozen_path + suffix] if npaths:
if len(npaths) < len(paths): os.environ[var] = os.pathsep.join(npaths)
if npaths: else:
os.environ[var] = os.pathsep.join(npaths) del os.environ[var]
else: changed[var] = True
del os.environ[var]
self.changed[var] = True
def __exit__(self, *args): try:
for var, orig in self.originals.iteritems(): yield
if self.changed[var]: finally:
os.environ[var] = orig for var, orig in originals.iteritems():
if changed[var]:
if orig:
os.environ[var] = orig
elif var in os.environ:
del os.environ[var]
def open_url(qurl): def open_url(qurl):
# Qt 5 requires QApplication to be constructed before trying to use # Qt 5 requires QApplication to be constructed before trying to use
@ -1109,7 +1122,7 @@ def open_url(qurl):
ensure_app() ensure_app()
if isinstance(qurl, basestring): if isinstance(qurl, basestring):
qurl = QUrl(qurl) qurl = QUrl(qurl)
with SanitizeLibraryPath(): with sanitize_env_vars():
QDesktopServices.openUrl(qurl) QDesktopServices.openUrl(qurl)
def get_current_db(): def get_current_db():