Exemplo n.º 1
0
	def testFeaturesMutation(self):
		"""
		Test whether mutation of config.features updates the FEATURES
		variable and persists through config.regenerate() calls.
		"""
		playground = ResolverPlayground()
		try:
			settings = config(clone=playground.settings)

			settings.features.add('noclean')
			self.assertEqual('noclean' in settings['FEATURES'].split(), True)
			settings.regenerate()
			self.assertEqual('noclean' in settings['FEATURES'].split(),True)

			settings.features.discard('noclean')
			self.assertEqual('noclean' in settings['FEATURES'].split(), False)
			settings.regenerate()
			self.assertEqual('noclean' in settings['FEATURES'].split(), False)

			settings.features.add('noclean')
			self.assertEqual('noclean' in settings['FEATURES'].split(), True)
			settings.regenerate()
			self.assertEqual('noclean' in settings['FEATURES'].split(),True)
		finally:
			playground.cleanup()
Exemplo n.º 2
0
	def _load_config(self):
		env = {
			"ACCEPT_KEYWORDS": "x86",
			"PORTDIR": self.portdir,
			'PORTAGE_TMPDIR'       : os.path.join(self.eroot, 'var/tmp'),
		}

		# Pass along PORTAGE_USERNAME and PORTAGE_GRPNAME since they
		# need to be inherited by ebuild subprocesses.
		if 'PORTAGE_USERNAME' in os.environ:
			env['PORTAGE_USERNAME'] = os.environ['PORTAGE_USERNAME']
		if 'PORTAGE_GRPNAME' in os.environ:
			env['PORTAGE_GRPNAME'] = os.environ['PORTAGE_GRPNAME']

		settings = config(_eprefix=self.eprefix, env=env)
		settings.lock()

		trees = {
			self.root: {
					"vartree": vartree(settings=settings),
					"porttree": portagetree(self.root, settings=settings),
					"bintree": binarytree(self.root,
						os.path.join(self.eroot, "usr/portage/packages"),
						settings=settings)
				}
			}

		for root, root_trees in trees.items():
			settings = root_trees["vartree"].settings
			settings._init_dirs()
			setconfig = load_default_config(settings, root_trees)
			root_trees["root_config"] = RootConfig(settings, root_trees, setconfig)
		
		return settings, trees
Exemplo n.º 3
0
	def testSetCpv(self):
		"""
		Test the clone via constructor.
		"""

		ebuilds = {
			"dev-libs/A-1": {"IUSE": "static-libs"},
			"dev-libs/B-1": {"IUSE": "static-libs"},
		}

		env_files = {
			"A" : ("USE=\"static-libs\"",)
		}

		package_env = (
			"dev-libs/A A",
		)

		eprefix = normalize_path(tempfile.mkdtemp())
		playground = None
		try:
			user_config_dir = os.path.join(eprefix, USER_CONFIG_PATH)
			os.makedirs(user_config_dir)

			with io.open(os.path.join(user_config_dir, "package.env"),
				mode='w', encoding=_encodings['content']) as f:
				for line in package_env:
					f.write(line + "\n")

			env_dir = os.path.join(user_config_dir, "env")
			os.makedirs(env_dir)
			for k, v in env_files.items():
				with io.open(os.path.join(env_dir, k), mode='w',
					encoding=_encodings['content']) as f:
					for line in v:
						f.write(line + "\n")

			playground = ResolverPlayground(eprefix=eprefix, ebuilds=ebuilds)
			settings = config(clone=playground.settings)

			result = playground.run(["=dev-libs/A-1"])
			pkg, existing_node = result.depgraph._select_package(
				playground.eroot, Atom("=dev-libs/A-1"))
			settings.setcpv(pkg)
			self.assertTrue("static-libs" in
				settings["PORTAGE_USE"].split())

			# Test bug #522362, where a USE=static-libs package.env
			# setting leaked from one setcpv call to the next.
			pkg, existing_node = result.depgraph._select_package(
				playground.eroot, Atom("=dev-libs/B-1"))
			settings.setcpv(pkg)
			self.assertTrue("static-libs" not in
				settings["PORTAGE_USE"].split())

		finally:
			if playground is None:
				shutil.rmtree(eprefix)
			else:
				playground.cleanup()
Exemplo n.º 4
0
def getmaskingstatus(mycpv, settings=None, portdb=None, myrepo=None):
	if settings is None:
		settings = config(clone=portage.settings)
	if portdb is None:
		portdb = portage.portdb

	return [mreason.message for \
		mreason in _getmaskingstatus(mycpv, settings, portdb,myrepo)]
