~ubuntu-branches/ubuntu/precise/enigmail/precise-security

« back to all changes in this revision

Viewing changes to build/pymake/pymake/process.py

  • Committer: Package Import Robot
  • Author(s): Chris Coulson
  • Date: 2012-11-12 16:36:01 UTC
  • mfrom: (0.12.15)
  • Revision ID: package-import@ubuntu.com-20121112163601-t8e8skdfi3ni9iqp
Tags: 2:1.4.6-0ubuntu0.12.04.1
* New upstream release v1.4.6
  - see LP: #1080212 for USN information
* Drop unneeded patches
  - remove debian/patches/correct-version-number.diff
  - remove debian/patches/dont_register_cids_multiple_times.diff
  - update debian/patches/series
* Support building in an objdir
  - update debian/rules

Show diffs side-by-side

added added

removed removed

Lines of Context:
4
4
"""
5
5
 
6
6
#TODO: ship pyprocessing?
7
 
import multiprocessing, multiprocessing.dummy
 
7
import multiprocessing
8
8
import subprocess, shlex, re, logging, sys, traceback, os, imp, glob
9
9
# XXXkhuey Work around http://bugs.python.org/issue1731717
10
10
subprocess._cleanup = lambda: None
15
15
_log = logging.getLogger('pymake.process')
16
16
 
17
17
_escapednewlines = re.compile(r'\\\n')
18
 
_blacklist = re.compile(r'[$><;[{~`|&()]')
 
18
# Characters that most likely indicate a shell script and that native commands
 
19
# should reject
 
20
_blacklist = re.compile(r'[$><;\[~`|&]' +
 
21
    r'|\${|(?:^|\s){(?:$|\s)')  # Blacklist ${foo} and { commands }
 
22
# Characters that probably indicate a shell script, but that native commands
 
23
# shouldn't just reject
 
24
_graylist = re.compile(r'[()]')
 
25
# Characters that indicate we need to glob
19
26
_needsglob = re.compile(r'[\*\?]')
20
 
def clinetoargv(cline):
 
27
 
 
28
def clinetoargv(cline, blacklist_gray):
21
29
    """
22
30
    If this command line can safely skip the shell, return an argv array.
23
31
    @returns argv, badchar
