~ubuntu-branches/ubuntu/karmic/calibre/karmic

« back to all changes in this revision

Viewing changes to src/calibre/utils/ipc/launch.py

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-07-30 12:49:41 UTC
  • mfrom: (1.3.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20090730124941-qjdsmri25zt8zocn
Tags: 0.6.3+dfsg-0ubuntu1
* New upstream release. Please see http://calibre.kovidgoyal.net/new_in_6/
  for the list of new features and changes.
* remove_postinstall.patch: Update for new version.
* build_debug.patch: Does not apply any more, disable for now. Might not be
  necessary any more.
* debian/copyright: Fix reference to versionless GPL.
* debian/rules: Drop obsolete dh_desktop call.
* debian/rules: Add workaround for weird Python 2.6 setuptools behaviour of
  putting compiled .so files into src/calibre/plugins/calibre/plugins
  instead of src/calibre/plugins.
* debian/rules: Drop hal fdi moving, new upstream version does not use hal
  any more. Drop hal dependency, too.
* debian/rules: Install udev rules into /lib/udev/rules.d.
* Add debian/calibre.preinst: Remove unmodified
  /etc/udev/rules.d/95-calibre.rules on upgrade.
* debian/control: Bump Python dependencies to 2.6, since upstream needs
  it now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
 
3
from __future__ import with_statement
 
4
 
 
5
__license__   = 'GPL v3'
 
6
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
 
7
__docformat__ = 'restructuredtext en'
 
8
 
 
9
import subprocess, os, sys, time
 
10
 
 
11
from calibre.constants import iswindows, isosx, isfrozen
 
12
from calibre.utils.config import prefs
 
13
from calibre.ptempfile import PersistentTemporaryFile
 
14
 
 
15
if iswindows:
 
16
    import win32process
 
17
 
 
18
class Worker(object):
 
19
    '''
 
20
    Platform independent object for launching child processes. All processes
 
21
    have the environment variable :envvar:`CALIBRE_WORKER` set.
 
22
 
 
23
    Useful attributes: ``is_alive``, ``returncode``
 
24
    usefule methods: ``kill``
 
25
 
 
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
 
28
    the call.
 
29
    '''
 
30
 
 
31
    @property
 
32
    def osx_interpreter(self):
 
33
        exe = os.path.basename(sys.executable)
 
34
        return exe if 'python' in exe else 'python'
 
35
 
 
36
    @property
 
37
    def osx_contents_dir(self):
 
38
        fd = os.path.realpath(getattr(sys, 'frameworks_dir'))
 
39
        return os.path.dirname(fd)
 
40
 
 
41
    @property
 
42
    def executable(self):
 
43
        if iswindows:
 
44
            return os.path.join(os.path.dirname(sys.executable),
 
45
                   'calibre-parallel.exe' if isfrozen else \
 
46
                           'Scripts\\calibre-parallel.exe')
 
47
        if isosx:
 
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)
 
52
 
 
53
        return os.path.join(getattr(sys, 'frozen_path'), 'calibre-parallel') \
 
54
                            if isfrozen else 'calibre-parallel'
 
55
 
 
56
    @property
 
57
    def gui_executable(self):
 
58
        if isfrozen and isosx:
 
59
            return os.path.join(self.osx_contents_dir,
 
60
                    'MacOS', self.osx_interpreter)
 
61
 
 
62
        return self.executable
 
63
 
 
64
    @property
 
65
    def env(self):
 
66
        env = dict(os.environ)
 
67
        env['CALIBRE_WORKER'] = '1'
 
68
        env.update(self._env)
 
69
        return env
 
70
 
 
71
    @property
 
72
    def is_alive(self):
 
73
        return hasattr(self, 'child') and self.child.poll() is None
 
74
 
 
75
    @property
 
76
    def returncode(self):
 
77
        if not hasattr(self, 'child'): return None
 
78
        self.child.poll()
 
79
        return self.child.returncode
 
80
 
 
81
    def kill(self):
 
82
        try:
 
83
            if self.is_alive:
 
84
                if iswindows:
 
85
                    return self.child.kill()
 
86
                try:
 
87
                    self.child.terminate()
 
88
                    st = time.time()
 
89
                    while self.is_alive and time.time()-st < 2:
 
90
                        time.sleep(0.2)
 
91
                finally:
 
92
                    if self.is_alive:
 
93
                        self.child.kill()
 
94
        except:
 
95
            pass
 
96
 
 
97
    def __init__(self, env, gui=False):
 
98
        self._env = {}
 
99
        self.gui = gui
 
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)
 
107
 
 
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')
 
115
 
 
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)
 
120
 
 
121
    def __call__(self, redirect_output=True, cwd=None, priority=None):
 
122
        '''
 
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.
 
125
        '''
 
126
        exe = self.gui_executable if self.gui else self.executable
 
127
        env = self.env
 
128
        env['ORIGWD'] = cwd or os.path.abspath(os.getcwd())
 
129
        _cwd = cwd
 
130
        if isfrozen and not iswindows and not isosx:
 
131
            _cwd = getattr(sys, 'frozen_path', None)
 
132
        if priority is None:
 
133
            priority = prefs['worker_process_priority']
 
134
        cmd = [exe]
 
135
        if isosx:
 
136
            cmd += ['-c', self.osx_prefix + 'from calibre.utils.ipc.worker import main; main()']
 
137
        args = {
 
138
                'env' : env,
 
139
                'cwd' : _cwd,
 
140
                }
 
141
        if iswindows:
 
142
            priority = {
 
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
 
147
        ret = None
 
148
        if redirect_output:
 
149
            self._file = PersistentTemporaryFile('_worker_redirect.log')
 
150
            args['stdout'] = self._file._fd
 
151
            args['stderr'] = subprocess.STDOUT
 
152
            ret = self._file.name
 
153
 
 
154
        self.child = subprocess.Popen(cmd, **args)
 
155
 
 
156
        self.log_path = ret
 
157
        return ret
 
158
 
 
159
 
 
160