Exemplo n.º 5
0
	def testFakedbapi(self):
		packages = (
			("sys-apps/portage-2.1.10", {
				"EAPI"         : "2",
				"IUSE"         : "ipc doc",
				"repository"   : "gentoo",
				"SLOT"         : "0",
				"USE"          : "ipc missing-iuse",
			}),
			("virtual/package-manager-0", {
				"EAPI"         : "0",
				"repository"   : "gentoo",
				"SLOT"         : "0",
			}),
		)

		match_tests = (
			("sys-apps/portage:0[ipc]",             ["sys-apps/portage-2.1.10"]),
			("sys-apps/portage:0[-ipc]",            []),
			("sys-apps/portage:0[doc]",             []),
			("sys-apps/portage:0[-doc]",            ["sys-apps/portage-2.1.10"]),
			("sys-apps/portage:0",                  ["sys-apps/portage-2.1.10"]),
			("sys-apps/portage:0[missing-iuse]",    []),
			("sys-apps/portage:0[-missing-iuse]",   []),
			("sys-apps/portage:0::gentoo[ipc]",     ["sys-apps/portage-2.1.10"]),
			("sys-apps/portage:0::multilib[ipc]",   []),
			("virtual/package-manager",             ["virtual/package-manager-0"]),
		)

		tempdir = tempfile.mkdtemp()
		try:
			test_repo = os.path.join(tempdir, "var", "repositories", "test_repo")
			os.makedirs(os.path.join(test_repo, "profiles"))
			with open(os.path.join(test_repo, "profiles", "repo_name"), "w") as f:
				f.write("test_repo")
			env = {
				"PORTAGE_REPOSITORIES": "[DEFAULT]\nmain-repo = test_repo\n[test_repo]\nlocation = %s" % test_repo
			}

			# Tests may override portage.const.EPREFIX in order to
			# simulate a prefix installation. It's reasonable to do
			# this because tests should be self-contained such that
			# the "real" value of portage.const.EPREFIX is entirely
			# irrelevant (see bug #492932).
			portage.const.EPREFIX = tempdir

			fakedb = fakedbapi(settings=config(config_profile_path="",
				env=env, eprefix=tempdir))
			for cpv, metadata in packages:
				fakedb.cpv_inject(cpv, metadata=metadata)

			for atom, expected_result in match_tests:
				result = fakedb.match(atom)
				self.assertEqual(fakedb.match(atom), expected_result,
					"fakedb.match('%s') = %s != %s" %
					(atom, result, expected_result))
		finally:
			shutil.rmtree(tempdir)
	def testDoebuildSpawn(self):
		playground = ResolverPlayground()
		try:
			settings = config(clone=playground.settings)
			cpv = 'sys-apps/portage-2.1'
			metadata = {
				'EAPI'      : '2',
				'INHERITED' : 'python eutils',
				'IUSE'      : 'build doc epydoc python3 selinux',
				'LICENSE'   : 'GPL-2',
				'PROVIDE'   : 'virtual/portage',
				'RDEPEND'   : '>=app-shells/bash-3.2_p17 >=dev-lang/python-2.6',
				'SLOT'      : '0',
			}
			root_config = playground.trees[playground.eroot]['root_config']
			pkg = Package(built=False, cpv=cpv, installed=False,
				metadata=metadata, root_config=root_config,
				type_name='ebuild')
			settings.setcpv(pkg)
			settings['PORTAGE_PYTHON'] = _python_interpreter
			settings['PORTAGE_BUILDDIR'] = os.path.join(
				settings['PORTAGE_TMPDIR'], cpv)
			settings['T'] = os.path.join(
				settings['PORTAGE_BUILDDIR'], 'temp')
			for x in ('PORTAGE_BUILDDIR', 'T'):
				os.makedirs(settings[x])
			# Create a fake environment, to pretend as if the ebuild
			# has been sourced already.
			open(os.path.join(settings['T'], 'environment'), 'wb').close()

			scheduler = PollScheduler().sched_iface
			for phase in ('_internal_test',):

				# Test EbuildSpawnProcess by calling doebuild.spawn() with
				# returnpid=False. This case is no longer used by portage
				# internals since EbuildPhase is used instead and that passes
				# returnpid=True to doebuild.spawn().
				rval = doebuild_spawn("%s %s" % (_shell_quote(
					os.path.join(settings["PORTAGE_BIN_PATH"],
					os.path.basename(EBUILD_SH_BINARY))), phase),
					settings, free=1)
				self.assertEqual(rval, os.EX_OK)

				ebuild_phase = EbuildPhase(background=False,
					phase=phase, scheduler=scheduler,
					settings=settings)
				ebuild_phase.start()
				ebuild_phase.wait()
				self.assertEqual(ebuild_phase.returncode, os.EX_OK)

			ebuild_phase = MiscFunctionsProcess(background=False,
				commands=['success_hooks'],
				scheduler=scheduler, settings=settings)
			ebuild_phase.start()
			ebuild_phase.wait()
			self.assertEqual(ebuild_phase.returncode, os.EX_OK)
		finally:
			playground.cleanup()
Exemplo n.º 7
0
    def testClone(self):
        """
		Test the clone via constructor.
		"""

        ebuilds = {"dev-libs/A-1": {}}

        playground = ResolverPlayground(ebuilds=ebuilds)
        try:
            settings = config(clone=playground.settings)
            result = playground.run(["=dev-libs/A-1"])
            pkg, existing_node = result.depgraph._select_package(playground.eroot, "=dev-libs/A-1")
            settings.setcpv(pkg)

            # clone after setcpv tests deepcopy of LazyItemsDict
            settings2 = config(clone=settings)
        finally:
            playground.cleanup()
Exemplo n.º 8
0
	def _create_ebuild_manifests(self, ebuilds):
		for cpv in ebuilds:
			a = Atom("=" + cpv)
			ebuild_dir = os.path.join(self.portdir, a.cp)
			ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild")

			portage.util.noiselimit = -1
			tmpsettings = config(clone=self.settings)
			portdb = self.trees[self.root]["porttree"].dbapi
			portage.doebuild(ebuild_path, "digest", self.root, tmpsettings,
				tree="porttree", mydbapi=portdb)
			portage.util.noiselimit = 0
Exemplo n.º 9
0
	def _start(self):
		settings = self.settings
		if settings is None:
			settings = self.portdb.settings

		if 'PORTAGE_PARALLEL_FETCHONLY' in settings:
			# parallel-fetch mode
			self.returncode = os.EX_OK
			self._async_wait()
			return

		# Prevent temporary config changes from interfering
		# with config instances that are reused.
		settings = self.settings = config(clone=settings)

		# We must create our private PORTAGE_TMPDIR before calling
		# doebuild_environment(), since lots of variables such
		# as PORTAGE_BUILDDIR refer to paths inside PORTAGE_TMPDIR.
		portage_tmpdir = settings.get('PORTAGE_TMPDIR')
		if not portage_tmpdir or not os.access(portage_tmpdir, os.W_OK):
			portage_tmpdir = None
		private_tmpdir = self._private_tmpdir = tempfile.mkdtemp(
			dir=portage_tmpdir)
		settings['PORTAGE_TMPDIR'] = private_tmpdir
		settings.backup_changes('PORTAGE_TMPDIR')
		# private temp dir was just created, so it's not locked yet
		settings.pop('PORTAGE_BUILDDIR_LOCKED', None)

		doebuild_environment(self.ebuild_path, 'nofetch',
			settings=settings, db=self.portdb)
		restrict = settings['PORTAGE_RESTRICT'].split()
		defined_phases = settings['DEFINED_PHASES'].split()
		if not defined_phases:
			# When DEFINED_PHASES is undefined, assume all
			# phases are defined.
			defined_phases = EBUILD_PHASES

		if 'fetch' not in restrict and \
			'nofetch' not in defined_phases:
			self.returncode = os.EX_OK
			self._async_wait()
			return

		prepare_build_dirs(settings=settings)

		ebuild_phase = EbuildPhase(background=self.background,
			phase='nofetch',
			scheduler=self.scheduler,
			fd_pipes=self.fd_pipes, settings=settings)

		self._start_task(ebuild_phase, self._nofetch_exit)
Exemplo n.º 10
0
	def testFakedbapi(self):
		packages = (
			("sys-apps/portage-2.1.10", {
				"EAPI"         : "2",
				"IUSE"         : "ipc doc",
				"repository"   : "gentoo",
				"SLOT"         : "0",
				"USE"          : "ipc missing-iuse",
			}),
			("virtual/package-manager-0", {
				"EAPI"         : "0",
				"repository"   : "gentoo",
				"SLOT"         : "0",
			}),
		)

		match_tests = (
			("sys-apps/portage:0[ipc]",             ["sys-apps/portage-2.1.10"]),
			("sys-apps/portage:0[-ipc]",            []),
			("sys-apps/portage:0[doc]",             []),
			("sys-apps/portage:0[-doc]",            ["sys-apps/portage-2.1.10"]),
			("sys-apps/portage:0",                  ["sys-apps/portage-2.1.10"]),
			("sys-apps/portage:0[missing-iuse]",    []),
			("sys-apps/portage:0[-missing-iuse]",   []),
			("sys-apps/portage:0::gentoo[ipc]",     ["sys-apps/portage-2.1.10"]),
			("sys-apps/portage:0::multilib[ipc]",   []),
			("virtual/package-manager",             ["virtual/package-manager-0"]),
		)

		tempdir = tempfile.mkdtemp()
		try:
			portdir = os.path.join(tempdir, "usr/portage")
			os.makedirs(portdir)
			env = {
				"PORTDIR": portdir,
			}
			fakedb = fakedbapi(settings=config(config_profile_path="",
				env=env, eprefix=tempdir))
			for cpv, metadata in packages:
				fakedb.cpv_inject(cpv, metadata=metadata)

			for atom, expected_result in match_tests:
				result = fakedb.match(atom)
				self.assertEqual(fakedb.match(atom), expected_result,
					"fakedb.match('%s') = %s != %s" %
					(atom, result, expected_result))
		finally:
			shutil.rmtree(tempdir)
