From 7fa3db93af033e9c41cdfd47663309622da12d7f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 19 Oct 2015 17:53:44 +0530 Subject: [PATCH] When auto-reloading server, handle RS compilation failures better --- src/calibre/srv/auto_reload.py | 30 ++++++++++++++++++----------- src/calibre/utils/rapydscript.py | 33 ++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/calibre/srv/auto_reload.py b/src/calibre/srv/auto_reload.py index 1ed4263d25..0d029b84c8 100644 --- a/src/calibre/srv/auto_reload.py +++ b/src/calibre/srv/auto_reload.py @@ -212,18 +212,26 @@ class Worker(object): self.p = None def restart(self): - from calibre.utils.rapydscript import compile_srv + from calibre.utils.rapydscript import compile_srv, CompileFailure self.clean_kill() - try: - compile_srv() - except EnvironmentError as e: - # Happens if the editor deletes and replaces a file being edited - if e.errno != errno.ENOENT or not getattr(e, 'filename', False): - raise - st = time.time() - while not os.path.exists(e.filename) and time.time() - st < 3: - time.sleep(0.01) - compile_srv() + while True: + try: + compile_srv() + except EnvironmentError as e: + # Happens if the editor deletes and replaces a file being edited + if e.errno != errno.ENOENT or not getattr(e, 'filename', False): + raise + st = time.time() + while not os.path.exists(e.filename) and time.time() - st < 3: + time.sleep(0.01) + compile_srv() + except CompileFailure as e: + print(e.message, file=sys.stderr) + print('Retrying in two seconds') + time.sleep(2) + continue + break + self.p = subprocess.Popen(self.cmd, creationflags=getattr(subprocess, 'CREATE_NEW_PROCESS_GROUP', 0)) def auto_reload(log, dirs=frozenset(), cmd=None, add_default_dirs=True): diff --git a/src/calibre/utils/rapydscript.py b/src/calibre/utils/rapydscript.py index d426e65c71..31a7eafa79 100644 --- a/src/calibre/utils/rapydscript.py +++ b/src/calibre/utils/rapydscript.py @@ -58,11 +58,8 @@ def compiler(): c.eval(buf.getvalue(), fname=COMPILER_PATH, noreturn=True) return c -class PYJError(Exception): - - def __init__(self, errors): - Exception.__init__(self, '') - self.errors = errors +class CompileFailure(ValueError): + pass def compile_pyj(data, filename='', beautify=True, private_scope=True, libdir=None, omit_baselib=False): if isinstance(data, bytes): @@ -77,7 +74,25 @@ def compile_pyj(data, filename='', beautify=True, private_scope=True, lib 'filename': filename, } c.g.rs_source_code = data - return c.eval('exports["compile"](rs_source_code, %s, current_options)' % json.dumps(filename)) + ok, result = c.eval( + ''' + ans = [null, null]; + try { + ans = [true, exports["compile"](rs_source_code, %s, current_options)]; + } catch(e) { + ans = [false, e] + } + ans; + ''' % json.dumps(filename)) + if ok: + return result + result = to_python(result) + if 'message' in result: + msg = result['message'] + if 'filename' in result and 'line' in result: + msg = '%s:%s:%s' % (result['filename'], result['line'], msg) + raise CompileFailure(msg) + raise CompileFailure(repr(result)) def compile_srv(): d = os.path.dirname @@ -295,12 +310,10 @@ def main(args=sys.argv): enc = getattr(sys.stdin, 'encoding', 'utf-8') or 'utf-8' data = compile_pyj(sys.stdin.read().decode(enc), libdir=libdir, private_scope=not args.no_private_scope, omit_baselib=args.omit_baselib) print(data.encode(enc)) - except PYJError as e: - for e in e.errors: - print(format_error(e), file=sys.stderr) - raise SystemExit(1) except JSError as e: raise SystemExit(e.message) + except CompileFailure as e: + raise SystemExit(e.message) def entry(): main(sys.argv[1:])