Esempio n. 1
0
	def _testPipeReader(self, master_fd, slave_fd, test_string):
		"""
		Use a poll loop to read data from a pipe and assert that
		the data written to the pipe is identical to the data
		read from the pipe.
		"""

		# WARNING: It is very important to use unbuffered mode here,
		# in order to avoid issue 5380 with python3.
		master_file = os.fdopen(master_fd, 'rb', 0)
		scheduler = global_event_loop()

		consumer = PipeReader(
			input_files={"producer" : master_file},
			_use_array=self._use_array,
			scheduler=scheduler)

		producer = PopenProcess(
			pipe_reader=consumer,
			proc=subprocess.Popen(["bash", "-c", self._echo_cmd % test_string],
				stdout=slave_fd),
			scheduler=scheduler)

		producer.start()
		os.close(slave_fd)
		producer.wait()
		consumer.wait()

		self.assertEqual(producer.returncode, os.EX_OK)
		self.assertEqual(consumer.returncode, os.EX_OK)

		return consumer.getvalue().decode('ascii', 'replace')
Esempio n. 2
0
	def _receive_reply(self, input_fd):

		start_time = time.time()

		pipe_reader = PipeReader(input_files={"input_fd":input_fd},
			scheduler=global_event_loop())
		pipe_reader.start()

		eof = pipe_reader.poll() is not None

		while not eof:
			pipe_reader._wait_loop(timeout=self._COMMUNICATE_RETRY_TIMEOUT)
			eof = pipe_reader.poll() is not None
			if not eof:
				if self._daemon_is_alive():
					self._timeout_retry_msg(start_time,
						portage.localization._('during read'))
				else:
					pipe_reader.cancel()
					self._no_daemon_msg()
					return 2

		buf = pipe_reader.getvalue()

		retval = 2

		if not buf:

			portage.util.writemsg_level(
				"ebuild-ipc: %s\n" % \
				(portage.localization._('read failed'),),
				level=logging.ERROR, noiselevel=-1)

		else:

			try:
				reply = pickle.loads(buf)
			except SystemExit:
				raise
			except Exception as e:
				# The pickle module can raise practically
				# any exception when given corrupt data.
				portage.util.writemsg_level(
					"ebuild-ipc: %s\n" % (e,),
					level=logging.ERROR, noiselevel=-1)

			else:

				(out, err, retval) = reply

				if out:
					portage.util.writemsg_stdout(out, noiselevel=-1)

				if err:
					portage.util.writemsg(err, noiselevel=-1)

		return retval
Esempio n. 3
0
	def _testPipeReader(self, test_string):
		"""
		Use a poll loop to read data from a pipe and assert that
		the data written to the pipe is identical to the data
		read from the pipe.
		"""

		if self._use_pty:
			got_pty, master_fd, slave_fd = _create_pty_or_pipe()
			if not got_pty:
				os.close(slave_fd)
				os.close(master_fd)
				skip_reason = "pty not acquired"
				self.portage_skip = skip_reason
				self.fail(skip_reason)
				return
		else:
			master_fd, slave_fd = os.pipe()

		# WARNING: It is very important to use unbuffered mode here,
		# in order to avoid issue 5380 with python3.
		master_file = os.fdopen(master_fd, 'rb', 0)
		slave_file = os.fdopen(slave_fd, 'wb', 0)
		task_scheduler = TaskScheduler(max_jobs=2)
		producer = SpawnProcess(
			args=["bash", "-c", self._echo_cmd % test_string],
			env=os.environ, fd_pipes={1:slave_fd},
			scheduler=task_scheduler.sched_iface)
		task_scheduler.add(producer)
		slave_file.close()

		consumer = PipeReader(
			input_files={"producer" : master_file},
			scheduler=task_scheduler.sched_iface, _use_array=self._use_array)

		task_scheduler.add(consumer)

		# This will ensure that both tasks have exited, which
		# is necessary to avoid "ResourceWarning: unclosed file"
		# warnings since Python 3.2 (and also ensures that we
		# don't leave any zombie child processes).
		task_scheduler.run()
		self.assertEqual(producer.returncode, os.EX_OK)
		self.assertEqual(consumer.returncode, os.EX_OK)

		return consumer.getvalue().decode('ascii', 'replace')
