From b27e06120c689bcd5538d8fc6d9a3eb23f05c79f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 1 May 2012 12:51:29 +0530 Subject: [PATCH] Run explode/rebuild of MOBI in worker process to ensure no mem leaks --- src/calibre/ebooks/mobi/tweak.py | 35 +++++++++++++++++++------------- src/calibre/ebooks/tweak.py | 13 +++++++++++- 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/src/calibre/ebooks/mobi/tweak.py b/src/calibre/ebooks/mobi/tweak.py index 4d21e71679..248ed97261 100644 --- a/src/calibre/ebooks/mobi/tweak.py +++ b/src/calibre/ebooks/mobi/tweak.py @@ -19,10 +19,21 @@ from calibre.ebooks.mobi.reader.mobi8 import Mobi8Reader from calibre.ebooks.conversion.plumber import Plumber, create_oebbook from calibre.customize.ui import (plugin_for_input_format, plugin_for_output_format) +from calibre.utils.ipc.simple_worker import fork_job class BadFormat(ValueError): pass +def do_explode(path, dest): + with open(path, 'rb') as stream: + mr = MobiReader(stream, default_log, None, None) + + with CurrentDir(dest): + mr = Mobi8Reader(mr, default_log) + opf = os.path.abspath(mr()) + + return opf + def explode(path, dest, question=lambda x:True): with open(path, 'rb') as stream: raw = stream.read(3) @@ -50,21 +61,10 @@ def explode(path, dest, question=lambda x:True): 'sure?')): return None + return fork_job('calibre.ebooks.mobi.tweak', 'do_explode', args=(path, + dest), no_output=True)['result'] - stream.seek(0) - mr = MobiReader(stream, default_log, None, None) - - with CurrentDir(dest): - mr = Mobi8Reader(mr, default_log) - opf = os.path.abspath(mr()) - - return opf - -def rebuild(src_dir, dest_path): - opf = glob.glob(os.path.join(src_dir, '*.opf')) - if not opf: - raise ValueError('No OPF file found in %s'%src_dir) - opf = opf[0] +def do_rebuild(opf, dest_path): plumber = Plumber(opf, dest_path, default_log) plumber.setup_options() inp = plugin_for_input_format('azw3') @@ -74,4 +74,11 @@ def rebuild(src_dir, dest_path): oeb = create_oebbook(default_log, opf, plumber.opts) outp.convert(oeb, dest_path, inp, plumber.opts, default_log) +def rebuild(src_dir, dest_path): + opf = glob.glob(os.path.join(src_dir, '*.opf')) + if not opf: + raise ValueError('No OPF file found in %s'%src_dir) + opf = opf[0] + fork_job('calibre.ebooks.mobi.tweak', 'do_rebuild', args=(opf, dest_path), + no_output=True) diff --git a/src/calibre/ebooks/tweak.py b/src/calibre/ebooks/tweak.py index ba3cf65a85..72e4c0a56c 100644 --- a/src/calibre/ebooks/tweak.py +++ b/src/calibre/ebooks/tweak.py @@ -14,6 +14,7 @@ from calibre.constants import iswindows, __appname__ from calibre.ptempfile import TemporaryDirectory from calibre.libunzip import extract as zipextract from calibre.utils.zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED +from calibre.utils.ipc.simple_worker import WorkerError class Error(ValueError): pass @@ -95,6 +96,10 @@ def tweak(ebook_file): os.path.basename(ebook_file).rpartition('.')[0]) as tdir: try: opf = exploder(ebook_file, tdir, question=ask_cli_question) + except WorkerError as e: + prints('Failed to unpack', ebook_file) + prints(e.orig_tb) + raise SystemExit(1) except Error as e: prints(as_unicode(e), file=sys.stderr) raise SystemExit(1) @@ -121,6 +126,12 @@ def tweak(ebook_file): proceed = True if proceed: - rebuilder(tdir, ebook_file) + prints('Rebuilding', ebook_file, 'please wait ...') + try: + rebuilder(tdir, ebook_file) + except WorkerError as e: + prints('Failed to rebuild', ebook_file) + prints(e.orig_tb) + raise SystemExit(1) prints(ebook_file, 'successfully tweaked')