Exemplo n.º 11
0
    def testHookDirectory(self):
        """
		Tests to be sure a hook loads and reads the right settings
		Based on test_PackageKeywordsFile.py
		"""

        self.tmp_dir_path = self.BuildTmp("/etc/portage/hooks/test.d")
        try:
            settings = config()
            settings["PORTAGE_CONFIGROOT"] = self.tmp_dir_path
            settings["FEATURES"] += " hooks"
            hooks = HookDirectory(phase="test", settings=settings)
            hooks.execute()
            self.assert_(settings["hookonlytest"] == "")
        finally:
            rmtree(self.tmp_dir_path)
Exemplo n.º 12
0
def env_update(makelinks=1, target_root=None, prev_mtimes=None, contents=None,
	env=None, writemsg_level=None, vardbapi=None):
	"""
	Parse /etc/env.d and use it to generate /etc/profile.env, csh.env,
	ld.so.conf, and prelink.conf. Finally, run ldconfig. When ldconfig is
	called, its -X option will be used in order to avoid potential
	interference with installed soname symlinks that are required for
	correct operation of FEATURES=preserve-libs for downgrade operations.
	It's not necessary for ldconfig to create soname symlinks, since
	portage will use NEEDED.ELF.2 data to automatically create them
	after src_install if they happen to be missing.
	@param makelinks: True if ldconfig should be called, False otherwise
	@param target_root: root that is passed to the ldconfig -r option,
		defaults to portage.settings["ROOT"].
	@type target_root: String (Path)
	"""
	if vardbapi is None:
		if isinstance(env, config):
			vardbapi = vartree(settings=env).dbapi
		else:
			if target_root is None:
				eprefix = portage.settings["EPREFIX"]
				target_root = portage.settings["ROOT"]
				target_eroot = portage.settings['EROOT']
			else:
				eprefix = portage.const.EPREFIX
				target_eroot = os.path.join(target_root,
					eprefix.lstrip(os.sep))
				target_eroot = target_eroot.rstrip(os.sep) + os.sep
			if hasattr(portage, "db") and target_eroot in portage.db:
				vardbapi = portage.db[target_eroot]["vartree"].dbapi
			else:
				settings = config(config_root=target_root,
					target_root=target_root, eprefix=eprefix)
				target_root = settings["ROOT"]
				if env is None:
					env = settings
				vardbapi = vartree(settings=settings).dbapi

	# Lock the config memory file to prevent symlink creation
	# in merge_contents from overlapping with env-update.
	vardbapi._fs_lock()
	try:
		return _env_update(makelinks, target_root, prev_mtimes, contents,
			env, writemsg_level)
	finally:
		vardbapi._fs_unlock()
Exemplo n.º 13
0
	def _create_ebuild_manifests(self, ebuilds):
		tmpsettings = config(clone=self.settings)
		tmpsettings['PORTAGE_QUIET'] = '1'
		for cpv in ebuilds:
			a = Atom("=" + cpv, allow_repo=True)
			repo = a.repo
			if repo is None:
				repo = "test_repo"

			repo_dir = self._get_repo_dir(repo)
			ebuild_dir = os.path.join(repo_dir, a.cp)
			ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild")

			portdb = self.trees[self.eroot]["porttree"].dbapi
			tmpsettings['O'] = ebuild_dir
			if not digestgen(mysettings=tmpsettings, myportdb=portdb):
				raise AssertionError('digest creation failed for %s' % ebuild_path)
Exemplo n.º 14
0
   def __init__(self, root = None, portage_arch = None):
      """Constructor.

      str root
         Portage root directory; defaults to Portage’s ${ROOT}.
      str portage_arch
         Portage architecture; defaults to Portage’s ${ARCH}.
      """

      if root:
         # Set this now to override Portage’s default root.
         os.environ['ROOT'] = root
      self._category = None # Set by make_package_name()
      self._portage_config = portage_config.config()
      if not root:
         # Set this now to override the null root with Portage’s default root.
         os.environ['ROOT'] = root = self._portage_config['ROOT']
      self._cross_compiler_prefix = None
      self._dev_null = open(os.devnull, 'w')
      self._ebuild_file_path = None
      self._ebuild_pkg_root = None
      self._indent = ''
      self._irf_compressor = None
      self._irf_archive_path = None
      self._irf_source_path = None
      self._kernel_release = None # Set by set_sources()
      self._kernel_version = None # Set by set_sources()
      self._kmake_args = ['make']
      self._kmake_args.extend(shlex.split(self._portage_config['MAKEOPTS']))
      self._kmake_env = dict(os.environ)
      if not portage_arch:
         portage_arch = self._portage_config['ARCH']
      self._kmake_env['ARCH'] = self._portage_arch_to_kernel_arch.get(
         portage_arch, portage_arch
      )
      self._module_packages = None # Set by build_kernel()
      self._package_name = None # Set by make_package_name()
      self._package_version = None # Set by make_package_name()
      self._root = root
      self._source_path = None
      self._src_config_path = None
      self._src_image_path = None
