From e8512141a1fbe40975117ac286058ce83e7d916a Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 22 Feb 2012 13:20:27 +0530 Subject: [PATCH] Use unicode temp paths on unix as well, for consistency. --- src/calibre/ptempfile.py | 74 +++++++++++++++------------------------- src/calibre/startup.py | 5 +++ 2 files changed, 33 insertions(+), 46 deletions(-) diff --git a/src/calibre/ptempfile.py b/src/calibre/ptempfile.py index 9bf189d5a2..1c595d4c12 100644 --- a/src/calibre/ptempfile.py +++ b/src/calibre/ptempfile.py @@ -5,9 +5,10 @@ __copyright__ = '2008, Kovid Goyal ' Provides platform independent temporary files that persist even after being closed. """ -import tempfile, os, atexit, binascii, cPickle +import tempfile, os, atexit +from future_builtins import map -from calibre.constants import (__version__, __appname__, +from calibre.constants import (__version__, __appname__, filesystem_encoding, get_unicode_windows_env_var, iswindows, get_windows_temp_path) def cleanup(path): @@ -40,6 +41,7 @@ def base_dir(): if _base_dir is None: td = os.environ.get('CALIBRE_WORKER_TEMP_DIR', None) if td is not None: + import cPickle, binascii try: td = cPickle.loads(binascii.unhexlify(td)) except: @@ -52,58 +54,38 @@ def base_dir(): base = get_unicode_windows_env_var('CALIBRE_TEMP_DIR') prefix = app_prefix(u'tmp_') if base is None and iswindows: - # On windows always use a unicode temp path, as for some - # localized (east asian) windows builds, there's no reliable - # way to escalate to unicode only when needed. See - # https://bugs.launchpad.net/bugs/937389 Hopefully, by now, the - # rest of calibre can deal with unicode temp paths. We'll leave - # temp paths as bytestring on Unix, as the temp dir on unix is - # very rarely non ascii anyway. + # On windows, if the TMP env var points to a path that + # cannot be encoded using the mbcs encoding, then the + # python 2 tempfile algorithm for getting the temporary + # directory breaks. So we use the win32 api to get a + # unicode temp path instead. See + # https://bugs.launchpad.net/bugs/937389 base = get_windows_temp_path() - try: - # First try an ascii path as that is what was done historically - # and we dont want to break working code - # _base_dir will be a bytestring - _base_dir = tempfile.mkdtemp(prefix=prefix.encode('ascii'), dir=base) - except: - # Failed to create tempdir (probably localized windows) - # Try unicode. This means that all temp paths created by this - # module will be unicode, this may cause problems elsewhere, if - # so, hopefully people will open tickets and they can be fixed. - _base_dir = tempfile.mkdtemp(prefix=prefix, dir=base) + _base_dir = tempfile.mkdtemp(prefix=prefix, dir=base) atexit.register(remove_dir, _base_dir) + + # Tell the tempfile module to in future always use our temp dir + # This also means that it will return unicode paths, instead of + # bytestrings + tempfile.tempdir = _base_dir + return _base_dir +def force_unicode(x): + # Cannot use the implementation in calibre.__init__ as it causes a circular + # dependency + if isinstance(x, bytes): + x = x.decode(filesystem_encoding) + return x + def _make_file(suffix, prefix, base): - try: - fd, name = tempfile.mkstemp(suffix, prefix, dir=base) - except (UnicodeDecodeError, OSError): - # On some windows systems, we get an OSError because base is not - # unicode and windows cannot find the path pointed to by base - global _base_dir - from calibre.constants import filesystem_encoding - base_dir() - if not isinstance(_base_dir, unicode): - _base_dir = _base_dir.decode(filesystem_encoding) - base = base.decode(filesystem_encoding) - fd, name = tempfile.mkstemp(suffix, prefix, dir=dir) - return fd, name + suffix, prefix = map(force_unicode, (suffix, prefix)) + return tempfile.mkstemp(suffix, prefix, dir=base) def _make_dir(suffix, prefix, base): - try: - tdir = tempfile.mkdtemp(suffix, prefix, base) - except (ValueError, OSError): - # On some windows systems, we get an OSError because base is not - # unicode and windows cannot find the path pointed to by base - global _base_dir - from calibre.constants import filesystem_encoding - base_dir() - if not isinstance(_base_dir, unicode): - _base_dir = _base_dir.decode(filesystem_encoding) - base = base.decode(filesystem_encoding) - tdir = tempfile.mkdtemp(suffix, prefix, base) - return tdir + suffix, prefix = map(force_unicode, (suffix, prefix)) + return tempfile.mkdtemp(suffix, prefix, base) class PersistentTemporaryFile(object): """ diff --git a/src/calibre/startup.py b/src/calibre/startup.py index 78f8aff7e3..02a4743000 100644 --- a/src/calibre/startup.py +++ b/src/calibre/startup.py @@ -33,6 +33,11 @@ if not _run_once: if len(sys.argv) > 1 and not isinstance(sys.argv[1], unicode): sys.argv[1:] = winutil.argv()[1-len(sys.argv):] + ################################################################################ + # Ensure that all temp files/dirs are created under a calibre tmp dir + from calibre.ptempfile import base_dir + base_dir() + ################################################################################ # Convert command line arguments to unicode enc = preferred_encoding