summaryrefslogtreecommitdiffstats
path: root/pym
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2008-07-06 09:17:22 +0000
committerZac Medico <zmedico@gentoo.org>2008-07-06 09:17:22 +0000
commit5d852fd7008a7e94c3f6045da2e3cb1e09e9cb20 (patch)
tree6d483a66ea222d2829068e40fc7f989e129ac06a /pym
parent81676e7a6301f25609e9e89f9cdeaa0ce1375427 (diff)
downloadportage-5d852fd7008a7e94c3f6045da2e3cb1e09e9cb20.tar.gz
portage-5d852fd7008a7e94c3f6045da2e3cb1e09e9cb20.tar.bz2
portage-5d852fd7008a7e94c3f6045da2e3cb1e09e9cb20.zip
Make BinpkgFetcher send output directly to stdout when appropriate,
so that wget's progress bar works normally. svn path=/main/trunk/; revision=10958
Diffstat (limited to 'pym')
-rw-r--r--pym/_emerge/__init__.py95
1 files changed, 66 insertions, 29 deletions
diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py
index 5359745b7..7785dd997 100644
--- a/pym/_emerge/__init__.py
+++ b/pym/_emerge/__init__.py
@@ -1630,6 +1630,11 @@ class TaskSequence(CompositeTask):
class SubProcess(AsynchronousTask):
__slots__ = ("pid",)
+ # A file descriptor is required for the scheduler to monitor changes from
+ # inside a poll() loop. When logging is not enabled, create a pipe just to
+ # serve this purpose alone.
+ _dummy_pipe_fd = 9
+
def _poll(self):
if self.returncode is not None:
return self.returncode
@@ -1693,43 +1698,48 @@ class SpawnProcess(SubProcess):
if self.cancelled:
return
- # flush any pending output
+ if self.fd_pipes is None:
+ self.fd_pipes = {}
fd_pipes = self.fd_pipes
- if fd_pipes is None:
- fd_pipes = {
- 0 : sys.stdin.fileno(),
- 1 : sys.stdout.fileno(),
- 2 : sys.stderr.fileno(),
- }
+ fd_pipes.setdefault(0, sys.stdin.fileno())
+ fd_pipes.setdefault(1, sys.stdout.fileno())
+ fd_pipes.setdefault(2, sys.stderr.fileno())
+
+ # flush any pending output
+ for fd in fd_pipes.itervalues():
+ if fd == sys.stdout.fileno():
+ sys.stdout.flush()
+ if fd == sys.stderr.fileno():
+ sys.stderr.flush()
logfile = self.logfile
self.files = self._files_dict()
files = self.files
+ master_fd, slave_fd = os.pipe()
+ fcntl.fcntl(master_fd, fcntl.F_SETFL,
+ fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+
if logfile is not None:
+
+ fd_pipes_orig = fd_pipes.copy()
+ fd_pipes[0] = fd_pipes_orig[0]
+ fd_pipes[1] = slave_fd
+ fd_pipes[2] = slave_fd
+
files.out = open(logfile, "a")
portage.util.apply_secpass_permissions(logfile,
uid=portage.portage_uid, gid=portage.portage_gid,
mode=0660)
- else:
- fd_pipes.setdefault(1, sys.stdout.fileno())
- for fd in fd_pipes.itervalues():
- if fd == sys.stdout.fileno():
- sys.stdout.flush()
- if fd == sys.stderr.fileno():
- sys.stderr.flush()
- files.out = os.fdopen(os.dup(fd_pipes[1]), 'w')
- master_fd, slave_fd = os.pipe()
+ output_handler = self._output_handler
- fcntl.fcntl(master_fd, fcntl.F_SETFL,
- fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
+ else:
- fd_pipes.setdefault(0, sys.stdin.fileno())
- fd_pipes_orig = fd_pipes.copy()
- fd_pipes[0] = fd_pipes_orig[0]
- fd_pipes[1] = slave_fd
- fd_pipes[2] = slave_fd
+ # Create a dummy pipe so the scheduler can monitor
+ # the process from inside a poll() loop.
+ fd_pipes[self._dummy_pipe_fd] = slave_fd
+ output_handler = self._dummy_handler
kwargs = {}
for k in self._spawn_kwarg_names:
@@ -1748,7 +1758,7 @@ class SpawnProcess(SubProcess):
os.close(slave_fd)
files.process = os.fdopen(master_fd, 'r')
self.reg_id = self.scheduler.register(files.process.fileno(),
- PollConstants.POLLIN, self._output_handler)
+ PollConstants.POLLIN, output_handler)
self.registered = True
def _output_handler(self, fd, event):
@@ -1769,6 +1779,27 @@ class SpawnProcess(SubProcess):
self.registered = False
return self.registered
+ def _dummy_handler(self, fd, event):
+ """
+ This method is mainly interested in detecting EOF, since
+ the only purpose of the pipe is to allow the scheduler to
+ monitor the process from inside a poll() loop.
+ """
+ files = self.files
+ buf = array.array('B')
+ try:
+ buf.fromfile(files.process, self._bufsize)
+ except EOFError:
+ pass
+ if buf:
+ pass
+ else:
+ fd = files.process.fileno()
+ for f in files.values():
+ f.close()
+ self.registered = False
+ return self.registered
+
class EbuildFetcher(SpawnProcess):
__slots__ = ("pkg",)
@@ -2106,11 +2137,6 @@ class EbuildPhase(SubProcess):
_files_dict = slot_dict_class(_file_names, prefix="")
_bufsize = 4096
- # A file descriptor is required for the scheduler to monitor changes from
- # inside a poll() loop. When logging is not enabled, create a pipe just to
- # serve this purpose alone.
- _dummy_pipe_fd = 9
-
def start(self):
root_config = self.pkg.root_config
tree = self.tree
@@ -2637,6 +2663,17 @@ class BinpkgFetcher(SpawnProcess):
if use_locks:
self.lock()
+ if self.fd_pipes is None:
+ self.fd_pipes = {}
+ fd_pipes = self.fd_pipes
+
+ # Redirect all output to stdout since some fetchers like
+ # wget pollute stderr (if portage detects a problem then it
+ # can send it's own message to stderr).
+ fd_pipes.setdefault(0, sys.stdin.fileno())
+ fd_pipes.setdefault(1, sys.stdout.fileno())
+ fd_pipes.setdefault(2, sys.stdout.fileno())
+
self.args = fetch_args
self.env = fetch_env
SpawnProcess.start(self)