Exemplo n.º 15
0
    def testFakedbapi(self):
        packages = (
            (
                "sys-apps/portage-2.1.10",
                {"EAPI": "2", "IUSE": "ipc doc", "repository": "gentoo", "SLOT": "0", "USE": "ipc missing-iuse"},
            ),
            ("virtual/package-manager-0", {"EAPI": "0", "repository": "gentoo", "SLOT": "0"}),
        )

        match_tests = (
            ("sys-apps/portage:0[ipc]", ["sys-apps/portage-2.1.10"]),
            ("sys-apps/portage:0[-ipc]", []),
            ("sys-apps/portage:0[doc]", []),
            ("sys-apps/portage:0[-doc]", ["sys-apps/portage-2.1.10"]),
            ("sys-apps/portage:0", ["sys-apps/portage-2.1.10"]),
            ("sys-apps/portage:0[missing-iuse]", []),
            ("sys-apps/portage:0[-missing-iuse]", []),
            ("sys-apps/portage:0::gentoo[ipc]", ["sys-apps/portage-2.1.10"]),
            ("sys-apps/portage:0::multilib[ipc]", []),
            ("virtual/package-manager", ["virtual/package-manager-0"]),
        )

        tempdir = tempfile.mkdtemp()
        try:
            test_repo = os.path.join(tempdir, "var", "repositories", "test_repo")
            os.makedirs(os.path.join(test_repo, "profiles"))
            with open(os.path.join(test_repo, "profiles", "repo_name"), "w") as f:
                f.write("test_repo")
            env = {"PORTAGE_REPOSITORIES": "[DEFAULT]\nmain-repo = test_repo\n[test_repo]\nlocation = %s" % test_repo}
            fakedb = fakedbapi(settings=config(config_profile_path="", env=env, eprefix=tempdir))
            for cpv, metadata in packages:
                fakedb.cpv_inject(cpv, metadata=metadata)

            for atom, expected_result in match_tests:
                result = fakedb.match(atom)
                self.assertEqual(
                    fakedb.match(atom),
                    expected_result,
                    "fakedb.match('%s') = %s != %s" % (atom, result, expected_result),
                )
        finally:
            shutil.rmtree(tempdir)
Exemplo n.º 16
0
	def testFeaturesMutation(self):
		"""
		Test whether mutation of config.features updates the FEATURES
		variable and persists through config.regenerate() calls. Also
		verify that features_set._prune_overrides() works correctly.
		"""
		playground = ResolverPlayground()
		try:
			settings = config(clone=playground.settings)

			settings.features.add('noclean')
			self.assertEqual('noclean' in settings['FEATURES'].split(), True)
			settings.regenerate()
			self.assertEqual('noclean' in settings['FEATURES'].split(), True)

			settings.features.discard('noclean')
			self.assertEqual('noclean' in settings['FEATURES'].split(), False)
			settings.regenerate()
			self.assertEqual('noclean' in settings['FEATURES'].split(), False)

			settings.features.add('noclean')
			self.assertEqual('noclean' in settings['FEATURES'].split(), True)
			settings.regenerate()
			self.assertEqual('noclean' in settings['FEATURES'].split(), True)

			# before: ['noclean', '-noclean', 'noclean']
			settings.features._prune_overrides()
			#  after: ['noclean']
			self.assertEqual(settings._features_overrides.count('noclean'), 1)
			self.assertEqual(settings._features_overrides.count('-noclean'), 0)

			settings.features.remove('noclean')

			# before: ['noclean', '-noclean']
			settings.features._prune_overrides()
			#  after: ['-noclean']
			self.assertEqual(settings._features_overrides.count('noclean'), 0)
			self.assertEqual(settings._features_overrides.count('-noclean'), 1)
		finally:
			playground.cleanup()
Exemplo n.º 17
0
   def __init__(self, sRoot = None, sPArch = None):
      """Constructor.

      str sRoot
         Portage root directory; defaults to Portage’s ${ROOT}.
      str sPArch
         Portage architecture; defaults to Portage’s ${ARCH}.
      """

      if sRoot:
         # Set this now to override Portage’s default root.
         os.environ['ROOT'] = sRoot
      self._m_sCategory = None # Set by make_package_name()
      self._m_pconfig = portage_config.config()
      if not sRoot:
         # Set this now to override the null sRoot with Portage’s default root.
         os.environ['ROOT'] = sRoot = self._m_pconfig['ROOT']
      self._m_sCrossCompiler = None
      self._m_sEbuildFilePath = None
      self._m_sEbuildPkgRoot = None
      self._m_sIndent = ''
      self._m_comprIrf = None
      self._m_sIrfArchivePath = None
      self._m_sIrfSourcePath = None
      self._m_sKernelRelease = None # Set by set_sources()
      self._m_sKernelVersion = None # Set by set_sources()
      self._m_listKMakeArgs = ['make']
      self._m_listKMakeArgs.extend(shlex.split(self._m_pconfig['MAKEOPTS']))
      self._m_dictKMakeEnv = dict(os.environ)
      if not sPArch:
         sPArch = self._m_pconfig['ARCH']
      self._m_dictKMakeEnv['ARCH'] = self._smc_dictPArchToKArch.get(sPArch, sPArch)
      self._m_tplModulePackages = None # Set by build_kernel()
      self._m_fileNullOut = open(os.devnull, 'w')
      self._m_sPackageName = None # Set by make_package_name()
      self._m_sPackageVersion = None # Set by make_package_name()
      self._m_sRoot = sRoot
      self._m_sSourcePath = None
      self._m_sSrcConfigPath = None
      self._m_sSrcImagePath = None
