diff --git a/src/calibre/gui2/viewer/convert_book.py b/src/calibre/gui2/viewer/convert_book.py index 52c10fb38c..3f1e1e3850 100644 --- a/src/calibre/gui2/viewer/convert_book.py +++ b/src/calibre/gui2/viewer/convert_book.py @@ -7,7 +7,6 @@ from __future__ import absolute_import, division, print_function, unicode_litera import errno import json import os -import shutil import tempfile import time from hashlib import sha1 @@ -16,6 +15,7 @@ from calibre import walk from calibre.constants import cache_dir, iswindows from calibre.ptempfile import TemporaryFile from calibre.srv.render_book import RENDER_VERSION +from calibre.utils.filenames import rmtree from calibre.utils.ipc.simple_worker import start_pipe_worker from calibre.utils.lock import ExclusiveFile from calibre.utils.serialize import msgpack_dumps @@ -55,7 +55,7 @@ def robust_rmtree(x): retries = 2 if iswindows else 1 # retry on windows to get around the idiotic mandatory file locking for i in range(retries): try: - shutil.rmtree(x) + rmtree(x) return True except EnvironmentError: time.sleep(0.1) @@ -297,7 +297,7 @@ def find_tests(): book_cache_dir.override = os.path.join(self.tdir, 'ev2') def tearDown(self): - shutil.rmtree(self.tdir) + rmtree(self.tdir) del book_cache_dir.override def test_viewer_cache(self): diff --git a/src/calibre/srv/books.py b/src/calibre/srv/books.py index 61bfee301e..25a6d5c0ce 100644 --- a/src/calibre/srv/books.py +++ b/src/calibre/srv/books.py @@ -7,7 +7,6 @@ from __future__ import absolute_import, division, print_function, unicode_litera import errno import json as jsonlib import os -import shutil import tempfile import time from functools import partial @@ -21,6 +20,7 @@ from calibre.srv.metadata import book_as_json from calibre.srv.render_book import RENDER_VERSION from calibre.srv.routes import endpoint, json from calibre.srv.utils import get_db, get_library_data +from calibre.utils.filenames import rmtree from calibre.utils.serialize import json_dumps from polyglot.builtins import as_unicode, map @@ -66,7 +66,7 @@ def safe_remove(x, is_file=None): if is_file is None: is_file = os.path.isfile(x) try: - os.remove(x) if is_file else shutil.rmtree(x, ignore_errors=True) + os.remove(x) if is_file else rmtree(x, ignore_errors=True) except EnvironmentError: pass diff --git a/src/calibre/srv/render_book.py b/src/calibre/srv/render_book.py index af5ffb9c0d..21857f7705 100644 --- a/src/calibre/srv/render_book.py +++ b/src/calibre/srv/render_book.py @@ -7,7 +7,6 @@ from __future__ import absolute_import, division, print_function, unicode_litera import json import os import re -import shutil import sys import time from collections import defaultdict @@ -15,10 +14,10 @@ from datetime import datetime from functools import partial from itertools import count from math import ceil -from lxml.etree import Comment from css_parser import replaceUrls from css_parser.css import CSSRule +from lxml.etree import Comment from calibre import detect_ncpus, force_unicode, prepare_string_for_xml from calibre.constants import iswindows, plugins @@ -41,6 +40,7 @@ from calibre.ptempfile import PersistentTemporaryDirectory from calibre.srv.metadata import encode_datetime from calibre.srv.opts import grouper from calibre.utils.date import EPOCH +from calibre.utils.filenames import rmtree from calibre.utils.ipc.simple_worker import start_pipe_worker from calibre.utils.iso8601 import parse_iso8601 from calibre.utils.logging import default_log @@ -448,11 +448,11 @@ class RenderManager(object): p.kill() del self.workers try: - shutil.rmtree(self.tdir) + rmtree(self.tdir) except EnvironmentError: time.sleep(0.1) try: - shutil.rmtree(self.tdir) + rmtree(self.tdir) except EnvironmentError: pass del self.tdir diff --git a/src/calibre/utils/filenames.py b/src/calibre/utils/filenames.py index 93236af4f5..2be2f9234d 100644 --- a/src/calibre/utils/filenames.py +++ b/src/calibre/utils/filenames.py @@ -12,7 +12,7 @@ from math import ceil from calibre import force_unicode, isbytestring, prints, sanitize_file_name from calibre.constants import ( - filesystem_encoding, iswindows, plugins, preferred_encoding, isosx + filesystem_encoding, iswindows, plugins, preferred_encoding, isosx, ispy3 ) from calibre.utils.localization import get_udc from polyglot.builtins import iteritems, itervalues, unicode_type, range @@ -627,3 +627,16 @@ def copytree_using_links(path, dest, dest_is_parent=True, filecopyfunc=copyfile) hardlink(src, df) except Exception: filecopyfunc(src, df) + + +if not ispy3 and not iswindows: + # On POSIX in python2 if you pass a unicode path to rmtree + # it tries to decode all filenames it encounters while walking + # the tree which leads to unicode errors on Linux where there + # can be non-decodeable filenames. + def rmtree(x, **kw): + if not isinstance(x, bytes): + x = x.encode('utf-8') + return shutil.rmtree(x, **kw) +else: + rmtree = shutil.rmtree