From c356e09dcf3367df9702506b64b9b5991f0c0721 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 20 Nov 2014 17:02:46 +0530 Subject: [PATCH] Fix regression in 2.10 that caused printing to stdout/stderr in FileType plugins to not work when running using calibre-debug -g in a windows console --- src/calibre/utils/ipc/pool.py | 50 ++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/src/calibre/utils/ipc/pool.py b/src/calibre/utils/ipc/pool.py index fa1ac16e73..1ff31031b3 100644 --- a/src/calibre/utils/ipc/pool.py +++ b/src/calibre/utils/ipc/pool.py @@ -12,7 +12,7 @@ from collections import namedtuple from Queue import Queue from calibre import detect_ncpus, as_unicode, prints -from calibre.constants import iswindows +from calibre.constants import iswindows, DEBUG from calibre.ptempfile import PersistentTemporaryFile from calibre.utils import join_with_timeout from calibre.utils.ipc import eintr_retry_call @@ -26,9 +26,28 @@ File = namedtuple('File', 'name') MAX_SIZE = 30 * 1024 * 1024 # max size of data to send over the connection (old versions of windows cannot handle arbitrary data lengths) worker_kwargs = {'stdout':None} -if iswindows and getattr(sys, 'gui_app', False): - from calibre.utils.ipc.launch import windows_null_file - worker_kwargs['stdout'] = worker_kwargs['stderr'] = windows_null_file +get_stdout_from_child = False + +if iswindows: + # The windows console cannot show output from child processes + # created with CREATE_NO_WINDOW, so the stdout/stderr file handles + # the child process inherits will be broken. Similarly, windows GUI apps + # have no usable stdout/stderr file handles. In both these cases, redirect + # the child's stdout/stderr to NUL. If we are running in calibre-debug -g, + # then redirect to PIPE and read from PIPE and print to our stdout. + # Note that when running via the "Restart in debug mode" action, stdout is + # not a console (its already redirected to a log file), so no redirection + # is required. + if getattr(sys, 'gui_app', False) or getattr(sys.stdout, 'isatty', lambda : False)(): + if DEBUG: + # We are running in a windows console with calibre-debug -g + import subprocess + get_stdout_from_child = True + worker_kwargs['stdout'] = subprocess.PIPE + worker_kwargs['stderr'] = subprocess.STDOUT + else: + from calibre.utils.ipc.launch import windows_null_file + worker_kwargs['stdout'] = worker_kwargs['stderr'] = windows_null_file class Failure(Exception): @@ -44,6 +63,10 @@ class Worker(object): self.process, self.conn = p, conn self.events = events self.name = name or '' + if get_stdout_from_child: + t = Thread(target=self.get_stdout, name='PoolWorkerGetOutput-'+self.name) + t.daemon = True + t.start() def __call__(self, job): eintr_retry_call(self.conn.send_bytes, cPickle.dumps(job, -1)) @@ -66,6 +89,22 @@ class Worker(object): def set_common_data(self, data): eintr_retry_call(self.conn.send_bytes, data) + def get_stdout(self): + import time + while self.process.poll() is None: + try: + raw = self.process.stdout.read(1) + if raw: + try: + sys.stdout.write(raw) + except EnvironmentError: + pass + else: + time.sleep(0.1) + except (EOFError, EnvironmentError): + break + + class Pool(Thread): daemon = True @@ -339,6 +378,9 @@ def run_main(func): with closing(Client(address, authkey=key)) as conn: raise SystemExit(func(conn)) +def test_write(): + print ('Printing to stdout in worker') + def test(): def get_results(pool, ignore_fail=False): ans = {}