Exemplo n.º 18
0
def digestgen(myarchives=None, mysettings=None,
	overwrite=None, manifestonly=None, myportdb=None):
	"""
	Generates a digest file if missing. Fetches files if necessary.
	NOTE: myarchives and mysettings used to be positional arguments,
		so their order must be preserved for backward compatibility.
	@param mysettings: the ebuild config (mysettings["O"] must correspond
		to the ebuild's parent directory)
	@type mysettings: config
	@param myportdb: a portdbapi instance
	@type myportdb: portdbapi
	@rtype: int
	@returns: 1 on success and 0 on failure
	"""
	if mysettings is None:
		raise TypeError("portage.digestgen(): missing" + \
			" required 'mysettings' parameter")
	if myportdb is None:
		warnings.warn("portage.digestgen() called without 'myportdb' parameter",
			DeprecationWarning, stacklevel=2)
		myportdb = portage.portdb
	if overwrite is not None:
		warnings.warn("portage.digestgen() called with " + \
			"deprecated 'overwrite' parameter",
			DeprecationWarning, stacklevel=2)
	if manifestonly is not None:
		warnings.warn("portage.digestgen() called with " + \
			"deprecated 'manifestonly' parameter",
			DeprecationWarning, stacklevel=2)

	try:
		portage._doebuild_manifest_exempt_depend += 1
		distfiles_map = {}
		fetchlist_dict = FetchlistDict(mysettings["O"], mysettings, myportdb)
		for cpv in fetchlist_dict:
			try:
				for myfile in fetchlist_dict[cpv]:
					distfiles_map.setdefault(myfile, []).append(cpv)
			except InvalidDependString as e:
				writemsg("!!! %s\n" % str(e), noiselevel=-1)
				del e
				return 0
		mytree = os.path.dirname(os.path.dirname(mysettings["O"]))
		manifest1_compat = False
		mf = Manifest(mysettings["O"], mysettings["DISTDIR"],
			fetchlist_dict=fetchlist_dict, manifest1_compat=manifest1_compat)
		# Don't require all hashes since that can trigger excessive
		# fetches when sufficient digests already exist.  To ease transition
		# while Manifest 1 is being removed, only require hashes that will
		# exist before and after the transition.
		required_hash_types = set()
		required_hash_types.add("size")
		required_hash_types.add(MANIFEST2_REQUIRED_HASH)
		dist_hashes = mf.fhashdict.get("DIST", {})

		# To avoid accidental regeneration of digests with the incorrect
		# files (such as partially downloaded files), trigger the fetch
		# code if the file exists and it's size doesn't match the current
		# manifest entry. If there really is a legitimate reason for the
		# digest to change, `ebuild --force digest` can be used to avoid
		# triggering this code (or else the old digests can be manually
		# removed from the Manifest).
		missing_files = []
		for myfile in distfiles_map:
			myhashes = dist_hashes.get(myfile)
			if not myhashes:
				try:
					st = os.stat(os.path.join(mysettings["DISTDIR"], myfile))
				except OSError:
					st = None
				if st is None or st.st_size == 0:
					missing_files.append(myfile)
				continue
			size = myhashes.get("size")

			try:
				st = os.stat(os.path.join(mysettings["DISTDIR"], myfile))
			except OSError as e:
				if e.errno != errno.ENOENT:
					raise
				del e
				if size == 0:
					missing_files.append(myfile)
					continue
				if required_hash_types.difference(myhashes):
					missing_files.append(myfile)
					continue
			else:
				if st.st_size == 0 or size is not None and size != st.st_size:
					missing_files.append(myfile)
					continue

		if missing_files:
				mytree = os.path.realpath(os.path.dirname(
					os.path.dirname(mysettings["O"])))
				fetch_settings = config(clone=mysettings)
				debug = mysettings.get("PORTAGE_DEBUG") == "1"
				for myfile in missing_files:
					uris = set()
					for cpv in distfiles_map[myfile]:
						myebuild = os.path.join(mysettings["O"],
							catsplit(cpv)[1] + ".ebuild")
						# for RESTRICT=fetch, mirror, etc...
						doebuild_environment(myebuild, "fetch",
							mysettings["ROOT"], fetch_settings,
							debug, 1, myportdb)
						uris.update(myportdb.getFetchMap(
							cpv, mytree=mytree)[myfile])

					fetch_settings["A"] = myfile # for use by pkg_nofetch()

					try:
						st = os.stat(os.path.join(
							mysettings["DISTDIR"],myfile))
					except OSError:
						st = None

					if not fetch({myfile : uris}, fetch_settings):
						writemsg(_("!!! Fetch failed for %s, can't update "
							"Manifest\n") % myfile, noiselevel=-1)
						if myfile in dist_hashes and \
							st is not None and st.st_size > 0:
							# stat result is obtained before calling fetch(),
							# since fetch may rename the existing file if the
							# digest does not match.
							writemsg(_("!!! If you would like to "
								"forcefully replace the existing "
								"Manifest entry\n!!! for %s, use "
								"the following command:\n") % myfile + \
								"!!!    " + colorize("INFORM",
								"ebuild --force %s manifest" % \
								os.path.basename(myebuild)) + "\n",
								noiselevel=-1)
						return 0
		writemsg_stdout(_(">>> Creating Manifest for %s\n") % mysettings["O"])
		try:
			mf.create(assumeDistHashesSometimes=True,
				assumeDistHashesAlways=(
				"assume-digests" in mysettings.features))
		except FileNotFound as e:
			writemsg(_("!!! File %s doesn't exist, can't update "
				"Manifest\n") % e, noiselevel=-1)
			return 0
		except PortagePackageException as e:
			writemsg(("!!! %s\n") % (e,), noiselevel=-1)
			return 0
		try:
			mf.write(sign=False)
		except PermissionDenied as e:
			writemsg(_("!!! Permission Denied: %s\n") % (e,), noiselevel=-1)
			return 0
		if "assume-digests" not in mysettings.features:
			distlist = list(mf.fhashdict.get("DIST", {}))
			distlist.sort()
			auto_assumed = []
			for filename in distlist:
				if not os.path.exists(
					os.path.join(mysettings["DISTDIR"], filename)):
					auto_assumed.append(filename)
			if auto_assumed:
				mytree = os.path.realpath(
					os.path.dirname(os.path.dirname(mysettings["O"])))
				cp = os.path.sep.join(mysettings["O"].split(os.path.sep)[-2:])
				pkgs = myportdb.cp_list(cp, mytree=mytree)
				pkgs.sort()
				writemsg_stdout("  digest.assumed" + colorize("WARN",
					str(len(auto_assumed)).rjust(18)) + "\n")
				for pkg_key in pkgs:
					fetchlist = myportdb.getFetchMap(pkg_key, mytree=mytree)
					pv = pkg_key.split("/")[1]
					for filename in auto_assumed:
						if filename in fetchlist:
							writemsg_stdout(
								"   %s::%s\n" % (pv, filename))
		return 1
	finally:
		portage._doebuild_manifest_exempt_depend -= 1
Exemplo n.º 19
0
	def testDoebuildSpawn(self):

		ebuild_body = textwrap.dedent("""
			pkg_nofetch() { : ; }
		""")

		ebuilds = {
			'sys-apps/portage-2.1': {
				'EAPI'      : '2',
				'IUSE'      : 'build doc epydoc python3 selinux',
				'KEYWORDS'  : 'x86',
				'LICENSE'   : 'GPL-2',
				'RDEPEND'   : '>=app-shells/bash-3.2_p17 >=dev-lang/python-2.6',
				'SLOT'      : '0',
				"MISC_CONTENT": ebuild_body,
			}
		}

		playground = ResolverPlayground(ebuilds=ebuilds)
		try:
			root_config = playground.trees[playground.eroot]['root_config']
			portdb = root_config.trees["porttree"].dbapi
			settings = 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")

			cpv = 'sys-apps/portage-2.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)
			settings['PORTAGE_PYTHON'] = _python_interpreter
			settings['PORTAGE_BUILDDIR'] = os.path.join(
				settings['PORTAGE_TMPDIR'], cpv)
			settings['PYTHONDONTWRITEBYTECODE'] = os.environ.get('PYTHONDONTWRITEBYTECODE', '')
			settings['T'] = os.path.join(
				settings['PORTAGE_BUILDDIR'], 'temp')
			for x in ('PORTAGE_BUILDDIR', 'T'):
				os.makedirs(settings[x])
			# Create a fake environment, to pretend as if the ebuild
			# has been sourced already.
			open(os.path.join(settings['T'], 'environment'), 'wb').close()

			scheduler = SchedulerInterface(global_event_loop())
			for phase in ('_internal_test',):

				# Test EbuildSpawnProcess by calling doebuild.spawn() with
				# returnpid=False. This case is no longer used by portage
				# internals since EbuildPhase is used instead and that passes
				# returnpid=True to doebuild.spawn().
				rval = doebuild_spawn("%s %s" % (_shell_quote(
					os.path.join(settings["PORTAGE_BIN_PATH"],
					os.path.basename(EBUILD_SH_BINARY))), phase),
					settings, free=1)
				self.assertEqual(rval, os.EX_OK)

				ebuild_phase = EbuildPhase(background=False,
					phase=phase, scheduler=scheduler,
					settings=settings)
				ebuild_phase.start()
				ebuild_phase.wait()
				self.assertEqual(ebuild_phase.returncode, os.EX_OK)

			ebuild_phase = MiscFunctionsProcess(background=False,
				commands=['success_hooks'],
				scheduler=scheduler, settings=settings)
			ebuild_phase.start()
			ebuild_phase.wait()
			self.assertEqual(ebuild_phase.returncode, os.EX_OK)

			spawn_nofetch(portdb, portdb.findname(cpv), settings=settings)
		finally:
			playground.cleanup()
