Gentoo Archives: gentoo-commits

From: "Zac Medico (zmedico)" <zmedico@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r15515 - in main/trunk/pym: _emerge portage/package/ebuild portage/tests/ebuild portage/util
Date: Tue, 02 Mar 2010 09:47:40
Message-Id: E1NmOhN-0005bo-Bh@stork.gentoo.org
1 Author: zmedico
2 Date: 2010-03-02 09:47:26 +0000 (Tue, 02 Mar 2010)
3 New Revision: 15515
4
5 Added:
6 main/trunk/pym/portage/util/_pty.py
7 Removed:
8 main/trunk/pym/portage/package/ebuild/_pty.py
9 Modified:
10 main/trunk/pym/_emerge/AbstractEbuildProcess.py
11 main/trunk/pym/_emerge/EbuildFetcher.py
12 main/trunk/pym/portage/package/ebuild/doebuild.py
13 main/trunk/pym/portage/tests/ebuild/test_pty_eof.py
14 Log:
15 Move _pty module to portage.util._pty.
16
17
18 Modified: main/trunk/pym/_emerge/AbstractEbuildProcess.py
19 ===================================================================
20 --- main/trunk/pym/_emerge/AbstractEbuildProcess.py 2010-03-02 09:42:20 UTC (rev 15514)
21 +++ main/trunk/pym/_emerge/AbstractEbuildProcess.py 2010-03-02 09:47:26 UTC (rev 15515)
22 @@ -5,7 +5,7 @@
23 from _emerge.SpawnProcess import SpawnProcess
24 import portage
25 from portage import os
26 -from portage.package.ebuild._pty import _create_pty_or_pipe
27 +from portage.util._pty import _create_pty_or_pipe
28
29 class AbstractEbuildProcess(SpawnProcess):
30
31
32 Modified: main/trunk/pym/_emerge/EbuildFetcher.py
33 ===================================================================
34 --- main/trunk/pym/_emerge/EbuildFetcher.py 2010-03-02 09:42:20 UTC (rev 15514)
35 +++ main/trunk/pym/_emerge/EbuildFetcher.py 2010-03-02 09:47:26 UTC (rev 15515)
36 @@ -11,7 +11,7 @@
37 from portage import _unicode_encode
38 import codecs
39 from portage.elog.messages import eerror
40 -from portage.package.ebuild._pty import _create_pty_or_pipe
41 +from portage.util._pty import _create_pty_or_pipe
42
43 class EbuildFetcher(SpawnProcess):
44
45
46 Deleted: main/trunk/pym/portage/package/ebuild/_pty.py
47 ===================================================================
48 --- main/trunk/pym/portage/package/ebuild/_pty.py 2010-03-02 09:42:20 UTC (rev 15514)
49 +++ main/trunk/pym/portage/package/ebuild/_pty.py 2010-03-02 09:47:26 UTC (rev 15515)
50 @@ -1,205 +0,0 @@
51 -# Copyright 2010 Gentoo Foundation
52 -# Distributed under the terms of the GNU General Public License v2
53 -# $Id$
54 -
55 -import array
56 -import fcntl
57 -import platform
58 -import pty
59 -import select
60 -import sys
61 -import termios
62 -
63 -from portage import os, _unicode_decode, _unicode_encode
64 -from portage.output import get_term_size, set_term_size
65 -from portage.process import spawn_bash
66 -from portage.util import writemsg
67 -
68 -def _can_test_pty_eof():
69 - """
70 - The _test_pty_eof() function seems to hang on most
71 - kernels other than Linux.
72 - This was reported for the following kernels which used to work fine
73 - without this EOF test: Darwin, AIX, FreeBSD. They seem to hang on
74 - the slave_file.close() call. Note that Python's implementation of
75 - openpty on Solaris already caused random hangs without this EOF test
76 - and hence is globally disabled.
77 - @rtype: bool
78 - @returns: True if _test_pty_eof() won't hang, False otherwise.
79 - """
80 - return platform.system() in ("Linux",)
81 -
82 -def _test_pty_eof():
83 - """
84 - Returns True if this issues is fixed for the currently
85 - running version of python: http://bugs.python.org/issue5380
86 - Raises an EnvironmentError from openpty() if it fails.
87 - """
88 -
89 - use_fork = False
90 -
91 - test_string = 2 * "blah blah blah\n"
92 - test_string = _unicode_decode(test_string,
93 - encoding='utf_8', errors='strict')
94 -
95 - # may raise EnvironmentError
96 - master_fd, slave_fd = pty.openpty()
97 -
98 - # Non-blocking mode is required for Darwin kernel.
99 - fcntl.fcntl(master_fd, fcntl.F_SETFL,
100 - fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
101 -
102 - # Disable post-processing of output since otherwise weird
103 - # things like \n -> \r\n transformations may occur.
104 - mode = termios.tcgetattr(slave_fd)
105 - mode[1] &= ~termios.OPOST
106 - termios.tcsetattr(slave_fd, termios.TCSANOW, mode)
107 -
108 - # Simulate a subprocess writing some data to the
109 - # slave end of the pipe, and then exiting.
110 - pid = None
111 - if use_fork:
112 - pids = spawn_bash(_unicode_encode("echo -n '%s'" % test_string,
113 - encoding='utf_8', errors='strict'), env=os.environ,
114 - fd_pipes={0:sys.stdin.fileno(), 1:slave_fd, 2:slave_fd},
115 - returnpid=True)
116 - if isinstance(pids, int):
117 - os.close(master_fd)
118 - os.close(slave_fd)
119 - raise EnvironmentError('spawn failed')
120 - pid = pids[0]
121 - else:
122 - os.write(slave_fd, _unicode_encode(test_string,
123 - encoding='utf_8', errors='strict'))
124 - os.close(slave_fd)
125 -
126 - # If using a fork, we must wait for the child here,
127 - # in order to avoid a race condition that would
128 - # lead to inconsistent results.
129 - if pid is not None:
130 - os.waitpid(pid, 0)
131 -
132 - master_file = os.fdopen(master_fd, 'rb')
133 - eof = False
134 - data = []
135 - iwtd = [master_file]
136 - owtd = []
137 - ewtd = []
138 -
139 - while not eof:
140 -
141 - events = select.select(iwtd, owtd, ewtd)
142 - if not events[0]:
143 - eof = True
144 - break
145 -
146 - buf = array.array('B')
147 - try:
148 - buf.fromfile(master_file, 1024)
149 - except EOFError:
150 - eof = True
151 - except IOError:
152 - # This is where data loss occurs.
153 - eof = True
154 -
155 - if not buf:
156 - eof = True
157 - else:
158 - data.append(_unicode_decode(buf.tostring(),
159 - encoding='utf_8', errors='strict'))
160 -
161 - master_file.close()
162 -
163 - return test_string == ''.join(data)
164 -
165 -# If _test_pty_eof() can't be used for runtime detection of
166 -# http://bugs.python.org/issue5380, openpty can't safely be used
167 -# unless we can guarantee that the current version of python has
168 -# been fixed (affects all current versions of python3). When
169 -# this issue is fixed in python3, we can add another sys.hexversion
170 -# conditional to enable openpty support in the fixed versions.
171 -if sys.hexversion >= 0x3000000 and not _can_test_pty_eof():
172 - _disable_openpty = True
173 -else:
174 - # Disable the use of openpty on Solaris as it seems Python's openpty
175 - # implementation doesn't play nice on Solaris with Portage's
176 - # behaviour causing hangs/deadlocks.
177 - # Additional note for the future: on Interix, pipes do NOT work, so
178 - # _disable_openpty on Interix must *never* be True
179 - _disable_openpty = platform.system() in ("SunOS",)
180 -_tested_pty = False
181 -
182 -if not _can_test_pty_eof():
183 - # Skip _test_pty_eof() on systems where it hangs.
184 - _tested_pty = True
185 -
186 -_fbsd_test_pty = platform.system() == 'FreeBSD'
187 -
188 -def _create_pty_or_pipe(copy_term_size=None):
189 - """
190 - Try to create a pty and if then fails then create a normal
191 - pipe instead.
192 -
193 - @param copy_term_size: If a tty file descriptor is given
194 - then the term size will be copied to the pty.
195 - @type copy_term_size: int
196 - @rtype: tuple
197 - @returns: A tuple of (is_pty, master_fd, slave_fd) where
198 - is_pty is True if a pty was successfully allocated, and
199 - False if a normal pipe was allocated.
200 - """
201 -
202 - got_pty = False
203 -
204 - global _disable_openpty, _fbsd_test_pty, _tested_pty
205 - if not (_tested_pty or _disable_openpty):
206 - try:
207 - if not _test_pty_eof():
208 - _disable_openpty = True
209 - except EnvironmentError as e:
210 - _disable_openpty = True
211 - writemsg("openpty failed: '%s'\n" % str(e),
212 - noiselevel=-1)
213 - del e
214 - _tested_pty = True
215 -
216 - if _fbsd_test_pty and not _disable_openpty:
217 - # Test for python openpty breakage after freebsd7 to freebsd8
218 - # upgrade, which results in a 'Function not implemented' error
219 - # and the process being killed.
220 - pid = os.fork()
221 - if pid == 0:
222 - pty.openpty()
223 - os._exit(os.EX_OK)
224 - pid, status = os.waitpid(pid, 0)
225 - if (status & 0xff) == 140:
226 - _disable_openpty = True
227 - _fbsd_test_pty = False
228 -
229 - if _disable_openpty:
230 - master_fd, slave_fd = os.pipe()
231 - else:
232 - try:
233 - master_fd, slave_fd = pty.openpty()
234 - got_pty = True
235 - except EnvironmentError as e:
236 - _disable_openpty = True
237 - writemsg("openpty failed: '%s'\n" % str(e),
238 - noiselevel=-1)
239 - del e
240 - master_fd, slave_fd = os.pipe()
241 -
242 - if got_pty:
243 - # Disable post-processing of output since otherwise weird
244 - # things like \n -> \r\n transformations may occur.
245 - mode = termios.tcgetattr(slave_fd)
246 - mode[1] &= ~termios.OPOST
247 - termios.tcsetattr(slave_fd, termios.TCSANOW, mode)
248 -
249 - if got_pty and \
250 - copy_term_size is not None and \
251 - os.isatty(copy_term_size):
252 - rows, columns = get_term_size()
253 - set_term_size(rows, columns, slave_fd)
254 -
255 - return (got_pty, master_fd, slave_fd)
256
257 Modified: main/trunk/pym/portage/package/ebuild/doebuild.py
258 ===================================================================
259 --- main/trunk/pym/portage/package/ebuild/doebuild.py 2010-03-02 09:42:20 UTC (rev 15514)
260 +++ main/trunk/pym/portage/package/ebuild/doebuild.py 2010-03-02 09:47:26 UTC (rev 15515)
261 @@ -49,10 +49,10 @@
262 from portage.output import style_to_ansi_code
263 from portage.package.ebuild.fetch import fetch
264 from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
265 -from portage.package.ebuild._pty import _create_pty_or_pipe
266 from portage.util import apply_recursive_permissions, \
267 apply_secpass_permissions, noiselimit, normalize_path, \
268 writemsg, writemsg_stdout, write_atomic
269 +from portage.util._pty import _create_pty_or_pipe
270 from portage.versions import _pkgsplit
271
272 def doebuild_environment(myebuild, mydo, myroot, mysettings,
273
274 Modified: main/trunk/pym/portage/tests/ebuild/test_pty_eof.py
275 ===================================================================
276 --- main/trunk/pym/portage/tests/ebuild/test_pty_eof.py 2010-03-02 09:42:20 UTC (rev 15514)
277 +++ main/trunk/pym/portage/tests/ebuild/test_pty_eof.py 2010-03-02 09:47:26 UTC (rev 15515)
278 @@ -4,7 +4,7 @@
279
280 import portage
281 from portage.tests import TestCase
282 -from portage.package.ebuild._pty import _can_test_pty_eof, _test_pty_eof
283 +from portage.util._pty import _can_test_pty_eof, _test_pty_eof
284
285 class PtyEofTestCase(TestCase):
286
287
288 Copied: main/trunk/pym/portage/util/_pty.py (from rev 15514, main/trunk/pym/portage/package/ebuild/_pty.py)
289 ===================================================================
290 --- main/trunk/pym/portage/util/_pty.py (rev 0)
291 +++ main/trunk/pym/portage/util/_pty.py 2010-03-02 09:47:26 UTC (rev 15515)
292 @@ -0,0 +1,205 @@
293 +# Copyright 2010 Gentoo Foundation
294 +# Distributed under the terms of the GNU General Public License v2
295 +# $Id$
296 +
297 +import array
298 +import fcntl
299 +import platform
300 +import pty
301 +import select
302 +import sys
303 +import termios
304 +
305 +from portage import os, _unicode_decode, _unicode_encode
306 +from portage.output import get_term_size, set_term_size
307 +from portage.process import spawn_bash
308 +from portage.util import writemsg
309 +
310 +def _can_test_pty_eof():
311 + """
312 + The _test_pty_eof() function seems to hang on most
313 + kernels other than Linux.
314 + This was reported for the following kernels which used to work fine
315 + without this EOF test: Darwin, AIX, FreeBSD. They seem to hang on
316 + the slave_file.close() call. Note that Python's implementation of
317 + openpty on Solaris already caused random hangs without this EOF test
318 + and hence is globally disabled.
319 + @rtype: bool
320 + @returns: True if _test_pty_eof() won't hang, False otherwise.
321 + """
322 + return platform.system() in ("Linux",)
323 +
324 +def _test_pty_eof():
325 + """
326 + Returns True if this issues is fixed for the currently
327 + running version of python: http://bugs.python.org/issue5380
328 + Raises an EnvironmentError from openpty() if it fails.
329 + """
330 +
331 + use_fork = False
332 +
333 + test_string = 2 * "blah blah blah\n"
334 + test_string = _unicode_decode(test_string,
335 + encoding='utf_8', errors='strict')
336 +
337 + # may raise EnvironmentError
338 + master_fd, slave_fd = pty.openpty()
339 +
340 + # Non-blocking mode is required for Darwin kernel.
341 + fcntl.fcntl(master_fd, fcntl.F_SETFL,
342 + fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
343 +
344 + # Disable post-processing of output since otherwise weird
345 + # things like \n -> \r\n transformations may occur.
346 + mode = termios.tcgetattr(slave_fd)
347 + mode[1] &= ~termios.OPOST
348 + termios.tcsetattr(slave_fd, termios.TCSANOW, mode)
349 +
350 + # Simulate a subprocess writing some data to the
351 + # slave end of the pipe, and then exiting.
352 + pid = None
353 + if use_fork:
354 + pids = spawn_bash(_unicode_encode("echo -n '%s'" % test_string,
355 + encoding='utf_8', errors='strict'), env=os.environ,
356 + fd_pipes={0:sys.stdin.fileno(), 1:slave_fd, 2:slave_fd},
357 + returnpid=True)
358 + if isinstance(pids, int):
359 + os.close(master_fd)
360 + os.close(slave_fd)
361 + raise EnvironmentError('spawn failed')
362 + pid = pids[0]
363 + else:
364 + os.write(slave_fd, _unicode_encode(test_string,
365 + encoding='utf_8', errors='strict'))
366 + os.close(slave_fd)
367 +
368 + # If using a fork, we must wait for the child here,
369 + # in order to avoid a race condition that would
370 + # lead to inconsistent results.
371 + if pid is not None:
372 + os.waitpid(pid, 0)
373 +
374 + master_file = os.fdopen(master_fd, 'rb')
375 + eof = False
376 + data = []
377 + iwtd = [master_file]
378 + owtd = []
379 + ewtd = []
380 +
381 + while not eof:
382 +
383 + events = select.select(iwtd, owtd, ewtd)
384 + if not events[0]:
385 + eof = True
386 + break
387 +
388 + buf = array.array('B')
389 + try:
390 + buf.fromfile(master_file, 1024)
391 + except EOFError:
392 + eof = True
393 + except IOError:
394 + # This is where data loss occurs.
395 + eof = True
396 +
397 + if not buf:
398 + eof = True
399 + else:
400 + data.append(_unicode_decode(buf.tostring(),
401 + encoding='utf_8', errors='strict'))
402 +
403 + master_file.close()
404 +
405 + return test_string == ''.join(data)
406 +
407 +# If _test_pty_eof() can't be used for runtime detection of
408 +# http://bugs.python.org/issue5380, openpty can't safely be used
409 +# unless we can guarantee that the current version of python has
410 +# been fixed (affects all current versions of python3). When
411 +# this issue is fixed in python3, we can add another sys.hexversion
412 +# conditional to enable openpty support in the fixed versions.
413 +if sys.hexversion >= 0x3000000 and not _can_test_pty_eof():
414 + _disable_openpty = True
415 +else:
416 + # Disable the use of openpty on Solaris as it seems Python's openpty
417 + # implementation doesn't play nice on Solaris with Portage's
418 + # behaviour causing hangs/deadlocks.
419 + # Additional note for the future: on Interix, pipes do NOT work, so
420 + # _disable_openpty on Interix must *never* be True
421 + _disable_openpty = platform.system() in ("SunOS",)
422 +_tested_pty = False
423 +
424 +if not _can_test_pty_eof():
425 + # Skip _test_pty_eof() on systems where it hangs.
426 + _tested_pty = True
427 +
428 +_fbsd_test_pty = platform.system() == 'FreeBSD'
429 +
430 +def _create_pty_or_pipe(copy_term_size=None):
431 + """
432 + Try to create a pty and if then fails then create a normal
433 + pipe instead.
434 +
435 + @param copy_term_size: If a tty file descriptor is given
436 + then the term size will be copied to the pty.
437 + @type copy_term_size: int
438 + @rtype: tuple
439 + @returns: A tuple of (is_pty, master_fd, slave_fd) where
440 + is_pty is True if a pty was successfully allocated, and
441 + False if a normal pipe was allocated.
442 + """
443 +
444 + got_pty = False
445 +
446 + global _disable_openpty, _fbsd_test_pty, _tested_pty
447 + if not (_tested_pty or _disable_openpty):
448 + try:
449 + if not _test_pty_eof():
450 + _disable_openpty = True
451 + except EnvironmentError as e:
452 + _disable_openpty = True
453 + writemsg("openpty failed: '%s'\n" % str(e),
454 + noiselevel=-1)
455 + del e
456 + _tested_pty = True
457 +
458 + if _fbsd_test_pty and not _disable_openpty:
459 + # Test for python openpty breakage after freebsd7 to freebsd8
460 + # upgrade, which results in a 'Function not implemented' error
461 + # and the process being killed.
462 + pid = os.fork()
463 + if pid == 0:
464 + pty.openpty()
465 + os._exit(os.EX_OK)
466 + pid, status = os.waitpid(pid, 0)
467 + if (status & 0xff) == 140:
468 + _disable_openpty = True
469 + _fbsd_test_pty = False
470 +
471 + if _disable_openpty:
472 + master_fd, slave_fd = os.pipe()
473 + else:
474 + try:
475 + master_fd, slave_fd = pty.openpty()
476 + got_pty = True
477 + except EnvironmentError as e:
478 + _disable_openpty = True
479 + writemsg("openpty failed: '%s'\n" % str(e),
480 + noiselevel=-1)
481 + del e
482 + master_fd, slave_fd = os.pipe()
483 +
484 + if got_pty:
485 + # Disable post-processing of output since otherwise weird
486 + # things like \n -> \r\n transformations may occur.
487 + mode = termios.tcgetattr(slave_fd)
488 + mode[1] &= ~termios.OPOST
489 + termios.tcsetattr(slave_fd, termios.TCSANOW, mode)
490 +
491 + if got_pty and \
492 + copy_term_size is not None and \
493 + os.isatty(copy_term_size):
494 + rows, columns = get_term_size()
495 + set_term_size(rows, columns, slave_fd)
496 +
497 + return (got_pty, master_fd, slave_fd)