Esempio n. 4
0
	def _start(self):
		pr, pw = os.pipe()
		self.fd_pipes = {}
		self.fd_pipes[pw] = pw
		self._digest_pw = pw
		self._digest_pipe_reader = PipeReader(
			input_files={"input":pr},
			scheduler=self.scheduler)
		self._digest_pipe_reader.addExitListener(self._digest_pipe_reader_exit)
		self._digest_pipe_reader.start()
		ForkProcess._start(self)
		os.close(pw)
Esempio n. 5
0
	def testPipeReader(self):
		"""
		Use a poll loop to read data from a pipe and assert that
		the data written to the pipe is identical to the data
		read from the pipe.
		"""

		test_string = 2 * "blah blah blah\n"

		master_fd, slave_fd = self._create_pipe()
		master_file = os.fdopen(master_fd, 'rb')

		task_scheduler = TaskScheduler(max_jobs=2)
		scheduler = task_scheduler.sched_iface

		class Producer(SpawnProcess):
			def _spawn(self, args, **kwargs):
				rval = SpawnProcess._spawn(self, args, **kwargs)
				os.close(kwargs['fd_pipes'][1])
				return rval

		producer = Producer(
			args=["bash", "-c", "echo -n '%s'" % test_string],
			fd_pipes={1:slave_fd}, scheduler=scheduler)

		consumer = PipeReader(
			input_files={"producer" : master_file},
			scheduler=scheduler)

		task_scheduler.add(producer)
		task_scheduler.add(consumer)

		task_scheduler.run()

		if sys.hexversion >= 0x3000000:
			test_string = test_string.encode()

		self._assertEqual(test_string, consumer.getvalue())
    def testLazyImportPortageBaseline(self):
        """
		Check what modules are imported by a baseline module import.
		"""

        env = os.environ.copy()
        pythonpath = env.get('PYTHONPATH')
        if pythonpath is not None and not pythonpath.strip():
            pythonpath = None
        if pythonpath is None:
            pythonpath = ''
        else:
            pythonpath = ':' + pythonpath
        pythonpath = PORTAGE_PYM_PATH + pythonpath
        env['PYTHONPATH'] = pythonpath

        # If python is patched to insert the path of the
        # currently installed portage module into sys.path,
        # then the above PYTHONPATH override doesn't help.
        env['PORTAGE_PYM_PATH'] = PORTAGE_PYM_PATH

        scheduler = global_event_loop()
        master_fd, slave_fd = os.pipe()
        master_file = os.fdopen(master_fd, 'rb', 0)
        slave_file = os.fdopen(slave_fd, 'wb')
        producer = SpawnProcess(args=self._baseline_import_cmd,
                                env=env,
                                fd_pipes={1: slave_fd},
                                scheduler=scheduler)
        producer.start()
        slave_file.close()

        consumer = PipeReader(input_files={"producer": master_file},
                              scheduler=scheduler)

        consumer.start()
        consumer.wait()
        self.assertEqual(producer.wait(), os.EX_OK)
        self.assertEqual(consumer.wait(), os.EX_OK)

        output = consumer.getvalue().decode('ascii', 'replace').split()

        unexpected_modules = " ".join(sorted(x for x in output \
         if self._module_re.match(x) is not None and \
         x not in self._baseline_imports))

        self.assertEqual("", unexpected_modules)
