2 # Copyright 2010 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
5 # This is a helper which ebuild processes can use
6 # to communicate with portage's main python process.
16 def debug_signal(signum, frame):
19 signal.signal(signal.SIGUSR1, debug_signal)
21 # Avoid sandbox violations after python upgrade.
22 pym_path = os.path.join(os.path.dirname(
23 os.path.dirname(os.path.realpath(__file__))), "pym")
24 if os.environ.get("SANDBOX_ON") == "1":
25 sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
26 if pym_path not in sandbox_write:
27 sandbox_write.append(pym_path)
28 os.environ["SANDBOX_WRITE"] = \
29 ":".join(filter(None, sandbox_write))
33 class EbuildIpc(object):
35 _COMMUNICATE_TIMEOUT_SECONDS = 40
38 self.fifo_dir = os.environ['PORTAGE_BUILDDIR']
39 self.ipc_in_fifo = os.path.join(self.fifo_dir, '.ipc_in')
40 self.ipc_out_fifo = os.path.join(self.fifo_dir, '.ipc_out')
41 self.ipc_lock_file = os.path.join(self.fifo_dir, '.ipc_lock')
43 def communicate(self, args):
45 # Make locks quiet since unintended locking messages displayed on
46 # stdout could corrupt the intended output of this program.
47 portage.locks._quiet = True
48 lock_obj = portage.locks.lockfile(self.ipc_lock_file, unlinkfile=True)
49 start_time = time.time()
52 signal.signal(signal.SIGALRM, portage.exception.AlarmSignal.signal_handler)
53 signal.alarm(self._COMMUNICATE_TIMEOUT_SECONDS)
54 returncode = self._communicate(args)
57 except portage.exception.AlarmSignal:
58 time_elapsed = time.time() - start_time
59 portage.util.writemsg_level(
60 ('ebuild-ipc timed out after %d seconds\n') % \
62 level=logging.ERROR, noiselevel=-1)
66 portage.locks.unlockfile(lock_obj)
68 def _communicate(self, args):
69 input_fd = os.open(self.ipc_out_fifo, os.O_RDONLY|os.O_NONBLOCK)
71 # File streams are in unbuffered mode since we do atomic
72 # read and write of whole pickles.
73 input_file = os.fdopen(input_fd, 'rb', 0)
74 output_file = open(self.ipc_in_fifo, 'wb', 0)
76 # Write the whole pickle in a single atomic write() call,
77 # since the reader is in non-blocking mode and we want
78 # it to get the whole pickle at once.
79 output_file.write(pickle.dumps(args))
82 events = select.select([input_file], [], [])
84 # Read the whole pickle in a single read() call since
85 # this stream is in non-blocking mode and pickle.load()
86 # has been known to raise the following exception when
87 # reading from a non-blocking stream:
89 # File "/usr/lib64/python2.6/pickle.py", line 1370, in load
90 # return Unpickler(file).load()
91 # File "/usr/lib64/python2.6/pickle.py", line 858, in load
93 # File "/usr/lib64/python2.6/pickle.py", line 1195, in load_setitem
95 # IndexError: pop from empty list
97 pickle_str = input_file.read()
98 reply = pickle.loads(pickle_str)
102 (out, err, rval) = reply
105 portage.util.writemsg_stdout(out, noiselevel=-1)
108 portage.util.writemsg(err, noiselevel=-1)
112 def ebuild_ipc_main(args):
113 ebuild_ipc = EbuildIpc()
114 return ebuild_ipc.communicate(args)
116 if __name__ == '__main__':
117 sys.exit(ebuild_ipc_main(sys.argv[1:]))