mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Make communication with toc editor process more robust
A crash on dialog close no longer affects writing the result. And avoid using the racy lock files for ipc.
This commit is contained in:
parent
2c802b7839
commit
e1a3458c51
@ -152,22 +152,15 @@ class ToCEditAction(InterfaceAction):
|
|||||||
self.check_for_completions()
|
self.check_for_completions()
|
||||||
|
|
||||||
def check_for_completions(self):
|
def check_for_completions(self):
|
||||||
from calibre.utils.lock import lock_file
|
from calibre.utils.filenames import retry_on_fail
|
||||||
for job in tuple(self.jobs):
|
for job in tuple(self.jobs):
|
||||||
lock_path = job['path'] + '.lock'
|
started_path = job['path'] + '.started'
|
||||||
if job['started']:
|
result_path = job['path'] + '.result'
|
||||||
if not os.path.exists(lock_path):
|
if job['started'] and os.path.exists(result_path):
|
||||||
self.jobs.remove(job)
|
self.jobs.remove(job)
|
||||||
continue
|
with open(result_path) as f:
|
||||||
try:
|
ret = int(f.read().strip())
|
||||||
lf = lock_file(lock_path, timeout=0.01, sleep_time=0.005)
|
retry_on_fail(os.remove, result_path)
|
||||||
except EnvironmentError:
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
self.jobs.remove(job)
|
|
||||||
ret = int(lf.read().decode('ascii'))
|
|
||||||
lf.close()
|
|
||||||
os.remove(lock_path)
|
|
||||||
if ret == 0:
|
if ret == 0:
|
||||||
db = self.gui.current_db
|
db = self.gui.current_db
|
||||||
if db.new_api.library_id != job['library_id']:
|
if db.new_api.library_id != job['library_id']:
|
||||||
@ -181,8 +174,9 @@ class ToCEditAction(InterfaceAction):
|
|||||||
if monotonic() - job['start_time'] > 10:
|
if monotonic() - job['start_time'] > 10:
|
||||||
self.jobs.remove(job)
|
self.jobs.remove(job)
|
||||||
continue
|
continue
|
||||||
if os.path.exists(lock_path):
|
if os.path.exists(started_path):
|
||||||
job['started'] = True
|
job['started'] = True
|
||||||
|
retry_on_fail(os.remove, started_path)
|
||||||
if self.jobs:
|
if self.jobs:
|
||||||
QTimer.singleShot(100, self.check_for_completions)
|
QTimer.singleShot(100, self.check_for_completions)
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
import textwrap
|
import textwrap
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from qt.core import (
|
from qt.core import (
|
||||||
@ -29,7 +30,7 @@ from calibre.gui2.progress_indicator import ProgressIndicator
|
|||||||
from calibre.gui2.toc.location import ItemEdit
|
from calibre.gui2.toc.location import ItemEdit
|
||||||
from calibre.ptempfile import reset_base_dir
|
from calibre.ptempfile import reset_base_dir
|
||||||
from calibre.utils.config import JSONConfig
|
from calibre.utils.config import JSONConfig
|
||||||
from calibre.utils.lock import ExclusiveFile
|
from calibre.utils.filenames import atomic_rename
|
||||||
from calibre.utils.logging import GUILog
|
from calibre.utils.logging import GUILog
|
||||||
from polyglot.builtins import map, range, unicode_type
|
from polyglot.builtins import map, range, unicode_type
|
||||||
|
|
||||||
@ -985,8 +986,9 @@ class TOCEditor(QDialog): # {{{
|
|||||||
explode_done = pyqtSignal(object)
|
explode_done = pyqtSignal(object)
|
||||||
writing_done = pyqtSignal(object)
|
writing_done = pyqtSignal(object)
|
||||||
|
|
||||||
def __init__(self, pathtobook, title=None, parent=None, prefs=None):
|
def __init__(self, pathtobook, title=None, parent=None, prefs=None, write_result_to=None):
|
||||||
QDialog.__init__(self, parent)
|
QDialog.__init__(self, parent)
|
||||||
|
self.write_result_to = write_result_to
|
||||||
self.prefs = prefs or te_prefs
|
self.prefs = prefs or te_prefs
|
||||||
self.pathtobook = pathtobook
|
self.pathtobook = pathtobook
|
||||||
self.working = True
|
self.working = True
|
||||||
@ -1071,7 +1073,7 @@ class TOCEditor(QDialog): # {{{
|
|||||||
' more information.')%self.book_title, det_msg=tb, show=True)
|
' more information.')%self.book_title, det_msg=tb, show=True)
|
||||||
super(TOCEditor, self).reject()
|
super(TOCEditor, self).reject()
|
||||||
return
|
return
|
||||||
|
self.write_result(0)
|
||||||
super(TOCEditor, self).accept()
|
super(TOCEditor, self).accept()
|
||||||
|
|
||||||
def reject(self):
|
def reject(self):
|
||||||
@ -1083,8 +1085,17 @@ class TOCEditor(QDialog): # {{{
|
|||||||
else:
|
else:
|
||||||
self.working = False
|
self.working = False
|
||||||
self.prefs['toc_editor_window_geom'] = bytearray(self.saveGeometry())
|
self.prefs['toc_editor_window_geom'] = bytearray(self.saveGeometry())
|
||||||
|
self.write_result(1)
|
||||||
super(TOCEditor, self).reject()
|
super(TOCEditor, self).reject()
|
||||||
|
|
||||||
|
def write_result(self, res):
|
||||||
|
if self.write_result_to:
|
||||||
|
with tempfile.NamedTemporaryFile(dir=os.path.dirname(self.write_result_to), delete=False) as f:
|
||||||
|
src = f.name
|
||||||
|
f.write(str(res).encode('utf-8'))
|
||||||
|
f.flush()
|
||||||
|
atomic_rename(src, self.write_result_to)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
t = Thread(target=self.explode)
|
t = Thread(target=self.explode)
|
||||||
t.daemon = True
|
t.daemon = True
|
||||||
@ -1140,15 +1151,15 @@ def main(path=None, title=None):
|
|||||||
# launched from within calibre, as both use calibre-parallel.exe
|
# launched from within calibre, as both use calibre-parallel.exe
|
||||||
set_app_uid(TOC_DIALOG_APP_UID)
|
set_app_uid(TOC_DIALOG_APP_UID)
|
||||||
|
|
||||||
with ExclusiveFile(path + '.lock') as wf:
|
with open(path + '.started', 'w'):
|
||||||
|
pass
|
||||||
override = 'calibre-gui' if islinux else None
|
override = 'calibre-gui' if islinux else None
|
||||||
app = Application([], override_program_name=override)
|
app = Application([], override_program_name=override)
|
||||||
d = TOCEditor(path, title=title)
|
d = TOCEditor(path, title=title, write_result_to=path + '.result')
|
||||||
d.start()
|
d.start()
|
||||||
ret = 1
|
ret = 1
|
||||||
if d.exec_() == QDialog.DialogCode.Accepted:
|
if d.exec_() == QDialog.DialogCode.Accepted:
|
||||||
ret = 0
|
ret = 0
|
||||||
wf.write('{}'.format(ret).encode('ascii'))
|
|
||||||
del d
|
del d
|
||||||
del app
|
del app
|
||||||
raise SystemExit(ret)
|
raise SystemExit(ret)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user