2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
3
from __future__ import with_statement
6
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
7
__docformat__ = 'restructuredtext en'
9
import subprocess, os, sys, time
11
from calibre.constants import iswindows, isosx, isfrozen
12
from calibre.utils.config import prefs
13
from calibre.ptempfile import PersistentTemporaryFile
20
Platform independent object for launching child processes. All processes
21
have the environment variable :envvar:`CALIBRE_WORKER` set.
23
Useful attributes: ``is_alive``, ``returncode``
24
usefule methods: ``kill``
26
To launch child simply call the Worker object. By default, the child's
27
output is redirected to an on disk file, the path to which is returned by
32
def osx_interpreter(self):
33
exe = os.path.basename(sys.executable)
34
return exe if 'python' in exe else 'python'
37
def osx_contents_dir(self):
38
fd = os.path.realpath(getattr(sys, 'frameworks_dir'))
39
return os.path.dirname(fd)
44
return os.path.join(os.path.dirname(sys.executable),
45
'calibre-parallel.exe' if isfrozen else \
46
'Scripts\\calibre-parallel.exe')
48
if not isfrozen: return 'calibre-parallel'
49
contents = os.path.join(self.osx_contents_dir,
50
'console.app', 'Contents')
51
return os.path.join(contents, 'MacOS', self.osx_interpreter)
53
return os.path.join(getattr(sys, 'frozen_path'), 'calibre-parallel') \
54
if isfrozen else 'calibre-parallel'
57
def gui_executable(self):
58
if isfrozen and isosx:
59
return os.path.join(self.osx_contents_dir,
60
'MacOS', self.osx_interpreter)
62
return self.executable
66
env = dict(os.environ)
67
env['CALIBRE_WORKER'] = '1'
73
return hasattr(self, 'child') and self.child.poll() is None
77
if not hasattr(self, 'child'): return None
79
return self.child.returncode
85
return self.child.kill()
87
self.child.terminate()
89
while self.is_alive and time.time()-st < 2:
97
def __init__(self, env, gui=False):
100
if isosx and isfrozen:
101
contents = os.path.join(self.osx_contents_dir, 'console.app', 'Contents')
102
resources = os.path.join(contents, 'Resources')
103
fd = os.path.join(contents, 'Frameworks')
104
sp = os.path.join(resources, 'lib', 'python'+sys.version[:3], 'site-packages.zip')
105
self.osx_prefix = 'import sys; sys.frameworks_dir = "%s"; sys.frozen = "macosx_app"; '%fd
106
self.osx_prefix += 'sys.path.insert(0, %s); '%repr(sp)
108
self._env['PYTHONHOME'] = resources
109
self._env['MAGICK_HOME'] = os.path.join(fd, 'ImageMagick')
110
self._env['DYLD_LIBRARY_PATH'] = os.path.join(fd, 'ImageMagick', 'lib')
111
self._env['FONTCONFIG_PATH'] = \
112
os.path.join(os.path.realpath(resources), 'fonts')
113
self._env['QT_PLUGIN_PATH'] = \
114
os.path.join(self.osx_contents_dir, 'MacOS')
116
if isfrozen and not (iswindows or isosx):
117
self._env['LD_LIBRARY_PATH'] = getattr(sys, 'frozen_path') + ':'\
118
+ os.environ.get('LD_LIBRARY_PATH', '')
119
self._env.update(env)
121
def __call__(self, redirect_output=True, cwd=None, priority=None):
123
If redirect_output is True, output from the child is redirected
124
to a file on disk and this method returns the path to that file.
126
exe = self.gui_executable if self.gui else self.executable
128
env['ORIGWD'] = cwd or os.path.abspath(os.getcwd())
130
if isfrozen and not iswindows and not isosx:
131
_cwd = getattr(sys, 'frozen_path', None)
133
priority = prefs['worker_process_priority']
136
cmd += ['-c', self.osx_prefix + 'from calibre.utils.ipc.worker import main; main()']
143
'high' : win32process.HIGH_PRIORITY_CLASS,
144
'normal' : win32process.NORMAL_PRIORITY_CLASS,
145
'low' : win32process.IDLE_PRIORITY_CLASS}[priority]
146
args['creationflags'] = win32process.CREATE_NO_WINDOW|priority
149
self._file = PersistentTemporaryFile('_worker_redirect.log')
150
args['stdout'] = self._file._fd
151
args['stderr'] = subprocess.STDOUT
152
ret = self._file.name
154
self.child = subprocess.Popen(cmd, **args)