From fe2a1cd25ed779ac1a09b9b5c076c61981a46158 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Mon, 9 Aug 2010 23:27:21 -0700 Subject: [PATCH] Convert doebuild.spawn() to use the AsynchronousTask api, which will be useful for ebuild IPC implementation. --- pym/_emerge/EbuildSpawnProcess.py | 22 +++++ pym/portage/package/ebuild/doebuild.py | 112 ++++--------------------- 2 files changed, 36 insertions(+), 98 deletions(-) create mode 100644 pym/_emerge/EbuildSpawnProcess.py diff --git a/pym/_emerge/EbuildSpawnProcess.py b/pym/_emerge/EbuildSpawnProcess.py new file mode 100644 index 000000000..e19a04051 --- /dev/null +++ b/pym/_emerge/EbuildSpawnProcess.py @@ -0,0 +1,22 @@ +# Copyright 2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +from _emerge.AbstractEbuildProcess import AbstractEbuildProcess +import portage +from portage import os + +class EbuildSpawnProcess(AbstractEbuildProcess): + """ + Spawns misc-functions.sh with an existing ebuild environment. + """ + _spawn_kwarg_names = AbstractEbuildProcess._spawn_kwarg_names + \ + ('fakeroot_state',) + + __slots__ = ('fakeroot_state', 'spawn_func') + + def _start(self): + + AbstractEbuildProcess._start(self) + + def _spawn(self, args, **kwargs): + return self.spawn_func(args, **kwargs) diff --git a/pym/portage/package/ebuild/doebuild.py b/pym/portage/package/ebuild/doebuild.py index 9f4fe2f4f..34a7206e2 100644 --- a/pym/portage/package/ebuild/doebuild.py +++ b/pym/portage/package/ebuild/doebuild.py @@ -54,6 +54,8 @@ from portage.util import apply_recursive_permissions, \ from portage.util._pty import _create_pty_or_pipe from portage.util.lafilefixer import rewrite_lafile from portage.versions import _pkgsplit +from _emerge.EbuildSpawnProcess import EbuildSpawnProcess +from _emerge.TaskScheduler import TaskScheduler def doebuild_environment(myebuild, mydo, myroot, mysettings, debug, use_cache, mydbapi): @@ -1159,54 +1161,6 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero sys.stderr.flush() break - # The default policy for the sesandbox domain only allows entry (via exec) - # from shells and from binaries that belong to portage (the number of entry - # points is minimized). The "tee" binary is not among the allowed entry - # points, so it is spawned outside of the sesandbox domain and reads from a - # pseudo-terminal that connects two domains. - logfile = keywords.get("logfile") - mypids = [] - master_fd = None - slave_fd = None - fd_pipes_orig = None - got_pty = False - if logfile: - del keywords["logfile"] - if 1 not in fd_pipes or 2 not in fd_pipes: - raise ValueError(fd_pipes) - - got_pty, master_fd, slave_fd = \ - _create_pty_or_pipe(copy_term_size=fd_pipes[1]) - - if not got_pty and 'sesandbox' in mysettings.features \ - and mysettings.selinux_enabled(): - # With sesandbox, logging works through a pty but not through a - # normal pipe. So, disable logging if ptys are broken. - # See Bug #162404. - logfile = None - os.close(master_fd) - master_fd = None - os.close(slave_fd) - slave_fd = None - - if logfile: - - fd_pipes.setdefault(0, sys.stdin.fileno()) - fd_pipes_orig = fd_pipes.copy() - - # We must set non-blocking mode before we close the slave_fd - # since otherwise the fcntl call can fail on FreeBSD (the child - # process might have already exited and closed slave_fd so we - # have to keep it open in order to avoid FreeBSD potentially - # generating an EAGAIN exception). - fcntl.fcntl(master_fd, fcntl.F_SETFL, - fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK) - - fd_pipes[0] = fd_pipes_orig[0] - fd_pipes[1] = slave_fd - fd_pipes[2] = slave_fd - keywords["fd_pipes"] = fd_pipes - features = mysettings.features # TODO: Enable fakeroot to be used together with droppriv. The # fake ownership/permissions will have to be converted to real @@ -1238,58 +1192,20 @@ def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakero spawn_func = selinux.spawn_wrapper(spawn_func, mysettings["PORTAGE_SANDBOX_T"]) - returnpid = keywords.get("returnpid") - keywords["returnpid"] = True - try: - mypids.extend(spawn_func(mystring, env=env, **keywords)) - finally: - if logfile: - os.close(slave_fd) + if keywords.get("returnpid"): + return spawn_func(mystring, env=env, **keywords) - if returnpid: - return mypids - - if logfile: - log_file = open(_unicode_encode(logfile), mode='ab') - apply_secpass_permissions(logfile, - uid=portage_uid, gid=portage_gid, mode=0o664) - stdout_file = os.fdopen(os.dup(fd_pipes_orig[1]), 'wb') - master_file = os.fdopen(master_fd, 'rb') - iwtd = [master_file] - owtd = [] - ewtd = [] - buffsize = 65536 - eof = False - while not eof: - events = select.select(iwtd, owtd, ewtd) - for f in events[0]: - # Use non-blocking mode to prevent read - # calls from blocking indefinitely. - buf = array.array('B') - try: - buf.fromfile(f, buffsize) - except (EOFError, IOError): - pass - if not buf: - eof = True - break - if f is master_file: - buf.tofile(stdout_file) - stdout_file.flush() - buf.tofile(log_file) - log_file.flush() - log_file.close() - stdout_file.close() - master_file.close() - pid = mypids[-1] - retval = os.waitpid(pid, 0)[1] - portage.process.spawned_pids.remove(pid) - if retval != os.EX_OK: - if retval & 0xff: - return (retval & 0xff) << 8 - return retval >> 8 - return retval + sched = TaskScheduler() + proc = EbuildSpawnProcess( + background=False, + args=mystring, env=env, + scheduler=sched.sched_iface, spawn_func=spawn_func, + settings=mysettings, **keywords) + + sched.add(proc) + sched.run() + return proc.returncode # parse actionmap to spawn ebuild with the appropriate args def spawnebuild(mydo, actionmap, mysettings, debug, alwaysdep=0, -- 2.26.2