Esempio n. 7
0
	def testPipeReader(self):
		"""
		Use a poll loop to read data from a pipe and assert that
		the data written to the pipe is identical to the data
		read from the pipe.
		"""

		test_string = 2 * "blah blah blah\n"

		scheduler = PollScheduler().sched_iface
		master_fd, slave_fd = os.pipe()
		master_file = os.fdopen(master_fd, 'rb', 0)
		slave_file = os.fdopen(slave_fd, 'wb')
		producer = SpawnProcess(
			args=["bash", "-c", "echo -n '%s'" % test_string],
			env=os.environ, fd_pipes={1:slave_fd},
			scheduler=scheduler)
		producer.start()
		slave_file.close()

		consumer = PipeReader(
			input_files={"producer" : master_file},
			scheduler=scheduler)

		consumer.start()

		# This will ensure that both tasks have exited, which
		# is necessary to avoid "ResourceWarning: unclosed file"
		# warnings since Python 3.2 (and also ensures that we
		# don't leave any zombie child processes).
		scheduler.schedule()
		self.assertEqual(producer.returncode, os.EX_OK)
		self.assertEqual(consumer.returncode, os.EX_OK)

		output = consumer.getvalue().decode('ascii', 'replace')
		self.assertEqual(test_string, output)
Esempio n. 8
0
 def _check_sig_key(self):
     null_fd = os.open("/dev/null", os.O_RDONLY)
     popen_proc = PopenProcess(
         proc=subprocess.Popen(
             ["gpg", "--verify", self._manifest_path],
             stdin=null_fd,
             stdout=subprocess.PIPE,
             stderr=subprocess.STDOUT,
         ),
         pipe_reader=PipeReader(),
     )
     os.close(null_fd)
     popen_proc.pipe_reader.input_files = {
         "producer": popen_proc.proc.stdout
     }
     self._start_task(popen_proc, self._check_sig_key_exit)
	def testLazyImportPortageBaseline(self):
		"""
		Check what modules are imported by a baseline module import.
		"""

		env = os.environ.copy()
		pythonpath = env.get('PYTHONPATH')
		if pythonpath is not None and not pythonpath.strip():
			pythonpath = None
		if pythonpath is None:
			pythonpath = ''
		else:
			pythonpath = ':' + pythonpath
		pythonpath = PORTAGE_PYM_PATH + pythonpath
		env['PYTHONPATH'] = pythonpath

		# If python is patched to insert the path of the
		# currently installed portage module into sys.path,
		# then the above PYTHONPATH override doesn't help.
		env['PORTAGE_PYM_PATH'] = PORTAGE_PYM_PATH

		scheduler = PollScheduler().sched_iface
		master_fd, slave_fd = os.pipe()
		master_file = os.fdopen(master_fd, 'rb', 0)
		slave_file = os.fdopen(slave_fd, 'wb')
		producer = SpawnProcess(
			args=self._baseline_import_cmd,
			env=env, fd_pipes={1:slave_fd},
			scheduler=scheduler)
		producer.start()
		slave_file.close()

		consumer = PipeReader(
			input_files={"producer" : master_file},
			scheduler=scheduler)

		consumer.start()
		consumer.wait()
		self.assertEqual(producer.wait(), os.EX_OK)
		self.assertEqual(consumer.wait(), os.EX_OK)

		output = consumer.getvalue().decode('ascii', 'replace').split()

		unexpected_modules = " ".join(sorted(x for x in output \
			if self._module_re.match(x) is not None and \
			x not in self._baseline_imports))

		self.assertEqual("", unexpected_modules)
Esempio n. 10
0
class _Reader(object):
    def __init__(self, future, input_file, loop):
        self._future = future
        self._pipe_reader = PipeReader(input_files={'input_file': input_file},
                                       scheduler=loop)

        self._future.add_done_callback(self._cancel_callback)
        self._pipe_reader.addExitListener(self._eof)
        self._pipe_reader.start()

    def _cancel_callback(self, future):
        if future.cancelled():
            self._cancel()

    def _eof(self, pipe_reader):
        self._pipe_reader = None
        self._future.set_result(pipe_reader.getvalue())

    def _cancel(self):
        if self._pipe_reader is not None and self._pipe_reader.poll() is None:
            self._pipe_reader.removeExitListener(self._eof)
            self._pipe_reader.cancel()
            self._pipe_reader = None
