blob: 375c98f6ad1c0eb19bd9562ccfba2cff3a21e645 [file] [log] [blame]
# Copyright 1999-2011 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from portage import os
from _emerge.AbstractPollTask import AbstractPollTask
from _emerge.PollConstants import PollConstants
import fcntl
import array
class PipeReader(AbstractPollTask):
"""
Reads output from one or more files and saves it in memory,
for retrieval via the getvalue() method. This is driven by
the scheduler's poll() loop, so it runs entirely within the
current process.
"""
__slots__ = ("input_files",) + \
("_read_data", "_reg_ids")
def _start(self):
self._reg_ids = set()
self._read_data = []
for k, f in self.input_files.items():
fcntl.fcntl(f.fileno(), fcntl.F_SETFL,
fcntl.fcntl(f.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
self._reg_ids.add(self.scheduler.register(f.fileno(),
self._registered_events, self._output_handler))
self._registered = True
def isAlive(self):
return self._registered
def _cancel(self):
if self.returncode is None:
self.returncode = 1
def _wait(self):
if self.returncode is not None:
return self.returncode
if self._registered:
self.scheduler.schedule(self._reg_ids)
self._unregister()
self.returncode = os.EX_OK
return self.returncode
def getvalue(self):
"""Retrieve the entire contents"""
return b''.join(self._read_data)
def close(self):
"""Free the memory buffer."""
self._read_data = None
def _output_handler(self, fd, event):
if event & PollConstants.POLLIN:
for f in self.input_files.values():
if fd == f.fileno():
break
buf = array.array('B')
try:
buf.fromfile(f, self._bufsize)
except (EOFError, IOError):
pass
if buf:
self._read_data.append(buf.tostring())
else:
self._unregister()
self.wait()
self._unregister_if_appropriate(event)
def _unregister(self):
"""
Unregister from the scheduler and close open files.
"""
self._registered = False
if self._reg_ids is not None:
for reg_id in self._reg_ids:
self.scheduler.unregister(reg_id)
self._reg_ids = None
if self.input_files is not None:
for f in self.input_files.values():
f.close()
self.input_files = None