def getmaskingstatus(mycpv, settings=None, portdb=None):
	if settings is None:
		settings = config(clone=portage.settings)
	if portdb is None:
		portdb = portage.portdb

	metadata = None
	installed = False
	if not isinstance(mycpv, basestring):
		# emerge passed in a Package instance
		pkg = mycpv
		mycpv = pkg.cpv
		metadata = pkg.metadata
		installed = pkg.installed

	mysplit = catpkgsplit(mycpv)
	if not mysplit:
		raise ValueError(_("invalid CPV: %s") % mycpv)
	if metadata is None:
		db_keys = list(portdb._aux_cache_keys)
		try:
			metadata = dict(zip(db_keys, portdb.aux_get(mycpv, db_keys)))
		except KeyError:
			if not portdb.cpv_exists(mycpv):
				raise
			return ["corruption"]
		if "?" in metadata["LICENSE"]:
			settings.setcpv(mycpv, mydb=metadata)
			metadata["USE"] = settings["PORTAGE_USE"]
		else:
			metadata["USE"] = ""

	rValue = []

	# profile checking
	if settings._getProfileMaskAtom(mycpv, metadata):
		rValue.append("profile")

	# package.mask checking
	if settings._getMaskAtom(mycpv, metadata):
		rValue.append("package.mask")

	# keywords checking
	eapi = metadata["EAPI"]
	mygroups = settings._getKeywords(mycpv, metadata)
	licenses = metadata["LICENSE"]
	properties = metadata["PROPERTIES"]
	if eapi.startswith("-"):
		eapi = eapi[1:]
	if not eapi_is_supported(eapi):
		return ["EAPI %s" % eapi]
	elif _eapi_is_deprecated(eapi) and not installed:
		return ["EAPI %s" % eapi]
	egroups = settings.configdict["backupenv"].get(
		"ACCEPT_KEYWORDS", "").split()
	pgroups = settings["ACCEPT_KEYWORDS"].split()
	myarch = settings["ARCH"]
	if pgroups and myarch not in pgroups:
		"""For operating systems other than Linux, ARCH is not necessarily a
		valid keyword."""
		myarch = pgroups[0].lstrip("~")

	cp = cpv_getkey(mycpv)
	pkgdict = settings.pkeywordsdict.get(cp)
	matches = False
	if pkgdict:
		cpv_slot_list = ["%s:%s" % (mycpv, metadata["SLOT"])]
		for atom, pkgkeywords in pkgdict.items():
			if match_from_list(atom, cpv_slot_list):
				matches = True
				pgroups.extend(pkgkeywords)
	if matches or egroups:
		pgroups.extend(egroups)
		inc_pgroups = set()
		for x in pgroups:
			if x.startswith("-"):
				if x == "-*":
					inc_pgroups.clear()
				else:
					inc_pgroups.discard(x[1:])
			else:
				inc_pgroups.add(x)
		pgroups = inc_pgroups
		del inc_pgroups

	kmask = "missing"

	if '**' in pgroups:
		kmask = None
	else:
		for keyword in pgroups:
			if keyword in mygroups:
				kmask = None
				break

	if kmask:
		for gp in mygroups:
			if gp=="*":
				kmask=None
				break
			elif gp=="-"+myarch and myarch in pgroups:
				kmask="-"+myarch
				break
			elif gp=="~"+myarch and myarch in pgroups:
				kmask="~"+myarch
				break

	try:
		missing_licenses = settings._getMissingLicenses(mycpv, metadata)
		if missing_licenses:
			allowed_tokens = set(["||", "(", ")"])
			allowed_tokens.update(missing_licenses)
			license_split = licenses.split()
			license_split = [x for x in license_split \
				if x in allowed_tokens]
			msg = license_split[:]
			msg.append("license(s)")
			rValue.append(" ".join(msg))
	except portage.exception.InvalidDependString as e:
		rValue.append("LICENSE: "+str(e))

	try:
		missing_properties = settings._getMissingProperties(mycpv, metadata)
		if missing_properties:
			allowed_tokens = set(["||", "(", ")"])
			allowed_tokens.update(missing_properties)
			properties_split = properties.split()
			properties_split = [x for x in properties_split \
					if x in allowed_tokens]
			msg = properties_split[:]
			msg.append("properties")
			rValue.append(" ".join(msg))
	except portage.exception.InvalidDependString as e:
		rValue.append("PROPERTIES: "+str(e))

	# Only show KEYWORDS masks for installed packages
	# if they're not masked for any other reason.
	if kmask and (not installed or not rValue):
		rValue.append(kmask+" keyword")

	return rValue