Esempio n. 11
0
    def _testPipeReader(self, test_string):
        """
		Use a poll loop to read data from a pipe and assert that
		the data written to the pipe is identical to the data
		read from the pipe.
		"""

        producer = PopenProcess(proc=subprocess.Popen(
            ["bash", "-c", self._echo_cmd % test_string],
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT),
                                pipe_reader=PipeReader(),
                                scheduler=global_event_loop())

        consumer = producer.pipe_reader
        consumer.input_files = {"producer": producer.proc.stdout}

        producer.start()
        producer.wait()

        self.assertEqual(producer.returncode, os.EX_OK)
        self.assertEqual(consumer.returncode, os.EX_OK)

        return consumer.getvalue().decode('ascii', 'replace')
Esempio n. 12
0
    def _testPipeReader(self, master_fd, slave_fd, test_string):
        """
        Use a poll loop to read data from a pipe and assert that
        the data written to the pipe is identical to the data
        read from the pipe.
        """

        # WARNING: It is very important to use unbuffered mode here,
        # in order to avoid issue 5380 with python3.
        master_file = os.fdopen(master_fd, "rb", 0)
        scheduler = global_event_loop()

        consumer = PipeReader(
            input_files={"producer": master_file},
            _use_array=self._use_array,
            scheduler=scheduler,
        )
        consumer.start()

        producer = scheduler.run_until_complete(
            asyncio.create_subprocess_exec(
                "bash",
                "-c",
                self._echo_cmd % test_string,
                stdout=slave_fd,
                loop=scheduler,
            ))

        os.close(slave_fd)
        scheduler.run_until_complete(producer.wait())
        scheduler.run_until_complete(consumer.async_wait())

        self.assertEqual(producer.returncode, os.EX_OK)
        self.assertEqual(consumer.returncode, os.EX_OK)

        return consumer.getvalue().decode("ascii", "replace")
Esempio n. 13
0
class FileDigester(ForkProcess):
	"""
	Asynchronously generate file digests. Pass in file_path and
	hash_names, and after successful execution, the digests
	attribute will be a dict containing all of the requested
	digests.
	"""

	__slots__ = ('file_path', 'digests', 'hash_names',
		'_digest_pipe_reader', '_digest_pw')

	def _start(self):
		pr, pw = os.pipe()
		self.fd_pipes = {}
		self.fd_pipes[pw] = pw
		self._digest_pw = pw
		self._digest_pipe_reader = PipeReader(
			input_files={"input":pr},
			scheduler=self.scheduler)
		self._digest_pipe_reader.addExitListener(self._digest_pipe_reader_exit)
		self._digest_pipe_reader.start()
		ForkProcess._start(self)
		os.close(pw)

	def _run(self):
		digests = perform_multiple_checksums(self.file_path,
			hashes=self.hash_names)

		buf = "".join("%s=%s\n" % item
			for item in digests.items()).encode('utf_8')

		while buf:
			buf = buf[os.write(self._digest_pw, buf):]

		return os.EX_OK

	def _parse_digests(self, data):

		digests = {}
		for line in data.decode('utf_8').splitlines():
			parts = line.split('=', 1)
			if len(parts) == 2:
				digests[parts[0]] = parts[1]

		self.digests = digests

	def _pipe_logger_exit(self, pipe_logger):
		# Ignore this event, since we want to ensure that we
		# exit only after _digest_pipe_reader has reached EOF.
		self._pipe_logger = None

	def _digest_pipe_reader_exit(self, pipe_reader):
		self._parse_digests(pipe_reader.getvalue())
		self._digest_pipe_reader = None
		self._unregister()
		self.wait()

	def _unregister(self):
		ForkProcess._unregister(self)

		pipe_reader = self._digest_pipe_reader
		if pipe_reader is not None:
			self._digest_pipe_reader = None
			pipe_reader.removeExitListener(self._digest_pipe_reader_exit)
			pipe_reader.cancel()
