Exemplo n.º 1
0
    def _elog(self, elog_funcname, lines, background=None, loop=None):
        if background is None:
            background = self.background
        out = io.StringIO()
        phase = self.phase
        elog_func = getattr(elog_messages, elog_funcname)
        global_havecolor = portage.output.havecolor
        try:
            portage.output.havecolor = \
             self.settings.get('NOCOLOR', 'false').lower() in ('no', 'false')
            for line in lines:
                elog_func(line, phase=phase, key=self.settings.mycpv, out=out)
        finally:
            portage.output.havecolor = global_havecolor
        msg = out.getvalue()
        if msg:
            build_logger = None
            try:
                log_file = None
                log_path = None
                if self.settings.get("PORTAGE_BACKGROUND") != "subprocess":
                    log_path = self.settings.get("PORTAGE_LOG_FILE")
                if log_path:
                    build_logger = BuildLogger(
                        env=self.settings.environ(),
                        log_path=log_path,
                        log_filter_file=self.settings.get(
                            'PORTAGE_LOG_FILTER_FILE_CMD'),
                        scheduler=self.scheduler)
                    build_logger.start()
                    _set_nonblocking(build_logger.stdin.fileno())
                    log_file = build_logger.stdin

                yield self.scheduler.async_output(msg,
                                                  log_file=log_file,
                                                  background=background,
                                                  loop=self.scheduler)

                if build_logger is not None:
                    build_logger.stdin.close()
                    yield build_logger.async_wait()
            except asyncio.CancelledError:
                if build_logger is not None:
                    build_logger.cancel()
                raise
Exemplo n.º 2
0
    def _start(self):

        if self.fd_pipes is None:
            self.fd_pipes = {}
        else:
            self.fd_pipes = self.fd_pipes.copy()
        fd_pipes = self.fd_pipes

        master_fd, slave_fd = self._pipe(fd_pipes)

        can_log = self._can_log(slave_fd)
        if can_log:
            log_file_path = self.logfile
        else:
            log_file_path = None

        null_input = None
        if not self.background or 0 in fd_pipes:
            # Subclasses such as AbstractEbuildProcess may have already passed
            # in a null file descriptor in fd_pipes, so use that when given.
            pass
        else:
            # TODO: Use job control functions like tcsetpgrp() to control
            # access to stdin. Until then, use /dev/null so that any
            # attempts to read from stdin will immediately return EOF
            # instead of blocking indefinitely.
            null_input = os.open('/dev/null', os.O_RDWR)
            fd_pipes[0] = null_input

        fd_pipes.setdefault(0, portage._get_stdin().fileno())
        fd_pipes.setdefault(1, sys.__stdout__.fileno())
        fd_pipes.setdefault(2, sys.__stderr__.fileno())

        # flush any pending output
        stdout_filenos = (sys.__stdout__.fileno(), sys.__stderr__.fileno())
        for fd in fd_pipes.values():
            if fd in stdout_filenos:
                sys.__stdout__.flush()
                sys.__stderr__.flush()
                break

        fd_pipes_orig = fd_pipes.copy()

        if log_file_path is not None or self.background:
            fd_pipes[1] = slave_fd
            fd_pipes[2] = slave_fd

        else:
            # Create a dummy pipe that PipeLogger uses to efficiently
            # monitor for process exit by listening for the EOF event.
            # Re-use of the allocated fd number for the key in fd_pipes
            # guarantees that the keys will not collide for similarly
            # allocated pipes which are used by callers such as
            # FileDigester and MergeProcess. See the _setup_pipes
            # docstring for more benefits of this allocation approach.
            self._dummy_pipe_fd = slave_fd
            fd_pipes[slave_fd] = slave_fd

        kwargs = {}
        for k in self._spawn_kwarg_names:
            v = getattr(self, k)
            if v is not None:
                kwargs[k] = v

        kwargs["fd_pipes"] = fd_pipes
        kwargs["returnpid"] = True
        kwargs.pop("logfile", None)

        retval = self._spawn(self.args, **kwargs)

        os.close(slave_fd)
        if null_input is not None:
            os.close(null_input)

        if isinstance(retval, int):
            # spawn failed
            self.returncode = retval
            self._async_wait()
            return

        self.pid = retval[0]

        stdout_fd = None
        if can_log and not self.background:
            stdout_fd = os.dup(fd_pipes_orig[1])

        build_logger = BuildLogger(env=self.env,
                                   log_path=log_file_path,
                                   log_filter_file=self.log_filter_file,
                                   scheduler=self.scheduler)
        build_logger.start()

        pipe_logger = PipeLogger(background=self.background,
                                 scheduler=self.scheduler,
                                 input_fd=master_fd,
                                 log_file_path=build_logger.stdin,
                                 stdout_fd=stdout_fd)

        pipe_logger.start()

        self._registered = True
        self._main_task = asyncio.ensure_future(self._main(
            build_logger, pipe_logger),
                                                loop=self.scheduler)
        self._main_task.add_done_callback(self._main_exit)