Preserve notes resource mtimes when importing notes db

This commit is contained in:
Kovid Goyal 2023-10-16 10:35:41 +05:30
parent 53f20a2ce6
commit 1e9a543e54
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 23 additions and 10 deletions

View File

@ -989,8 +989,8 @@ class DB:
id_val = self.tables[field].id_map[item_id]
return self.notes.unretire(self.conn, field, item_id, id_val)
def add_notes_resource(self, path_or_stream, name) -> int:
return self.notes.add_resource(self.conn, path_or_stream, name)
def add_notes_resource(self, path_or_stream, name, mtime=None) -> int:
return self.notes.add_resource(self.conn, path_or_stream, name, mtime=mtime)
def get_notes_resource(self, resource_hash) -> Optional[dict]:
return self.notes.get_resource_data(self.conn, resource_hash)

View File

@ -20,7 +20,7 @@ from functools import partial, wraps
from io import DEFAULT_BUFFER_SIZE, BytesIO
from queue import Queue
from threading import Lock
from time import monotonic, sleep, time
from time import mktime, monotonic, sleep, time
from typing import NamedTuple, Optional, Tuple
from calibre import as_unicode, detect_ncpus, isbytestring
@ -724,9 +724,9 @@ class Cache:
return self.backend.set_notes_for(field, item_id, doc, searchable_text, resource_hashes, remove_unused_resources)
@write_api
def add_notes_resource(self, path_or_stream_or_data, name: str) -> int:
def add_notes_resource(self, path_or_stream_or_data, name: str, mtime: float = None) -> int:
' Add the specified resource so it can be referenced by notes and return its content hash '
return self.backend.add_notes_resource(path_or_stream_or_data, name)
return self.backend.add_notes_resource(path_or_stream_or_data, name, mtime)
@read_api
def get_notes_resource(self, resource_hash) -> Optional[dict]:
@ -3460,7 +3460,10 @@ def import_library(library_key, importer, library_path, progress=None, abort=Non
with closing(importer.start_file(metadata['notes.db'], 'notes.db for ' + library_path)) as stream:
stream.check_hash = False
with zipfile.ZipFile(stream) as zf:
zf.extractall(notes_dir)
for zi in zf.infolist():
tpath = zf._extract_member(zi, notes_dir, None)
date_time = mktime(zi.date_time + (0, 0, -1))
os.utime(tpath, (date_time, date_time))
if abort is not None and abort.is_set():
return
cache = Cache(DB(library_path, load_user_formatter_functions=False))

View File

@ -306,7 +306,7 @@ class Notes:
for path in items[:extra]:
remove_with_retry(path, is_dir=True)
def add_resource(self, conn, path_or_stream_or_data, name, update_name=True):
def add_resource(self, conn, path_or_stream_or_data, name, update_name=True, mtime=None):
if isinstance(path_or_stream_or_data, bytes):
data = path_or_stream_or_data
elif isinstance(path_or_stream_or_data, str):
@ -332,6 +332,9 @@ class Notes:
f = open(path, 'wb')
with f:
f.write(data)
if mtime is not None:
os.utime(f.name, (mtime, mtime))
name = sanitize_file_name(name)
base_name, ext = os.path.splitext(name)
c = 0

View File

@ -264,8 +264,8 @@ class FilesystemTest(BaseTest):
bookdir = os.path.dirname(ic.format_abspath(1, '__COVER_INTERNAL__'))
self.assertEqual('exf', open(os.path.join(bookdir, 'exf')).read())
self.assertEqual('recurse', open(os.path.join(bookdir, 'sub', 'recurse')).read())
r1 = cache.add_notes_resource(b'res1', 'res.jpg')
r2 = cache.add_notes_resource(b'res2', 'res.jpg')
r1 = cache.add_notes_resource(b'res1', 'res.jpg', mtime=time.time()-113)
r2 = cache.add_notes_resource(b'res2', 'res.jpg', mtime=time.time()-1115)
cache.set_notes_for('authors', 2, 'some notes', resource_hashes=(r1, r2))
cache.add_format(1, 'TXT', BytesIO(b'testing exim'))
cache.fts_indexing_sleep_time = 0.001
@ -285,7 +285,10 @@ class FilesystemTest(BaseTest):
ic = import_library('l', importer, idir)
self.assertEqual(ic.fts_search('exim')[0]['id'], 1)
self.assertEqual(cache.notes_for('authors', 2), ic.notes_for('authors', 2))
self.assertEqual(cache.get_notes_resource(r1), ic.get_notes_resource(r1))
a, b = cache.get_notes_resource(r1), ic.get_notes_resource(r1)
at, bt, = a.pop('mtime'), b.pop('mtime')
self.assertEqual(a, b)
self.assertLess(abs(at-bt), 2)
def test_find_books_in_directory(self):
from calibre.db.adding import find_books_in_directory, compile_rule

View File

@ -151,6 +151,10 @@ def test_cache_api(self: 'NotesTest'):
self.assertGreater(note_id, 0)
self.assertIn('<p>test simple exim <img', cache.notes_for('authors', author_id))
res2 = tuple(cache.get_notes_resource(x) for x in cache.notes_resources_used_by('authors', author_id))
for x in res:
del x['mtime']
for x in res2:
del x['mtime']
self.ae(sorted(res, key=itemgetter('name')), sorted(res2, key=itemgetter('name')))