Esempio n. 14
0
class AsyncFunction(ForkProcess):
	"""
	Execute a function call in a fork, and retrieve the function
	return value via pickling/unpickling, accessible as the
	"result" attribute after the forked process has exited.
	"""

	# NOTE: This class overrides the meaning of the SpawnProcess 'args'
	# attribute, and uses it to hold the positional arguments for the
	# 'target' function.
	__slots__ = ('kwargs', 'result', 'target',
		'_async_func_reader', '_async_func_reader_pw')

	def _start(self):
		pr, pw = os.pipe()
		self.fd_pipes = {}
		self.fd_pipes[pw] = pw
		self._async_func_reader_pw = pw
		self._async_func_reader = PipeReader(
			input_files={"input":pr},
			scheduler=self.scheduler)
		self._async_func_reader.addExitListener(self._async_func_reader_exit)
		self._async_func_reader.start()
		ForkProcess._start(self)
		os.close(pw)

	def _run(self):
		try:
			result = self.target(*(self.args or []), **(self.kwargs or {}))
			os.write(self._async_func_reader_pw, pickle.dumps(result))
		except Exception:
			traceback.print_exc()
			return 1

		return os.EX_OK

	def _pipe_logger_exit(self, pipe_logger):
		# Ignore this event, since we want to ensure that we exit
		# only after _async_func_reader_exit has reached EOF.
		self._pipe_logger = None

	def _async_func_reader_exit(self, pipe_reader):
		try:
			self.result = pickle.loads(pipe_reader.getvalue())
		except Exception:
			# The child process will have printed a traceback in this case,
			# and returned an unsuccessful returncode.
			pass
		self._async_func_reader = None
		if self.returncode is None:
			self._async_waitpid()
		else:
			self._unregister()
			self._async_wait()

	def _unregister(self):
		ForkProcess._unregister(self)

		pipe_reader = self._async_func_reader
		if pipe_reader is not None:
			self._async_func_reader = None
			pipe_reader.removeExitListener(self._async_func_reader_exit)
			pipe_reader.cancel()
Esempio n. 15
0
class FileDigester(ForkProcess):
    """
	Asynchronously generate file digests. Pass in file_path and
	hash_names, and after successful execution, the digests
	attribute will be a dict containing all of the requested
	digests.
	"""

    __slots__ = ('file_path', 'digests', 'hash_names', '_digest_pipe_reader',
                 '_digest_pw')

    def _start(self):
        pr, pw = os.pipe()
        self.fd_pipes = {}
        self.fd_pipes[pw] = pw
        self._digest_pw = pw
        self._digest_pipe_reader = PipeReader(input_files={"input": pr},
                                              scheduler=self.scheduler)
        self._digest_pipe_reader.addExitListener(self._digest_pipe_reader_exit)
        self._digest_pipe_reader.start()
        ForkProcess._start(self)
        os.close(pw)

    def _run(self):
        digests = perform_multiple_checksums(self.file_path,
                                             hashes=self.hash_names)

        buf = "".join("%s=%s\n" % item
                      for item in digests.items()).encode('utf_8')

        while buf:
            buf = buf[os.write(self._digest_pw, buf):]

        return os.EX_OK

    def _parse_digests(self, data):

        digests = {}
        for line in data.decode('utf_8').splitlines():
            parts = line.split('=', 1)
            if len(parts) == 2:
                digests[parts[0]] = parts[1]

        self.digests = digests

    def _pipe_logger_exit(self, pipe_logger):
        # Ignore this event, since we want to ensure that we
        # exit only after _digest_pipe_reader has reached EOF.
        self._pipe_logger = None

    def _digest_pipe_reader_exit(self, pipe_reader):
        self._parse_digests(pipe_reader.getvalue())
        self._digest_pipe_reader = None
        self._unregister()
        self.wait()

    def _unregister(self):
        ForkProcess._unregister(self)

        pipe_reader = self._digest_pipe_reader
        if pipe_reader is not None:
            self._digest_pipe_reader = None
            pipe_reader.removeExitListener(self._digest_pipe_reader_exit)
            pipe_reader.cancel()