Exemplo n.º 21
0
	def testEbuildFetch(self):

		distfiles = {
			'bar': b'bar\n',
			'foo': b'foo\n',
		}

		ebuilds = {
			'dev-libs/A-1': {
				'EAPI': '7',
				'RESTRICT': 'primaryuri',
				'SRC_URI': '''{scheme}://{host}:{port}/distfiles/bar.txt -> bar
					{scheme}://{host}:{port}/distfiles/foo.txt -> foo''',
			},
		}

		loop = SchedulerInterface(global_event_loop())
		scheme = 'http'
		host = '127.0.0.1'
		content = {}
		for k, v in distfiles.items():
			content['/distfiles/{}.txt'.format(k)] = v

		with AsyncHTTPServer(host, content, loop) as server:
			ebuilds_subst = {}
			for cpv, metadata in ebuilds.items():
				metadata = metadata.copy()
				metadata['SRC_URI'] = metadata['SRC_URI'].format(
					scheme=scheme, host=host, port=server.server_port)
				ebuilds_subst[cpv] = metadata

			playground = ResolverPlayground(ebuilds=ebuilds_subst, distfiles=distfiles)
			ro_distdir = tempfile.mkdtemp()
			try:
				fetchcommand = portage.util.shlex_split(playground.settings['FETCHCOMMAND'])
				fetch_bin = portage.process.find_binary(fetchcommand[0])
				if fetch_bin is None:
					self.skipTest('FETCHCOMMAND not found: {}'.format(playground.settings['FETCHCOMMAND']))
				resumecommand = portage.util.shlex_split(playground.settings['RESUMECOMMAND'])
				resume_bin = portage.process.find_binary(resumecommand[0])
				if resume_bin is None:
					self.skipTest('RESUMECOMMAND not found: {}'.format(playground.settings['RESUMECOMMAND']))
				root_config = playground.trees[playground.eroot]['root_config']
				portdb = root_config.trees["porttree"].dbapi
				settings = config(clone=playground.settings)

				# Tests only work with one ebuild at a time, so the config
				# pool only needs a single config instance.
				class config_pool:
					@staticmethod
					def allocate():
						return settings
					@staticmethod
					def deallocate(settings):
						pass

				def async_fetch(pkg, ebuild_path):
					fetcher = EbuildFetcher(config_pool=config_pool, ebuild_path=ebuild_path,
						fetchonly=False, fetchall=True, pkg=pkg, scheduler=loop)
					fetcher.start()
					return fetcher.async_wait()

				for cpv in ebuilds:
					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)
					ebuild_path = portdb.findname(pkg.cpv)
					portage.doebuild_environment(ebuild_path, 'fetch', settings=settings, db=portdb)

					# Test good files in DISTDIR
					for k in settings['AA'].split():
						os.stat(os.path.join(settings['DISTDIR'], k))
					self.assertEqual(loop.run_until_complete(async_fetch(pkg, ebuild_path)), 0)
					for k in settings['AA'].split():
						with open(os.path.join(settings['DISTDIR'], k), 'rb') as f:
							self.assertEqual(f.read(), distfiles[k])

					# Test digestgen with fetch
					os.unlink(os.path.join(os.path.dirname(ebuild_path), 'Manifest'))
					for k in settings['AA'].split():
						os.unlink(os.path.join(settings['DISTDIR'], k))
					with ForkExecutor(loop=loop) as executor:
						self.assertTrue(bool(loop.run_until_complete(
							loop.run_in_executor(executor, functools.partial(
								digestgen, mysettings=settings, myportdb=portdb)))))
					for k in settings['AA'].split():
						with open(os.path.join(settings['DISTDIR'], k), 'rb') as f:
							self.assertEqual(f.read(), distfiles[k])

					# Test missing files in DISTDIR
					for k in settings['AA'].split():
						os.unlink(os.path.join(settings['DISTDIR'], k))
					self.assertEqual(loop.run_until_complete(async_fetch(pkg, ebuild_path)), 0)
					for k in settings['AA'].split():
						with open(os.path.join(settings['DISTDIR'], k), 'rb') as f:
							self.assertEqual(f.read(), distfiles[k])

					# Test empty files in DISTDIR
					for k in settings['AA'].split():
						file_path = os.path.join(settings['DISTDIR'], k)
						with open(file_path, 'wb') as f:
							pass
						self.assertEqual(os.stat(file_path).st_size, 0)
					self.assertEqual(loop.run_until_complete(async_fetch(pkg, ebuild_path)), 0)
					for k in settings['AA'].split():
						with open(os.path.join(settings['DISTDIR'], k), 'rb') as f:
							self.assertEqual(f.read(), distfiles[k])

					# Test non-empty files containing null bytes in DISTDIR
					for k in settings['AA'].split():
						file_path = os.path.join(settings['DISTDIR'], k)
						with open(file_path, 'wb') as f:
							f.write(len(distfiles[k]) * b'\0')
						self.assertEqual(os.stat(file_path).st_size, len(distfiles[k]))
					self.assertEqual(loop.run_until_complete(async_fetch(pkg, ebuild_path)), 0)
					for k in settings['AA'].split():
						with open(os.path.join(settings['DISTDIR'], k), 'rb') as f:
							self.assertEqual(f.read(), distfiles[k])

					# Test PORTAGE_RO_DISTDIRS
					settings['PORTAGE_RO_DISTDIRS'] = '"{}"'.format(ro_distdir)
					orig_fetchcommand = settings['FETCHCOMMAND']
					orig_resumecommand = settings['RESUMECOMMAND']
					try:
						settings['FETCHCOMMAND'] = settings['RESUMECOMMAND'] = ''
						for k in settings['AA'].split():
							file_path = os.path.join(settings['DISTDIR'], k)
							os.rename(file_path, os.path.join(ro_distdir, k))
						self.assertEqual(loop.run_until_complete(async_fetch(pkg, ebuild_path)), 0)
						for k in settings['AA'].split():
							file_path = os.path.join(settings['DISTDIR'], k)
							self.assertTrue(os.path.islink(file_path))
							with open(file_path, 'rb') as f:
								self.assertEqual(f.read(), distfiles[k])
							os.unlink(file_path)
					finally:
						settings.pop('PORTAGE_RO_DISTDIRS')
						settings['FETCHCOMMAND'] = orig_fetchcommand
						settings['RESUMECOMMAND'] = orig_resumecommand

					# Test local filesystem in GENTOO_MIRRORS
					orig_mirrors = settings['GENTOO_MIRRORS']
					orig_fetchcommand = settings['FETCHCOMMAND']
					try:
						settings['GENTOO_MIRRORS'] = ro_distdir
						settings['FETCHCOMMAND'] = settings['RESUMECOMMAND'] = ''
						self.assertEqual(loop.run_until_complete(async_fetch(pkg, ebuild_path)), 0)
						for k in settings['AA'].split():
							with open(os.path.join(settings['DISTDIR'], k), 'rb') as f:
								self.assertEqual(f.read(), distfiles[k])
					finally:
						settings['GENTOO_MIRRORS'] = orig_mirrors
						settings['FETCHCOMMAND'] = orig_fetchcommand
						settings['RESUMECOMMAND'] = orig_resumecommand

					# Test readonly DISTDIR
					orig_distdir_mode = os.stat(settings['DISTDIR']).st_mode
					try:
						os.chmod(settings['DISTDIR'], 0o555)
						self.assertEqual(loop.run_until_complete(async_fetch(pkg, ebuild_path)), 0)
						for k in settings['AA'].split():
							with open(os.path.join(settings['DISTDIR'], k), 'rb') as f:
								self.assertEqual(f.read(), distfiles[k])
					finally:
						os.chmod(settings['DISTDIR'], orig_distdir_mode)

					# Test parallel-fetch mode
					settings['PORTAGE_PARALLEL_FETCHONLY'] = '1'
					try:
						self.assertEqual(loop.run_until_complete(async_fetch(pkg, ebuild_path)), 0)
						for k in settings['AA'].split():
							with open(os.path.join(settings['DISTDIR'], k), 'rb') as f:
								self.assertEqual(f.read(), distfiles[k])
						for k in settings['AA'].split():
							os.unlink(os.path.join(settings['DISTDIR'], k))
						self.assertEqual(loop.run_until_complete(async_fetch(pkg, ebuild_path)), 0)
						for k in settings['AA'].split():
							with open(os.path.join(settings['DISTDIR'], k), 'rb') as f:
								self.assertEqual(f.read(), distfiles[k])
					finally:
						settings.pop('PORTAGE_PARALLEL_FETCHONLY')

					# Test RESUMECOMMAND
					orig_resume_min_size = settings['PORTAGE_FETCH_RESUME_MIN_SIZE']
					try:
						settings['PORTAGE_FETCH_RESUME_MIN_SIZE'] = '2'
						for k in settings['AA'].split():
							file_path = os.path.join(settings['DISTDIR'], k)
							os.unlink(file_path)
							with open(file_path + _download_suffix, 'wb') as f:
								f.write(distfiles[k][:2])
						self.assertEqual(loop.run_until_complete(async_fetch(pkg, ebuild_path)), 0)
						for k in settings['AA'].split():
							with open(os.path.join(settings['DISTDIR'], k), 'rb') as f:
								self.assertEqual(f.read(), distfiles[k])
					finally:
						settings['PORTAGE_FETCH_RESUME_MIN_SIZE'] = orig_resume_min_size
			finally:
				shutil.rmtree(ro_distdir)
				playground.cleanup()