24
32
    """
25
 
 
26
33
    str = _escapednewlines.sub('', cline)
27
34
    m = _blacklist.search(str)
28
35
    if m is not None:
29
36
        return None, m.group(0)
 
37
    if blacklist_gray:
 
38
        m = _graylist.search(str)
 
39
        if m is not None:
 
40
            return None, m.group(0)
30
41
 
31
42
    args = shlex.split(str, comments=True)
32
43
 
64
75
    if msys and cline.startswith('/'):
65
76
        shellreason = "command starts with /"
66
77
    else:
67
 
        argv, badchar = clinetoargv(cline)
 
78
        argv, badchar = clinetoargv(cline, blacklist_gray=True)
68
79
        if argv is None:
69
80
            shellreason = "command contains shell-special character '%s'" % (badchar,)
70
81
        elif len(argv) and argv[0] in shellwords:
149
160
        self.shell = shell
150
161
        self.env = env
151
162
        self.cwd = cwd
 
163
        self.parentpid = os.getpid()
152
164
 
153
165
    def run(self):
 
166
        assert os.getpid() != self.parentpid
 
167
        # subprocess.Popen doesn't use the PATH set in the env argument for
 
168
        # finding the executable on some platforms (but strangely it does on
 
169
        # others!), so set os.environ['PATH'] explicitly. This is parallel-
 
170
        # safe because pymake uses separate processes for parallelism, and
 
171
        # each process is serial. See http://bugs.python.org/issue8557 for a
 
172
        # general overview of "subprocess PATH semantics and portability".
 
173
        oldpath = os.environ['PATH']
154
174
        try:
 
175
            if self.env is not None and self.env.has_key('PATH'):
 
176
                os.environ['PATH'] = self.env['PATH']
155
177
            p = subprocess.Popen(self.argv, executable=self.executable, shell=self.shell, env=self.env, cwd=self.cwd)
156
178
            return p.wait()
157
179
        except OSError, e:
158
180
            print >>sys.stderr, e
159
181
            return -127
 
182
        finally:
 
183
            os.environ['PATH'] = oldpath
160
184
 
161
185
class PythonException(Exception):
162
186
    def __init__(self, message, exitcode):
194
218
        self.env = env
195
219
        self.cwd = cwd
196
220
        self.pycommandpath = pycommandpath or []
 
221
        self.parentpid = os.getpid()
197
222
 
198
223
    def run(self):
199
 
        oldenv = os.environ
 
224
        assert os.getpid() != self.parentpid
 
225
        # os.environ is a magic dictionary. Setting it to something else
 
226
        # doesn't affect the environment of subprocesses, so use clear/update
 
227
        oldenv = dict(os.environ)
200
228
        try:
201
229
            os.chdir(self.cwd)
202
 
            os.environ = self.env
 
230
            os.environ.clear()
 
231
            os.environ.update(self.env)
203
232
            if self.module not in sys.modules:
204
233
                load_module_recursive(self.module,
205
234
                                      sys.path + self.pycommandpath)
208
237
                return -127                
209
238
            m = sys.modules[self.module]
210
239
            if self.method not in m.__dict__:
211
 
                print >>sys.stderr, "No method named '%s' in module %s" % (method, module)
 
240
                print >>sys.stderr, "No method named '%s' in module %s" % (self.method, self.module)
212
241
                return -127
213
 
            m.__dict__[self.method](self.argv)
 
242
            rv = m.__dict__[self.method](self.argv)
 
243
            if rv != 0 and rv is not None:
 
244
                print >>sys.stderr, (
 
245
                    "Native command '%s %s' returned value '%s'" %
 
246
                    (self.module, self.method, rv))
 
247
                return (rv if isinstance(rv, int) else 1)
 
248
 
214
249
        except PythonException, e:
215
250
            print >>sys.stderr, e
216
251
            return e.exitcode
217
252
        except:
218
253
            e = sys.exc_info()[1]
219
 
            if isinstance(e, SystemExit) and (e.code == 0 or e.code == '0'):
 
254
            if isinstance(e, SystemExit) and (e.code == 0 or e.code is None):
220
255
                pass # sys.exit(0) is not a failure
221
256
            else:
222
257
                print >>sys.stderr, e
223
258
                print >>sys.stderr, traceback.print_exc()
224
 
                return -127
 
259
                return (e.code if isinstance(e.code, int) else 1)
225
260
        finally:
226
 
            os.environ = oldenv
 
261
            os.environ.clear()
 
262
            os.environ.update(oldenv)
227
263
        return 0
228
264
 
229
265
def job_runner(job):
245
281
        self.exit = False
246
282
 
247
283
        self.processpool = multiprocessing.Pool(processes=jcount)
248
 
        self.threadpool = multiprocessing.dummy.Pool(processes=jcount)
249
284
        self.pending = [] # list of (cb, args, kwargs)
250
285
        self.running = [] # list of (subprocess, cb)
251
286
 
254
289
    def finish(self):
255
290
        assert len(self.pending) == 0 and len(self.running) == 0, "pending: %i running: %i" % (len(self.pending), len(self.running))
256
291
        self.processpool.close()
257
 
        self.threadpool.close()
258
292
        self.processpool.join()
259
 
        self.threadpool.join()
260
293
        self._allcontexts.remove(self)
261
294
 
262
295
    def run(self):
284
317
        """
285
318
 
286
319
        job = PopenJob(argv, executable=executable, shell=shell, env=env, cwd=cwd)
287
 
        self.defer(self._docall_generic, self.threadpool, job, cb, echo, justprint)
 
320
        self.defer(self._docall_generic, self.processpool, job, cb, echo, justprint)
288
321
 
289
322
    def call_native(self, module, method, argv, env, cwd, cb,
290
323
                    echo, justprint=False, pycommandpath=None):