Esempio n. 16
0
	def testDoebuild(self):
		"""
		Invoke portage.doebuild() with the fd_pipes parameter, and
		check that the expected output appears in the pipe. This
		functionality is not used by portage internally, but it is
		supported for API consumers (see bug #475812).
		"""

		output_fd = 200
		ebuild_body = ['S=${WORKDIR}']
		for phase_func in ('pkg_info', 'pkg_nofetch', 'pkg_pretend',
			'pkg_setup', 'src_unpack', 'src_prepare', 'src_configure',
			'src_compile', 'src_test', 'src_install'):
			ebuild_body.append(('%s() { echo ${EBUILD_PHASE}'
				' 1>&%s; }') % (phase_func, output_fd))

		ebuild_body.append('')
		ebuild_body = '\n'.join(ebuild_body)

		ebuilds = {
			'app-misct/foo-1': {
				'EAPI'      : '5',
				"MISC_CONTENT": ebuild_body,
			}
		}

		# Override things that may be unavailable, or may have portability
		# issues when running tests in exotic environments.
		#   prepstrip - bug #447810 (bash read builtin EINTR problem)
		true_symlinks = ("find", "prepstrip", "sed", "scanelf")
		true_binary = portage.process.find_binary("true")
		self.assertEqual(true_binary is None, False,
			"true command not found")

		dev_null = open(os.devnull, 'wb')
		playground = ResolverPlayground(ebuilds=ebuilds)
		try:
			QueryCommand._db = playground.trees
			root_config = playground.trees[playground.eroot]['root_config']
			portdb = root_config.trees["porttree"].dbapi
			settings = portage.config(clone=playground.settings)
			if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ:
				settings["__PORTAGE_TEST_HARDLINK_LOCKS"] = \
					os.environ["__PORTAGE_TEST_HARDLINK_LOCKS"]
				settings.backup_changes("__PORTAGE_TEST_HARDLINK_LOCKS")

			settings.features.add("noauto")
			settings.features.add("test")
			settings['PORTAGE_PYTHON'] = portage._python_interpreter
			settings['PORTAGE_QUIET'] = "1"
			settings['PYTHONDONTWRITEBYTECODE'] = os.environ.get("PYTHONDONTWRITEBYTECODE", "")

			fake_bin = os.path.join(settings["EPREFIX"], "bin")
			portage.util.ensure_dirs(fake_bin)
			for x in true_symlinks:
				os.symlink(true_binary, os.path.join(fake_bin, x))

			settings["__PORTAGE_TEST_PATH_OVERRIDE"] = fake_bin
			settings.backup_changes("__PORTAGE_TEST_PATH_OVERRIDE")

			cpv = 'app-misct/foo-1'
			metadata = dict(zip(Package.metadata_keys,
				portdb.aux_get(cpv, Package.metadata_keys)))

			pkg = Package(built=False, cpv=cpv, installed=False,
				metadata=metadata, root_config=root_config,
				type_name='ebuild')
			settings.setcpv(pkg)
			ebuildpath = portdb.findname(cpv)
			self.assertNotEqual(ebuildpath, None)

			for phase in ('info', 'nofetch',
				 'pretend', 'setup', 'unpack', 'prepare', 'configure',
				 'compile', 'test', 'install', 'qmerge', 'clean', 'merge'):

				pr, pw = os.pipe()

				producer = DoebuildProcess(doebuild_pargs=(ebuildpath, phase),
					doebuild_kwargs={"settings" : settings,
						"mydbapi": portdb, "tree": "porttree",
						"vartree": root_config.trees["vartree"],
						"fd_pipes": {
							1: dev_null.fileno(),
							2: dev_null.fileno(),
							output_fd: pw,
						},
						"prev_mtimes": {}})

				consumer = PipeReader(
					input_files={"producer" : pr})

				task_scheduler = TaskScheduler(iter([producer, consumer]),
					max_jobs=2)

				try:
					task_scheduler.start()
				finally:
					# PipeReader closes pr
					os.close(pw)

				task_scheduler.wait()
				output = portage._unicode_decode(
					consumer.getvalue()).rstrip("\n")

				if task_scheduler.returncode != os.EX_OK:
					portage.writemsg(output, noiselevel=-1)

				self.assertEqual(task_scheduler.returncode, os.EX_OK)

				if phase not in ('clean', 'merge', 'qmerge'):
					self.assertEqual(phase, output)

		finally:
			dev_null.close()
			playground.cleanup()
			QueryCommand._db = None