Exemplo n.º 22
0
def spawn_nofetch(portdb, ebuild_path, settings=None):
	"""
	This spawns pkg_nofetch if appropriate. The settings parameter
	is useful only if setcpv has already been called in order
	to cache metadata. It will be cloned internally, in order to
	prevent any changes from interfering with the calling code.
	If settings is None then a suitable config instance will be
	acquired from the given portdbapi instance.

	A private PORTAGE_BUILDDIR will be created and cleaned up, in
	order to avoid any interference with any other processes.
	If PORTAGE_TMPDIR is writable, that will be used, otherwise
	the default directory for the tempfile module will be used.

	We only call the pkg_nofetch phase if either RESTRICT=fetch
	is set or the package has explicitly overridden the default
	pkg_nofetch implementation. This allows specialized messages
	to be displayed for problematic packages even though they do
	not set RESTRICT=fetch (bug #336499).

	This function does nothing if the PORTAGE_PARALLEL_FETCHONLY
	variable is set in the config instance.
	"""

	if settings is None:
		settings = config(clone=portdb.settings)
	else:
		settings = config(clone=settings)

	if 'PORTAGE_PARALLEL_FETCHONLY' in settings:
		return

	# We must create our private PORTAGE_TMPDIR before calling
	# doebuild_environment(), since lots of variables such
	# as PORTAGE_BUILDDIR refer to paths inside PORTAGE_TMPDIR.
	portage_tmpdir = settings.get('PORTAGE_TMPDIR')
	if not portage_tmpdir or not os.access(portage_tmpdir, os.W_OK):
		portage_tmpdir = None
	private_tmpdir = tempfile.mkdtemp(dir=portage_tmpdir)
	settings['PORTAGE_TMPDIR'] = private_tmpdir
	settings.backup_changes('PORTAGE_TMPDIR')
	# private temp dir was just created, so it's not locked yet
	settings.pop('PORTAGE_BUILDIR_LOCKED', None)

	try:
		doebuild_environment(ebuild_path, 'nofetch',
			settings=settings, db=portdb)
		restrict = settings['PORTAGE_RESTRICT'].split()
		defined_phases = settings['DEFINED_PHASES'].split()
		if not defined_phases:
			# When DEFINED_PHASES is undefined, assume all
			# phases are defined.
			defined_phases = EBUILD_PHASES

		if 'fetch' not in restrict and \
			'nofetch' not in defined_phases:
			return

		prepare_build_dirs(settings=settings)
		ebuild_phase = EbuildPhase(background=False,
			phase='nofetch', scheduler=PollScheduler().sched_iface,
			settings=settings)
		ebuild_phase.start()
		ebuild_phase.wait()
		elog_process(settings.mycpv, settings)
	finally:
		shutil.rmtree(private_tmpdir)
	def testUseExpandIncremental(self):

		profiles = (
			(
				'base',
				{
					"eapi": ("5",),
					"parent": ("..",),
					"make.defaults": (
						"INPUT_DEVICES=\"keyboard mouse\"",
						"PYTHON_TARGETS=\"python2_7 python3_3\"",
						("USE_EXPAND=\"INPUT_DEVICES PYTHON_TARGETS "
							"VIDEO_CARDS\""),
					)
				}
			),
			(
				'default/linux',
				{
					"eapi": ("5",),
					"make.defaults": (
						"VIDEO_CARDS=\"dummy fbdev v4l\"",
					)
				}
			),
			(
				'default/linux/x86',
				{
					"eapi": ("5",),
					"make.defaults": (
						# Test negative incremental for bug 530222.
						"PYTHON_TARGETS=\"-python3_3\"",
					),
					"parent": ("../../../base",
						"../../../mixins/python/3.4",
						".."
					)
				}
			),
			(
				'mixins/python/3.4',
				{
					"eapi": ("5",),
					"make.defaults": (
						"PYTHON_TARGETS=\"python3_4\"",
					)
				}
			),
		)

		# USE_EXPAND variable settings in make.conf will cause
		# profile settings for the same variable to be discarded
		# (non-incremental behavior). PMS does not govern make.conf
		# behavior.
		user_config = {
			"make.conf" : (
				"VIDEO_CARDS=\"intel\"",
			)
		}

		ebuilds = {
			"x11-base/xorg-drivers-1.15": {
				"EAPI": "5",
				"IUSE": ("input_devices_keyboard input_devices_mouse "
					"videos_cards_dummy video_cards_fbdev "
					"video_cards_v4l video_cards_intel")
			},
			"sys-apps/portage-2.2.14": {
				"EAPI": "5",
				"IUSE": ("python_targets_python2_7 "
					"python_targets_python3_3 python_targets_python3_4")
			},
		}

		package_expected_use = (
			("x11-base/xorg-drivers-1.15", ("input_devices_keyboard",
				"input_devices_mouse", "video_cards_intel",)),
			("sys-apps/portage-2.2.14", ("python_targets_python2_7",
				"python_targets_python3_4"))
		)

		playground = ResolverPlayground(debug=False,
			ebuilds=ebuilds, user_config=user_config)
		try:
			repo_dir = (playground.settings.repositories.
				get_location_for_name("test_repo"))
			profile_root = os.path.join(repo_dir, "profiles")

			for p, data in profiles:
				prof_path = os.path.join(profile_root, p)
				ensure_dirs(prof_path)
				for k, v in data.items():
					with io.open(os.path.join(prof_path, k), mode="w",
						encoding=_encodings["repo.content"]) as f:
						for line in v:
							f.write("%s\n" % line)

			# The config must be reloaded in order to account
			# for the above profile customizations.
			playground.reload_config()

			depgraph = playground.run(
				["=x11-base/xorg-drivers-1.15"]).depgraph
			settings = config(clone=playground.settings)

			for cpv, expected_use in package_expected_use:
				pkg, existing_node = depgraph._select_package(
					playground.eroot, Atom("=" + cpv))
				settings.setcpv(pkg)
				expected = frozenset(expected_use)
				got = frozenset(settings["PORTAGE_USE"].split())
				self.assertEqual(got, expected,
					"%s != %s" % (got, expected))

		finally:
			playground.cleanup()