Package _emerge :: Module PipeReader
[hide private]

Source Code for Module _emerge.PipeReader

  1  # Copyright 1999-2013 Gentoo Foundation 
  2  # Distributed under the terms of the GNU General Public License v2 
  3   
  4  import fcntl 
  5  import sys 
  6   
  7  from portage import os 
  8  from _emerge.AbstractPollTask import AbstractPollTask 
  9   
10 -class PipeReader(AbstractPollTask):
11 12 """ 13 Reads output from one or more files and saves it in memory, 14 for retrieval via the getvalue() method. This is driven by 15 the scheduler's poll() loop, so it runs entirely within the 16 current process. 17 """ 18 19 __slots__ = ("input_files",) + \ 20 ("_read_data", "_reg_ids", "_use_array") 21
22 - def _start(self):
23 self._reg_ids = set() 24 self._read_data = [] 25 26 if self._use_array: 27 output_handler = self._array_output_handler 28 else: 29 output_handler = self._output_handler 30 31 for f in self.input_files.values(): 32 fd = isinstance(f, int) and f or f.fileno() 33 fcntl.fcntl(fd, fcntl.F_SETFL, 34 fcntl.fcntl(fd, fcntl.F_GETFL) | os.O_NONBLOCK) 35 36 # FD_CLOEXEC is enabled by default in Python >=3.4. 37 if sys.hexversion < 0x3040000: 38 try: 39 fcntl.FD_CLOEXEC 40 except AttributeError: 41 pass 42 else: 43 fcntl.fcntl(fd, fcntl.F_SETFD, 44 fcntl.fcntl(fd, fcntl.F_GETFD) | fcntl.FD_CLOEXEC) 45 46 self._reg_ids.add(self.scheduler.io_add_watch(fd, 47 self._registered_events, output_handler)) 48 self._registered = True
49
50 - def _cancel(self):
51 self._unregister() 52 if self.returncode is None: 53 self.returncode = self._cancelled_returncode
54
55 - def _wait(self):
56 if self.returncode is not None: 57 return self.returncode 58 self._wait_loop() 59 self.returncode = os.EX_OK 60 return self.returncode
61
62 - def getvalue(self):
63 """Retrieve the entire contents""" 64 return b''.join(self._read_data)
65
66 - def close(self):
67 """Free the memory buffer.""" 68 self._read_data = None
69
70 - def _output_handler(self, fd, event):
71 72 while True: 73 data = self._read_buf(fd, event) 74 if data is None: 75 break 76 if data: 77 self._read_data.append(data) 78 else: 79 self._unregister() 80 self.wait() 81 break 82 83 self._unregister_if_appropriate(event) 84 85 return True
86
87 - def _array_output_handler(self, fd, event):
88 89 for f in self.input_files.values(): 90 if f.fileno() == fd: 91 break 92 93 while True: 94 data = self._read_array(f, event) 95 if data is None: 96 break 97 if data: 98 self._read_data.append(data) 99 else: 100 self._unregister() 101 self.wait() 102 break 103 104 self._unregister_if_appropriate(event) 105 106 return True
107
108 - def _unregister(self):
109 """ 110 Unregister from the scheduler and close open files. 111 """ 112 113 self._registered = False 114 115 if self._reg_ids is not None: 116 for reg_id in self._reg_ids: 117 self.scheduler.source_remove(reg_id) 118 self._reg_ids = None 119 120 if self.input_files is not None: 121 for f in self.input_files.values(): 122 if isinstance(f, int): 123 os.close(f) 124 else: 125 f.close() 126 self.input_files = None
127