Esempio n. 17
0
    def testDoebuild(self):
        """
        Invoke portage.doebuild() with the fd_pipes parameter, and
        check that the expected output appears in the pipe. This
        functionality is not used by portage internally, but it is
        supported for API consumers (see bug #475812).
        """

        output_fd = 200
        ebuild_body = ["S=${WORKDIR}"]
        for phase_func in (
                "pkg_info",
                "pkg_nofetch",
                "pkg_pretend",
                "pkg_setup",
                "src_unpack",
                "src_prepare",
                "src_configure",
                "src_compile",
                "src_test",
                "src_install",
        ):
            ebuild_body.append(("%s() { echo ${EBUILD_PHASE}"
                                " 1>&%s; }") % (phase_func, output_fd))

        ebuild_body.append("")
        ebuild_body = "\n".join(ebuild_body)

        ebuilds = {
            "app-misct/foo-1": {
                "EAPI": "5",
                "MISC_CONTENT": ebuild_body,
            }
        }

        # Override things that may be unavailable, or may have portability
        # issues when running tests in exotic environments.
        #   prepstrip - bug #447810 (bash read builtin EINTR problem)
        true_symlinks = ("find", "prepstrip", "sed", "scanelf")
        true_binary = portage.process.find_binary("true")
        self.assertEqual(true_binary is None, False, "true command not found")

        dev_null = open(os.devnull, "wb")
        playground = ResolverPlayground(ebuilds=ebuilds)
        try:
            QueryCommand._db = playground.trees
            root_config = playground.trees[playground.eroot]["root_config"]
            portdb = root_config.trees["porttree"].dbapi
            settings = portage.config(clone=playground.settings)
            if "__PORTAGE_TEST_HARDLINK_LOCKS" in os.environ:
                settings["__PORTAGE_TEST_HARDLINK_LOCKS"] = os.environ[
                    "__PORTAGE_TEST_HARDLINK_LOCKS"]
                settings.backup_changes("__PORTAGE_TEST_HARDLINK_LOCKS")

            settings.features.add("noauto")
            settings.features.add("test")
            settings["PORTAGE_PYTHON"] = portage._python_interpreter
            settings["PORTAGE_QUIET"] = "1"
            settings["PYTHONDONTWRITEBYTECODE"] = os.environ.get(
                "PYTHONDONTWRITEBYTECODE", "")

            fake_bin = os.path.join(settings["EPREFIX"], "bin")
            portage.util.ensure_dirs(fake_bin)
            for x in true_symlinks:
                os.symlink(true_binary, os.path.join(fake_bin, x))

            settings["__PORTAGE_TEST_PATH_OVERRIDE"] = fake_bin
            settings.backup_changes("__PORTAGE_TEST_PATH_OVERRIDE")

            cpv = "app-misct/foo-1"
            metadata = dict(
                zip(Package.metadata_keys,
                    portdb.aux_get(cpv, Package.metadata_keys)))

            pkg = Package(
                built=False,
                cpv=cpv,
                installed=False,
                metadata=metadata,
                root_config=root_config,
                type_name="ebuild",
            )
            settings.setcpv(pkg)
            ebuildpath = portdb.findname(cpv)
            self.assertNotEqual(ebuildpath, None)

            for phase in (
                    "info",
                    "nofetch",
                    "pretend",
                    "setup",
                    "unpack",
                    "prepare",
                    "configure",
                    "compile",
                    "test",
                    "install",
                    "qmerge",
                    "clean",
                    "merge",
            ):

                pr, pw = os.pipe()

                producer = DoebuildProcess(
                    doebuild_pargs=(ebuildpath, phase),
                    doebuild_kwargs={
                        "settings": settings,
                        "mydbapi": portdb,
                        "tree": "porttree",
                        "vartree": root_config.trees["vartree"],
                        "fd_pipes": {
                            1: dev_null.fileno(),
                            2: dev_null.fileno(),
                            output_fd: pw,
                        },
                        "prev_mtimes": {},
                    },
                )

                consumer = PipeReader(input_files={"producer": pr})

                task_scheduler = TaskScheduler(iter([producer, consumer]),
                                               max_jobs=2)

                try:
                    task_scheduler.start()
                finally:
                    # PipeReader closes pr
                    os.close(pw)

                task_scheduler.wait()
                output = portage._unicode_decode(
                    consumer.getvalue()).rstrip("\n")

                if task_scheduler.returncode != os.EX_OK:
                    portage.writemsg(output, noiselevel=-1)

                self.assertEqual(task_scheduler.returncode, os.EX_OK)

                if phase not in ("clean", "merge", "qmerge"):
                    self.assertEqual(phase, output)

        finally:
            dev_null.close()
            playground.cleanup()
            QueryCommand._db = None
