From 9c7f9e5786b0eef7ca4412397cfb1063e42f67bd Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 16 Oct 2016 22:38:19 +0530 Subject: [PATCH] Edit Book: When using the arrange into folders tool do not change the case of already existing folders in the book. Fixes #1633875 [Editor:Arrange Folders problem on Windows](https://bugs.launchpad.net/calibre/+bug/1633875) --- src/calibre/ebooks/oeb/polish/container.py | 2 +- src/calibre/ebooks/oeb/polish/replace.py | 15 +++++++++++++++ src/calibre/ebooks/oeb/polish/tests/container.py | 11 ++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/calibre/ebooks/oeb/polish/container.py b/src/calibre/ebooks/oeb/polish/container.py index 198cfae728..6ae22da9d0 100644 --- a/src/calibre/ebooks/oeb/polish/container.py +++ b/src/calibre/ebooks/oeb/polish/container.py @@ -484,7 +484,7 @@ class Container(ContainerBase): # {{{ return name_to_abspath(name, self.root) def exists(self, name): - ''' True iff a file corresponding to the canonical name exists. Note + ''' True iff a file/directory corresponding to the canonical name exists. Note that this function suffers from the limitations of the underlying OS filesystem, in particular case (in)sensitivity. So on a case insensitive filesystem this will return True even if the case of name diff --git a/src/calibre/ebooks/oeb/polish/replace.py b/src/calibre/ebooks/oeb/polish/replace.py index b6afc92a9a..734b7f62d1 100644 --- a/src/calibre/ebooks/oeb/polish/replace.py +++ b/src/calibre/ebooks/oeb/polish/replace.py @@ -267,10 +267,25 @@ def get_recommended_folders(container, names): return {n:recommendations.get(mt_to_category(container, guess_type(os.path.basename(n))), opf_folder) for n in names} +def normalize_case(container, val): + parts = val.split('/') + ans = [] + for i in range(len(parts)): + q = '/'.join(parts[:i+1]) + x = container.name_to_abspath(q) + xl = parts[i].lower() + candidates = [c for c in os.listdir(os.path.dirname(x)) if c != parts[i] and c.lower() == xl] + ans.append(candidates[0] if candidates else parts[i]) + return '/'.join(ans) + + def rationalize_folders(container, folder_type_map): all_names = set(container.mime_map) new_names = set() name_map = {} + for key in tuple(folder_type_map): + val = folder_type_map[key] + folder_type_map[key] = normalize_case(container, val) for name in all_names: if name.startswith('META-INF/'): continue diff --git a/src/calibre/ebooks/oeb/polish/tests/container.py b/src/calibre/ebooks/oeb/polish/tests/container.py index 3a076c7b43..2a798a8bab 100644 --- a/src/calibre/ebooks/oeb/polish/tests/container.py +++ b/src/calibre/ebooks/oeb/polish/tests/container.py @@ -12,7 +12,7 @@ from zipfile import ZipFile from calibre import CurrentDir from calibre.ebooks.oeb.polish.tests.base import BaseTest, get_simple_book, get_split_book from calibre.ebooks.oeb.polish.container import get_container as _gc, clone_container, OCF_NS -from calibre.ebooks.oeb.polish.replace import rename_files +from calibre.ebooks.oeb.polish.replace import rename_files, rationalize_folders from calibre.ebooks.oeb.polish.split import split, merge from calibre.utils.filenames import nlinks_file from calibre.ptempfile import TemporaryFile, TemporaryDirectory @@ -264,3 +264,12 @@ class ContainerTests(BaseTest): self.assertTrue(os.path.exists('.git/xxx')) self.assertTrue(os.path.exists('images/test-container.xyz')) self.assertFalse(os.path.exists('images/cover.jpg')) + + def test_folder_type_map_case(self): + book = get_simple_book() + c = get_container(book) + c.add_file('Image/testcase.png', b'xxx') + rationalize_folders(c, {'image':'image'}) + self.assertTrue(c.has_name('Image/testcase.png')) + self.assertTrue(c.exists('Image/testcase.png')) + self.assertFalse(c.has_name('image/testcase.png'))