mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
newdb: Fix replacing formats in a book creating orphans
When replacing formats in a book with a very long title+authors on windows, newdb could leave behind the old format file, because the filename shortening algorithm has changed. Handle that case.
This commit is contained in:
parent
121469daa5
commit
41bcffea92
@ -1337,7 +1337,7 @@ class DB(object):
|
||||
if wam is not None:
|
||||
wam.close_handles()
|
||||
|
||||
def add_format(self, book_id, fmt, stream, title, author, path):
|
||||
def add_format(self, book_id, fmt, stream, title, author, path, current_name):
|
||||
fmt = ('.' + fmt.lower()) if fmt else ''
|
||||
fname = self.construct_file_name(book_id, title, author, len(fmt))
|
||||
path = os.path.join(self.library_path, path)
|
||||
@ -1345,6 +1345,22 @@ class DB(object):
|
||||
if not os.path.exists(path):
|
||||
os.makedirs(path)
|
||||
size = 0
|
||||
if current_name is not None:
|
||||
old_path = os.path.join(path, current_name + fmt)
|
||||
if old_path != dest:
|
||||
# Ensure that the old format file is not orphaned, this can
|
||||
# happen if the algorithm in construct_file_name is changed.
|
||||
try:
|
||||
# rename rather than remove, so that if something goes
|
||||
# wrong in the rest of this function, at least the file is
|
||||
# not deleted
|
||||
os.rename(old_path, dest)
|
||||
except EnvironmentError as e:
|
||||
if getattr(e, 'errno', None) != errno.ENOENT:
|
||||
# Failing to rename the old format will at worst leave a
|
||||
# harmless orphan, so log and ignore the error
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
if (not getattr(stream, 'name', False) or not samefile(dest, stream.name)):
|
||||
with lopen(dest, 'wb') as f:
|
||||
|
@ -1201,7 +1201,8 @@ class Cache(object):
|
||||
title = self._field_for('title', book_id, default_value=_('Unknown'))
|
||||
author = self._field_for('authors', book_id, default_value=(_('Unknown'),))[0]
|
||||
stream = stream_or_path if hasattr(stream_or_path, 'read') else lopen(stream_or_path, 'rb')
|
||||
size, fname = self.backend.add_format(book_id, fmt, stream, title, author, path)
|
||||
|
||||
size, fname = self.backend.add_format(book_id, fmt, stream, title, author, path, name)
|
||||
del stream
|
||||
|
||||
max_size = self.fields['formats'].table.update_fmt(book_id, fmt, fname, size, self.backend)
|
||||
|
@ -7,7 +7,7 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os
|
||||
import os, glob
|
||||
from io import BytesIO
|
||||
from tempfile import NamedTemporaryFile
|
||||
from datetime import timedelta
|
||||
@ -285,3 +285,19 @@ class AddRemoveTest(BaseTest):
|
||||
af(db.has_format(1, 'ORIGINAL_FMT1'))
|
||||
ae(set(fmts), set(db.formats(1, verify_formats=False)))
|
||||
# }}}
|
||||
|
||||
def test_format_orphan(self): # {{{
|
||||
' Test that adding formats does not create orphans if the file name algorithm changes '
|
||||
cache = self.init_cache()
|
||||
path = cache.format_abspath(1, 'FMT1')
|
||||
base, name = os.path.split(path)
|
||||
prefix = 'mushroomxx'
|
||||
os.rename(path, os.path.join(base, prefix + name))
|
||||
cache.fields['formats'].table.fname_map[1]['FMT1'] = prefix + os.path.splitext(name)[0]
|
||||
old = glob.glob(os.path.join(base, '*.fmt1'))
|
||||
cache.add_format(1, 'FMT1', BytesIO(b'xxxx'), run_hooks=False)
|
||||
new = glob.glob(os.path.join(base, '*.fmt1'))
|
||||
self.assertNotEqual(old, new)
|
||||
self.assertEqual(len(old), len(new))
|
||||
self.assertNotIn(prefix, cache.fields['formats'].format_fname(1, 'FMT1'))
|
||||
# }}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user