Esempio n. 18
0
    def _receive_reply(self, input_fd):

        start_time = time.time()

        pipe_reader = PipeReader(input_files={"input_fd": input_fd},
                                 scheduler=global_event_loop())
        pipe_reader.start()

        eof = pipe_reader.poll() is not None

        while not eof:
            pipe_reader._wait_loop(timeout=self._COMMUNICATE_RETRY_TIMEOUT)
            eof = pipe_reader.poll() is not None
            if not eof:
                if self._daemon_is_alive():
                    self._timeout_retry_msg(
                        start_time, portage.localization._('during read'))
                else:
                    pipe_reader.cancel()
                    self._no_daemon_msg()
                    return 2

        buf = pipe_reader.getvalue()

        retval = 2

        if not buf:

            portage.util.writemsg_level(
             "ebuild-ipc: %s\n" % \
             (portage.localization._('read failed'),),
             level=logging.ERROR, noiselevel=-1)

        else:

            try:
                reply = pickle.loads(buf)
            except SystemExit:
                raise
            except Exception as e:
                # The pickle module can raise practically
                # any exception when given corrupt data.
                portage.util.writemsg_level("ebuild-ipc: %s\n" % (e, ),
                                            level=logging.ERROR,
                                            noiselevel=-1)

            else:

                (out, err, retval) = reply

                if out:
                    portage.util.writemsg_stdout(out, noiselevel=-1)

                if err:
                    portage.util.writemsg(err, noiselevel=-1)

        return retval
Esempio n. 19
0
class AsyncFunction(ForkProcess):
    """
    Execute a function call in a fork, and retrieve the function
    return value via pickling/unpickling, accessible as the
    "result" attribute after the forked process has exited.
    """

    # NOTE: This class overrides the meaning of the SpawnProcess 'args'
    # attribute, and uses it to hold the positional arguments for the
    # 'target' function.
    __slots__ = (
        "kwargs",
        "result",
        "target",
        "_async_func_reader",
        "_async_func_reader_pw",
    )

    def _start(self):
        pr, pw = os.pipe()
        self.fd_pipes = {} if self.fd_pipes is None else self.fd_pipes
        self.fd_pipes[pw] = pw
        self._async_func_reader_pw = pw
        self._async_func_reader = PipeReader(
            input_files={"input": pr}, scheduler=self.scheduler
        )
        self._async_func_reader.addExitListener(self._async_func_reader_exit)
        self._async_func_reader.start()
        ForkProcess._start(self)
        os.close(pw)

    def _run(self):
        try:
            result = self.target(*(self.args or []), **(self.kwargs or {}))
            os.write(self._async_func_reader_pw, pickle.dumps(result))
        except Exception:
            traceback.print_exc()
            return 1

        return os.EX_OK

    def _async_waitpid(self):
        # Ignore this event, since we want to ensure that we exit
        # only after _async_func_reader_exit has reached EOF.
        if self._async_func_reader is None:
            ForkProcess._async_waitpid(self)

    def _async_func_reader_exit(self, pipe_reader):
        try:
            self.result = pickle.loads(pipe_reader.getvalue())
        except Exception:
            # The child process will have printed a traceback in this case,
            # and returned an unsuccessful returncode.
            pass
        self._async_func_reader = None
        if self.returncode is None:
            self._async_waitpid()
        else:
            self._unregister()
            self._async_wait()

    def _unregister(self):
        ForkProcess._unregister(self)

        pipe_reader = self._async_func_reader
        if pipe_reader is not None:
            self._async_func_reader = None
            pipe_reader.removeExitListener(self._async_func_reader_exit)
            pipe_reader.cancel()