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) |