Пример #1
0
	def __init__(self, paths, settings):
		"""Load config from files in paths"""

		prepos = {}
		location_map = {}
		treemap = {}
		ignored_map = {}
		default_opts = {
			"EPREFIX" : settings["EPREFIX"],
			"EROOT" : settings["EROOT"],
			"PORTAGE_CONFIGROOT" : settings["PORTAGE_CONFIGROOT"],
			"ROOT" : settings["ROOT"],
		}

		if "PORTAGE_REPOSITORIES" in settings:
			portdir = ""
			portdir_overlay = ""
			# deprecated portdir_sync
			portdir_sync = ""
		else:
			portdir = settings.get("PORTDIR", "")
			portdir_overlay = settings.get("PORTDIR_OVERLAY", "")
			# deprecated portdir_sync
			portdir_sync = settings.get("SYNC", "")

		default_opts['sync-rsync-extra-opts'] = \
			settings.get("PORTAGE_RSYNC_EXTRA_OPTS", "")

		try:
			self._parse(paths, prepos, settings.local_config, default_opts)
		except ConfigParserError as e:
			writemsg(
				_("!!! Error while reading repo config file: %s\n") % e,
				noiselevel=-1)
			# The configparser state is unreliable (prone to quirky
			# exceptions) after it has thrown an error, so use empty
			# config and try to fall back to PORTDIR{,_OVERLAY}.
			prepos.clear()
			prepos['DEFAULT'] = RepoConfig('DEFAULT',
				{}, local_config=settings.local_config)
			location_map.clear()
			treemap.clear()

		default_portdir = os.path.join(os.sep,
			settings['EPREFIX'].lstrip(os.sep), 'usr', 'portage')

		# If PORTDIR_OVERLAY contains a repo with the same repo_name as
		# PORTDIR, then PORTDIR is overridden.
		portdir = self._add_repositories(portdir, portdir_overlay, prepos,
			ignored_map, settings.local_config,
			default_portdir)
		if portdir and portdir.strip():
			portdir = os.path.realpath(portdir)

		ignored_repos = tuple((repo_name, tuple(paths)) \
			for repo_name, paths in ignored_map.items())

		self.missing_repo_names = frozenset(repo.location
			for repo in prepos.values()
			if repo.location is not None and repo.missing_repo_name)

		# Do this before expanding aliases, so that location_map and
		# treemap consistently map unaliased names whenever available.
		for repo_name, repo in list(prepos.items()):
			if repo.location is None:
				if repo_name != 'DEFAULT':
					# Skip this warning for repoman (bug #474578).
					if settings.local_config and paths:
						writemsg_level("!!! %s\n" % _("Section '%s' in repos.conf is missing location attribute") %
							repo.name, level=logging.ERROR, noiselevel=-1)
					del prepos[repo_name]
					continue
			else:
				if not portage._sync_mode:
					if not isdir_raise_eaccess(repo.location):
						writemsg_level("!!! %s\n" % _("Section '%s' in repos.conf has location attribute set "
							"to nonexistent directory: '%s'") %
							(repo_name, repo.location), level=logging.ERROR, noiselevel=-1)

						# Ignore missing directory for 'gentoo' so that
						# first sync with emerge-webrsync is possible.
						if repo.name != 'gentoo':
							del prepos[repo_name]
							continue

					# After removing support for PORTDIR_OVERLAY, the following check can be:
					# if repo.missing_repo_name:
					if repo.missing_repo_name and repo.name != repo_name:
						writemsg_level("!!! %s\n" % _("Section '%s' in repos.conf refers to repository "
							"without repository name set in '%s'") %
							(repo_name, os.path.join(repo.location, REPO_NAME_LOC)), level=logging.ERROR, noiselevel=-1)
						del prepos[repo_name]
						continue

					if repo.name != repo_name:
						writemsg_level("!!! %s\n" % _("Section '%s' in repos.conf has name different "
							"from repository name '%s' set inside repository") %
							(repo_name, repo.name), level=logging.ERROR, noiselevel=-1)
						del prepos[repo_name]
						continue

				location_map[repo.location] = repo_name
				treemap[repo_name] = repo.location

		# Add alias mappings, but never replace unaliased mappings.
		for repo_name, repo in list(prepos.items()):
			names = set()
			names.add(repo_name)
			if repo.aliases:
				aliases = stack_lists([repo.aliases], incremental=True)
				names.update(aliases)

			for name in names:
				if name in prepos and prepos[name].location is not None:
					if name == repo_name:
						# unaliased names already handled earlier
						continue
					writemsg_level(_("!!! Repository name or alias '%s', " + \
						"defined for repository '%s', overrides " + \
						"existing alias or repository.\n") % (name, repo_name), level=logging.WARNING, noiselevel=-1)
					# Never replace an unaliased mapping with
					# an aliased mapping.
					continue
				prepos[name] = repo
				if repo.location is not None:
					if repo.location not in location_map:
						# Never replace an unaliased mapping with
						# an aliased mapping.
						location_map[repo.location] = name
					treemap[name] = repo.location

		main_repo = prepos['DEFAULT'].main_repo
		if main_repo is None or main_repo not in prepos:
			#setting main_repo if it was not set in repos.conf
			main_repo = location_map.get(portdir)
			if main_repo is not None:
				prepos['DEFAULT'].main_repo = main_repo
			else:
				prepos['DEFAULT'].main_repo = None
				if portdir and not portage._sync_mode:
					writemsg(_("!!! main-repo not set in DEFAULT and PORTDIR is empty.\n"), noiselevel=-1)

		if main_repo is not None and prepos[main_repo].priority is None:
			# This happens if main-repo has been set in repos.conf.
			prepos[main_repo].priority = -1000

		# DEPRECATED Backward compatible SYNC support for old mirrorselect.
		# Feb. 2, 2015.  Version 2.2.16
		if portdir_sync and main_repo is not None:
			writemsg(_("!!! SYNC setting found in make.conf.\n    "
				"This setting is Deprecated and no longer used.  "
				"Please ensure your 'sync-type' and 'sync-uri' are set correctly"
				" in /etc/portage/repos.conf/gentoo.conf\n"),
				noiselevel=-1)


		# Include repo.name in sort key, for predictable sorting
		# even when priorities are equal.
		prepos_order = sorted(prepos.items(),
			key=lambda r:(r[1].priority or 0, r[1].name))

		# filter duplicates from aliases, by only including
		# items where repo.name == key
		prepos_order = [repo.name for (key, repo) in prepos_order
			if repo.name == key and key != 'DEFAULT' and
			repo.location is not None]

		self.prepos = prepos
		self.prepos_order = prepos_order
		self.ignored_repos = ignored_repos
		self.location_map = location_map
		self.treemap = treemap
		self._prepos_changed = True
		self._repo_location_list = []

		#The 'masters' key currently contains repo names. Replace them with the matching RepoConfig.
		for repo_name, repo in prepos.items():
			if repo_name == "DEFAULT":
				continue
			if repo.masters is None:
				if self.mainRepo() and repo_name != self.mainRepo().name:
					repo.masters = self.mainRepo(),
				else:
					repo.masters = ()
			else:
				if repo.masters and isinstance(repo.masters[0], RepoConfig):
					# This one has already been processed
					# because it has an alias.
					continue
				master_repos = []
				for master_name in repo.masters:
					if master_name not in prepos:
						layout_filename = os.path.join(repo.location,
							"metadata", "layout.conf")
						writemsg_level(_("Unavailable repository '%s' " \
							"referenced by masters entry in '%s'\n") % \
							(master_name, layout_filename),
							level=logging.ERROR, noiselevel=-1)
					else:
						master_repos.append(prepos[master_name])
				repo.masters = tuple(master_repos)

		#The 'eclass_overrides' key currently contains repo names. Replace them with the matching repo paths.
		for repo_name, repo in prepos.items():
			if repo_name == "DEFAULT":
				continue

			eclass_locations = []
			eclass_locations.extend(master_repo.location for master_repo in repo.masters)
			# Only append the current repo to eclass_locations if it's not
			# there already. This allows masters to have more control over
			# eclass override order, which may be useful for scenarios in
			# which there is a plan to migrate eclasses to a master repo.
			if repo.location not in eclass_locations:
				eclass_locations.append(repo.location)

			if repo.eclass_overrides:
				for other_repo_name in repo.eclass_overrides:
					if other_repo_name in self.treemap:
						eclass_locations.append(self.get_location_for_name(other_repo_name))
					else:
						writemsg_level(_("Unavailable repository '%s' " \
							"referenced by eclass-overrides entry for " \
							"'%s'\n") % (other_repo_name, repo_name), \
							level=logging.ERROR, noiselevel=-1)
			repo.eclass_locations = tuple(eclass_locations)

		eclass_dbs = {}
		for repo_name, repo in prepos.items():
			if repo_name == "DEFAULT":
				continue

			eclass_db = None
			for eclass_location in repo.eclass_locations:
				tree_db = eclass_dbs.get(eclass_location)
				if tree_db is None:
					tree_db = eclass_cache.cache(eclass_location)
					eclass_dbs[eclass_location] = tree_db
				if eclass_db is None:
					eclass_db = tree_db.copy()
				else:
					eclass_db.append(tree_db)
			repo.eclass_db = eclass_db

		for repo_name, repo in prepos.items():
			if repo_name == "DEFAULT":
				continue

			if repo._masters_orig is None and self.mainRepo() and \
				repo.name != self.mainRepo().name and not portage._sync_mode:
				# TODO: Delete masters code in pym/portage/tests/resolver/ResolverPlayground.py when deleting this warning.
				writemsg_level("!!! %s\n" % _("Repository '%s' is missing masters attribute in '%s'") %
					(repo.name, os.path.join(repo.location, "metadata", "layout.conf")) +
					"!!! %s\n" % _("Set 'masters = %s' in this file for future compatibility") %
					self.mainRepo().name, level=logging.WARNING, noiselevel=-1)

		self._prepos_changed = True
		self._repo_location_list = []

		self._check_locations()
Пример #2
0
	def __init__(self, _unused_param=None, mysettings=None):
		"""
		@param _unused_param: deprecated, use mysettings['PORTDIR'] instead
		@type _unused_param: None
		@param mysettings: an immutable config instance
		@type mysettings: portage.config
		"""
		portdbapi.portdbapi_instances.append(self)

		from portage import config
		if mysettings:
			self.settings = mysettings
		else:
			from portage import settings
			self.settings = config(clone=settings)

		porttree_root = self.settings['PORTDIR']

		# always show this warning after this parameter
		# is unused in stable portage
		if _unused_param is not None and _unused_param != porttree_root:
			warnings.warn("The first parameter of the " + \
				"portage.dbapi.porttree.portdbapi" + \
				" constructor is now unused. Use " + \
				"mysettings['PORTDIR'] instead.",
				DeprecationWarning, stacklevel=2)

		# This is strictly for use in aux_get() doebuild calls when metadata
		# is generated by the depend phase.  It's safest to use a clone for
		# this purpose because doebuild makes many changes to the config
		# instance that is passed in.
		self.doebuild_settings = config(clone=self.settings)
		self.depcachedir = os.path.realpath(self.settings.depcachedir)

		if os.environ.get("SANDBOX_ON") == "1":
			# Make api consumers exempt from sandbox violations
			# when doing metadata cache updates.
			sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
			if self.depcachedir not in sandbox_write:
				sandbox_write.append(self.depcachedir)
				os.environ["SANDBOX_WRITE"] = \
					":".join(filter(None, sandbox_write))

		porttrees = [os.path.realpath(porttree_root)]
		porttrees.extend(os.path.realpath(x) for x in \
			shlex_split(self.settings.get('PORTDIR_OVERLAY', '')))
		treemap = {}
		repository_map = {}
		self.treemap = treemap
		self._repository_map = repository_map
		identically_named_paths = {}
		for path in porttrees:
			if path in repository_map:
				continue
			repo_name_path = os.path.join(path, REPO_NAME_LOC)
			try:
				repo_name = codecs.open(
					_unicode_encode(repo_name_path,
					encoding=_encodings['fs'], errors='strict'),
					mode='r', encoding=_encodings['repo.content'],
					errors='replace').readline().strip()
			except EnvironmentError:
				# warn about missing repo_name at some other time, since we
				# don't want to see a warning every time the portage module is
				# imported.
				pass
			else:
				identically_named_path = treemap.get(repo_name)
				if identically_named_path is not None:
					# The earlier one is discarded.
					del repository_map[identically_named_path]
					identically_named_paths[identically_named_path] = repo_name
					if identically_named_path == porttrees[0]:
						# Found another repo with the same name as
						# $PORTDIR, so update porttrees[0] to match.
						porttrees[0] = path
				treemap[repo_name] = path
				repository_map[path] = repo_name

		# Ensure that each repo_name is unique. Later paths override
		# earlier ones that correspond to the same name.
		porttrees = [x for x in porttrees if x not in identically_named_paths]
		ignored_map = {}
		for path, repo_name in identically_named_paths.items():
			ignored_map.setdefault(repo_name, []).append(path)
		self._ignored_repos = tuple((repo_name, tuple(paths)) \
			for repo_name, paths in ignored_map.items())

		self.porttrees = porttrees
		porttree_root = porttrees[0]
		self.porttree_root = porttree_root

		self.eclassdb = eclass_cache.cache(porttree_root)

		# This is used as sanity check for aux_get(). If there is no
		# root eclass dir, we assume that PORTDIR is invalid or
		# missing. This check allows aux_get() to detect a missing
		# portage tree and return early by raising a KeyError.
		self._have_root_eclass_dir = os.path.isdir(
			os.path.join(self.porttree_root, "eclass"))

		self.metadbmodule = self.settings.load_best_module("portdbapi.metadbmodule")

		#if the portdbapi is "frozen", then we assume that we can cache everything (that no updates to it are happening)
		self.xcache = {}
		self.frozen = 0

		self._repo_info = {}
		eclass_dbs = {porttree_root : self.eclassdb}
		local_repo_configs = self.settings._local_repo_configs
		default_loc_repo_config = None
		repo_aliases = {}
		if local_repo_configs is not None:
			default_loc_repo_config = local_repo_configs.get('DEFAULT')
			for repo_name, loc_repo_conf in local_repo_configs.items():
				if loc_repo_conf.aliases is not None:
					for alias in loc_repo_conf.aliases:
						overridden_alias = repo_aliases.get(alias)
						if overridden_alias is not None:
							writemsg_level(_("!!! Alias '%s' " \
								"created for '%s' overrides " \
								"'%s' alias in " \
								"'%s'\n") % (alias, repo_name,
								overridden_alias,
								self.settings._local_repo_conf_path),
								level=logging.WARNING, noiselevel=-1)
						repo_aliases[alias] = repo_name

		for path in self.porttrees:
			if path in self._repo_info:
				continue

			repo_name = self._repository_map.get(path)

			loc_repo_conf = None
			if local_repo_configs is not None:
				if repo_name is not None:
					loc_repo_conf = local_repo_configs.get(repo_name)
				if loc_repo_conf is None:
					loc_repo_conf = default_loc_repo_config

			layout_filename = os.path.join(path, "metadata/layout.conf")
			layout_file = KeyValuePairFileLoader(layout_filename, None, None)
			layout_data, layout_errors = layout_file.load()
			porttrees = []

			masters = None
			if loc_repo_conf is not None and \
				loc_repo_conf.masters is not None:
				masters = loc_repo_conf.masters
			else:
				masters = layout_data.get('masters', '').split()

			for master_name in masters:
				master_name = repo_aliases.get(master_name, master_name)
				master_path = self.treemap.get(master_name)
				if master_path is None:
					writemsg_level(_("Unavailable repository '%s' " \
						"referenced by masters entry in '%s'\n") % \
						(master_name, layout_filename),
						level=logging.ERROR, noiselevel=-1)
				else:
					porttrees.append(master_path)

			if not porttrees and path != porttree_root:
				# Make PORTDIR the default master, but only if our
				# heuristics suggest that it's necessary.
				profiles_desc = os.path.join(path, 'profiles', 'profiles.desc')
				eclass_dir = os.path.join(path, 'eclass')
				if not os.path.isfile(profiles_desc) or \
					not os.path.isdir(eclass_dir):
					porttrees.append(porttree_root)

			porttrees.append(path)

			if loc_repo_conf is not None and \
					loc_repo_conf.eclass_overrides is not None:
					for other_name in loc_repo_conf.eclass_overrides:
						other_path = self.treemap.get(other_name)
						if other_path is None:
							writemsg_level(_("Unavailable repository '%s' " \
								"referenced by eclass-overrides entry in " \
								"'%s'\n") % (other_name,
								self.settings._local_repo_conf_path),
								level=logging.ERROR, noiselevel=-1)
							continue
						porttrees.append(other_path)

			eclass_db = None
			for porttree in porttrees:
				tree_db = eclass_dbs.get(porttree)
				if tree_db is None:
					tree_db = eclass_cache.cache(porttree)
					eclass_dbs[porttree] = tree_db
				if eclass_db is None:
					eclass_db = tree_db.copy()
				else:
					eclass_db.append(tree_db)

			self._repo_info[path] = _repo_info(repo_name, path, eclass_db)

		self.auxdbmodule = self.settings.load_best_module("portdbapi.auxdbmodule")
		self.auxdb = {}
		self._pregen_auxdb = {}
		self._init_cache_dirs()
		depcachedir_w_ok = os.access(self.depcachedir, os.W_OK)
		cache_kwargs = {
			'gid'     : portage_gid,
			'perms'   : 0o664
		}

		if secpass < 1:
			# portage_gid is irrelevant, so just obey umask
			cache_kwargs['gid']   = -1
			cache_kwargs['perms'] = -1

		# XXX: REMOVE THIS ONCE UNUSED_0 IS YANKED FROM auxdbkeys
		# ~harring
		filtered_auxdbkeys = [x for x in auxdbkeys if not x.startswith("UNUSED_0")]
		filtered_auxdbkeys.sort()
		from portage.cache import metadata_overlay, volatile
		if not depcachedir_w_ok:
			for x in self.porttrees:
				db_ro = self.auxdbmodule(self.depcachedir, x,
					filtered_auxdbkeys, gid=portage_gid, readonly=True)
				self.auxdb[x] = metadata_overlay.database(
					self.depcachedir, x, filtered_auxdbkeys,
					gid=portage_gid, db_rw=volatile.database,
					db_ro=db_ro)
		else:
			for x in self.porttrees:
				if x in self.auxdb:
					continue
				# location, label, auxdbkeys
				self.auxdb[x] = self.auxdbmodule(
					self.depcachedir, x, filtered_auxdbkeys, **cache_kwargs)
				if self.auxdbmodule is metadata_overlay.database:
					self.auxdb[x].db_ro.ec = self._repo_info[x].eclass_db
		if "metadata-transfer" not in self.settings.features:
			for x in self.porttrees:
				if x in self._pregen_auxdb:
					continue
				if os.path.isdir(os.path.join(x, "metadata", "cache")):
					self._pregen_auxdb[x] = self.metadbmodule(
						x, "metadata/cache", filtered_auxdbkeys, readonly=True)
					try:
						self._pregen_auxdb[x].ec = self._repo_info[x].eclass_db
					except AttributeError:
						pass
		# Selectively cache metadata in order to optimize dep matching.
		self._aux_cache_keys = set(
			["DEPEND", "EAPI", "INHERITED", "IUSE", "KEYWORDS", "LICENSE",
			"PDEPEND", "PROPERTIES", "PROVIDE", "RDEPEND", "repository",
			"RESTRICT", "SLOT", "DEFINED_PHASES"])

		self._aux_cache = {}
		self._broken_ebuilds = set()
Пример #3
0
	def __init__(self, _unused_param=None, mysettings=None):
		"""
		@param _unused_param: deprecated, use mysettings['PORTDIR'] instead
		@type _unused_param: None
		@param mysettings: an immutable config instance
		@type mysettings: portage.config
		"""
		portdbapi.portdbapi_instances.append(self)

		from portage import config
		if mysettings:
			self.settings = mysettings
		else:
			from portage import settings
			self.settings = config(clone=settings)

		if _unused_param is not None:
			warnings.warn("The first parameter of the " + \
				"portage.dbapi.porttree.portdbapi" + \
				" constructor is unused since portage-2.1.8. " + \
				"mysettings['PORTDIR'] is used instead.",
				DeprecationWarning, stacklevel=2)

		self.repositories = self.settings.repositories
		self.treemap = self.repositories.treemap

		# This is strictly for use in aux_get() doebuild calls when metadata
		# is generated by the depend phase.  It's safest to use a clone for
		# this purpose because doebuild makes many changes to the config
		# instance that is passed in.
		self.doebuild_settings = config(clone=self.settings)
		self.depcachedir = os.path.realpath(self.settings.depcachedir)
		
		if os.environ.get("SANDBOX_ON") == "1":
			# Make api consumers exempt from sandbox violations
			# when doing metadata cache updates.
			sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
			if self.depcachedir not in sandbox_write:
				sandbox_write.append(self.depcachedir)
				os.environ["SANDBOX_WRITE"] = \
					":".join(filter(None, sandbox_write))

		self.porttrees = list(self.settings.repositories.repoLocationList())
		self.eclassdb = eclass_cache.cache(self.settings.repositories.mainRepoLocation())

		# This is used as sanity check for aux_get(). If there is no
		# root eclass dir, we assume that PORTDIR is invalid or
		# missing. This check allows aux_get() to detect a missing
		# portage tree and return early by raising a KeyError.
		self._have_root_eclass_dir = os.path.isdir(
			os.path.join(self.settings.repositories.mainRepoLocation(), "eclass"))

		#if the portdbapi is "frozen", then we assume that we can cache everything (that no updates to it are happening)
		self.xcache = {}
		self.frozen = 0

		#Create eclass dbs
		self._repo_info = {}
		eclass_dbs = {self.settings.repositories.mainRepoLocation() : self.eclassdb}
		for repo in self.repositories:
			if repo.location in self._repo_info:
				continue

			eclass_db = None
			for eclass_location in repo.eclass_locations:
				tree_db = eclass_dbs.get(eclass_location)
				if tree_db is None:
					tree_db = eclass_cache.cache(eclass_location)
					eclass_dbs[eclass_location] = tree_db
				if eclass_db is None:
					eclass_db = tree_db.copy()
				else:
					eclass_db.append(tree_db)

			self._repo_info[repo.location] = _repo_info(repo.name, repo.location, eclass_db)

		#Keep a list of repo names, sorted by priority (highest priority first).
		self._ordered_repo_name_list = tuple(reversed(self.repositories.prepos_order))

		self.auxdbmodule = self.settings.load_best_module("portdbapi.auxdbmodule")
		self.auxdb = {}
		self._pregen_auxdb = {}
		# If the current user doesn't have depcachedir write permission,
		# then the depcachedir cache is kept here read-only access.
		self._ro_auxdb = {}
		self._init_cache_dirs()
		try:
			depcachedir_st = os.stat(self.depcachedir)
			depcachedir_w_ok = os.access(self.depcachedir, os.W_OK)
		except OSError:
			depcachedir_st = None
			depcachedir_w_ok = False

		cache_kwargs = {}

		depcachedir_unshared = False
		if portage.data.secpass < 1 and \
			depcachedir_w_ok and \
			depcachedir_st is not None and \
			os.getuid() == depcachedir_st.st_uid and \
			os.getgid() == depcachedir_st.st_gid:
			# If this user owns depcachedir and is not in the
			# portage group, then don't bother to set permissions
			# on cache entries. This makes it possible to run
			# egencache without any need to be a member of the
			# portage group.
			depcachedir_unshared = True
		else:
			cache_kwargs.update({
				'gid'     : portage_gid,
				'perms'   : 0o664
			})

		# If secpass < 1, we don't want to write to the cache
		# since then we won't be able to apply group permissions
		# to the cache entries/directories.
		if (secpass < 1 and not depcachedir_unshared) or not depcachedir_w_ok:
			for x in self.porttrees:
				self.auxdb[x] = volatile.database(
					self.depcachedir, x, self._known_keys,
					**cache_kwargs)
				try:
					self._ro_auxdb[x] = self.auxdbmodule(self.depcachedir, x,
						self._known_keys, readonly=True, **cache_kwargs)
				except CacheError:
					pass
		else:
			for x in self.porttrees:
				if x in self.auxdb:
					continue
				# location, label, auxdbkeys
				self.auxdb[x] = self.auxdbmodule(
					self.depcachedir, x, self._known_keys, **cache_kwargs)
		if "metadata-transfer" not in self.settings.features:
			for x in self.porttrees:
				if x in self._pregen_auxdb:
					continue
				cache = self._create_pregen_cache(x)
				if cache is not None:
					self._pregen_auxdb[x] = cache
		# Selectively cache metadata in order to optimize dep matching.
		self._aux_cache_keys = set(
			["DEPEND", "EAPI", "INHERITED", "IUSE", "KEYWORDS", "LICENSE",
			"PDEPEND", "PROPERTIES", "PROVIDE", "RDEPEND", "repository",
			"RESTRICT", "SLOT", "DEFINED_PHASES", "REQUIRED_USE"])

		self._aux_cache = {}
		self._broken_ebuilds = set()
Пример #4
0
    def __init__(self, paths, settings):
        """Load config from files in paths"""

        prepos = {}
        location_map = {}
        treemap = {}
        ignored_map = {}
        default_opts = {
            "EPREFIX": settings["EPREFIX"],
            "EROOT": settings["EROOT"],
            "PORTAGE_CONFIGROOT": settings["PORTAGE_CONFIGROOT"],
            "ROOT": settings["ROOT"],
        }

        if "PORTAGE_REPOSITORIES" in settings:
            portdir = ""
            portdir_overlay = ""
            # deprecated portdir_sync
            portdir_sync = ""
        else:
            portdir = settings.get("PORTDIR", "")
            portdir_overlay = settings.get("PORTDIR_OVERLAY", "")
            # deprecated portdir_sync
            portdir_sync = settings.get("SYNC", "")

        default_opts['sync-rsync-extra-opts'] = \
         settings.get("PORTAGE_RSYNC_EXTRA_OPTS", None)

        try:
            self._parse(paths, prepos, settings.local_config, default_opts)
        except ConfigParserError as e:
            writemsg(_("!!! Error while reading repo config file: %s\n") % e,
                     noiselevel=-1)
            # The configparser state is unreliable (prone to quirky
            # exceptions) after it has thrown an error, so use empty
            # config and try to fall back to PORTDIR{,_OVERLAY}.
            prepos.clear()
            prepos['DEFAULT'] = RepoConfig('DEFAULT', {},
                                           local_config=settings.local_config)
            location_map.clear()
            treemap.clear()

        default_portdir = os.path.join(os.sep,
                                       settings['EPREFIX'].lstrip(os.sep),
                                       'usr', 'portage')

        # If PORTDIR_OVERLAY contains a repo with the same repo_name as
        # PORTDIR, then PORTDIR is overridden.
        portdir = self._add_repositories(portdir, portdir_overlay, prepos,
                                         ignored_map, settings.local_config,
                                         default_portdir)
        if portdir and portdir.strip():
            portdir = os.path.realpath(portdir)

        ignored_repos = tuple((repo_name, tuple(paths)) \
         for repo_name, paths in ignored_map.items())

        self.missing_repo_names = frozenset(
            repo.location for repo in prepos.values()
            if repo.location is not None and repo.missing_repo_name)

        # Do this before expanding aliases, so that location_map and
        # treemap consistently map unaliased names whenever available.
        for repo_name, repo in list(prepos.items()):
            if repo.location is None:
                if repo_name != 'DEFAULT':
                    # Skip this warning for repoman (bug #474578).
                    if settings.local_config and paths:
                        writemsg_level("!!! %s\n" % _(
                            "Section '%s' in repos.conf is missing location attribute"
                        ) % repo.name,
                                       level=logging.ERROR,
                                       noiselevel=-1)
                    del prepos[repo_name]
                    continue
            else:
                if not portage._sync_mode:
                    if not isdir_raise_eaccess(repo.location):
                        writemsg_level("!!! %s\n" % _(
                            "Section '%s' in repos.conf has location attribute set "
                            "to nonexistent directory: '%s'") %
                                       (repo_name, repo.location),
                                       level=logging.ERROR,
                                       noiselevel=-1)

                        # Ignore missing directory for 'gentoo' so that
                        # first sync with emerge-webrsync is possible.
                        if repo.name != 'gentoo':
                            del prepos[repo_name]
                            continue

                    # After removing support for PORTDIR_OVERLAY, the following check can be:
                    # if repo.missing_repo_name:
                    if repo.missing_repo_name and repo.name != repo_name:
                        writemsg_level("!!! %s\n" % _(
                            "Section '%s' in repos.conf refers to repository "
                            "without repository name set in '%s'") %
                                       (repo_name,
                                        os.path.join(repo.location,
                                                     REPO_NAME_LOC)),
                                       level=logging.ERROR,
                                       noiselevel=-1)
                        del prepos[repo_name]
                        continue

                    if repo.name != repo_name:
                        writemsg_level("!!! %s\n" % _(
                            "Section '%s' in repos.conf has name different "
                            "from repository name '%s' set inside repository")
                                       % (repo_name, repo.name),
                                       level=logging.ERROR,
                                       noiselevel=-1)
                        del prepos[repo_name]
                        continue

                location_map[repo.location] = repo_name
                treemap[repo_name] = repo.location

        # Add alias mappings, but never replace unaliased mappings.
        for repo_name, repo in list(prepos.items()):
            names = set()
            names.add(repo_name)
            if repo.aliases:
                aliases = stack_lists([repo.aliases], incremental=True)
                names.update(aliases)

            for name in names:
                if name in prepos and prepos[name].location is not None:
                    if name == repo_name:
                        # unaliased names already handled earlier
                        continue
                    writemsg_level(_("!!! Repository name or alias '%s', " + \
                     "defined for repository '%s', overrides " + \
                     "existing alias or repository.\n") % (name, repo_name), level=logging.WARNING, noiselevel=-1)
                    # Never replace an unaliased mapping with
                    # an aliased mapping.
                    continue
                prepos[name] = repo
                if repo.location is not None:
                    if repo.location not in location_map:
                        # Never replace an unaliased mapping with
                        # an aliased mapping.
                        location_map[repo.location] = name
                    treemap[name] = repo.location

        main_repo = prepos['DEFAULT'].main_repo
        if main_repo is None or main_repo not in prepos:
            #setting main_repo if it was not set in repos.conf
            main_repo = location_map.get(portdir)
            if main_repo is not None:
                prepos['DEFAULT'].main_repo = main_repo
            else:
                prepos['DEFAULT'].main_repo = None
                if portdir and not portage._sync_mode:
                    writemsg(_(
                        "!!! main-repo not set in DEFAULT and PORTDIR is empty.\n"
                    ),
                             noiselevel=-1)

        if main_repo is not None and prepos[main_repo].priority is None:
            # This happens if main-repo has been set in repos.conf.
            prepos[main_repo].priority = -1000

        # DEPRECATED Backward compatible SYNC support for old mirrorselect.
        # Feb. 2, 2015.  Version 2.2.16
        if portdir_sync and main_repo is not None:
            writemsg(_(
                "!!! SYNC setting found in make.conf.\n    "
                "This setting is Deprecated and no longer used.  "
                "Please ensure your 'sync-type' and 'sync-uri' are set correctly"
                " in /etc/portage/repos.conf/gentoo.conf\n"),
                     noiselevel=-1)

        # Include repo.name in sort key, for predictable sorting
        # even when priorities are equal.
        prepos_order = sorted(prepos.items(),
                              key=lambda r: (r[1].priority or 0, r[1].name))

        # filter duplicates from aliases, by only including
        # items where repo.name == key
        prepos_order = [
            repo.name for (key, repo) in prepos_order if repo.name == key
            and key != 'DEFAULT' and repo.location is not None
        ]

        self.prepos = prepos
        self.prepos_order = prepos_order
        self.ignored_repos = ignored_repos
        self.location_map = location_map
        self.treemap = treemap
        self._prepos_changed = True
        self._repo_location_list = []

        #The 'masters' key currently contains repo names. Replace them with the matching RepoConfig.
        for repo_name, repo in prepos.items():
            if repo_name == "DEFAULT":
                continue
            if repo.masters is None:
                if self.mainRepo() and repo_name != self.mainRepo().name:
                    repo.masters = self.mainRepo(),
                else:
                    repo.masters = ()
            else:
                if repo.masters and isinstance(repo.masters[0], RepoConfig):
                    # This one has already been processed
                    # because it has an alias.
                    continue
                master_repos = []
                for master_name in repo.masters:
                    if master_name not in prepos:
                        layout_filename = os.path.join(repo.location,
                                                       "metadata",
                                                       "layout.conf")
                        writemsg_level(_("Unavailable repository '%s' " \
                         "referenced by masters entry in '%s'\n") % \
                         (master_name, layout_filename),
                         level=logging.ERROR, noiselevel=-1)
                    else:
                        master_repos.append(prepos[master_name])
                repo.masters = tuple(master_repos)

        #The 'eclass_overrides' key currently contains repo names. Replace them with the matching repo paths.
        for repo_name, repo in prepos.items():
            if repo_name == "DEFAULT":
                continue

            eclass_locations = []
            eclass_locations.extend(master_repo.location
                                    for master_repo in repo.masters)
            # Only append the current repo to eclass_locations if it's not
            # there already. This allows masters to have more control over
            # eclass override order, which may be useful for scenarios in
            # which there is a plan to migrate eclasses to a master repo.
            if repo.location not in eclass_locations:
                eclass_locations.append(repo.location)

            if repo.eclass_overrides:
                for other_repo_name in repo.eclass_overrides:
                    if other_repo_name in self.treemap:
                        eclass_locations.append(
                            self.get_location_for_name(other_repo_name))
                    else:
                        writemsg_level(_("Unavailable repository '%s' " \
                         "referenced by eclass-overrides entry for " \
                         "'%s'\n") % (other_repo_name, repo_name), \
                         level=logging.ERROR, noiselevel=-1)
            repo.eclass_locations = tuple(eclass_locations)

        eclass_dbs = {}
        for repo_name, repo in prepos.items():
            if repo_name == "DEFAULT":
                continue

            eclass_db = None
            for eclass_location in repo.eclass_locations:
                tree_db = eclass_dbs.get(eclass_location)
                if tree_db is None:
                    tree_db = eclass_cache.cache(eclass_location)
                    eclass_dbs[eclass_location] = tree_db
                if eclass_db is None:
                    eclass_db = tree_db.copy()
                else:
                    eclass_db.append(tree_db)
            repo.eclass_db = eclass_db

        for repo_name, repo in prepos.items():
            if repo_name == "DEFAULT":
                continue

            if repo._masters_orig is None and self.mainRepo() and \
             repo.name != self.mainRepo().name and not portage._sync_mode:
                # TODO: Delete masters code in pym/portage/tests/resolver/ResolverPlayground.py when deleting this warning.
                writemsg_level(
                    "!!! %s\n" %
                    _("Repository '%s' is missing masters attribute in '%s'") %
                    (repo.name,
                     os.path.join(repo.location, "metadata", "layout.conf")) +
                    "!!! %s\n" %
                    _("Set 'masters = %s' in this file for future compatibility"
                      ) % self.mainRepo().name,
                    level=logging.WARNING,
                    noiselevel=-1)

        self._prepos_changed = True
        self._repo_location_list = []

        self._check_locations()
Пример #5
0
	def __init__(self, paths, settings):
		"""Load config from files in paths"""

		prepos = {}
		location_map = {}
		treemap = {}
		ignored_map = {}
		ignored_location_map = {}

		portdir = settings.get('PORTDIR', '')
		portdir_overlay = settings.get('PORTDIR_OVERLAY', '')

		self._parse(paths, prepos, ignored_map, ignored_location_map)

		# If PORTDIR_OVERLAY contains a repo with the same repo_name as
		# PORTDIR, then PORTDIR is overridden.
		portdir = self._add_repositories(portdir, portdir_overlay, prepos,
			ignored_map, ignored_location_map)
		if portdir and portdir.strip():
			portdir = os.path.realpath(portdir)

		ignored_repos = tuple((repo_name, tuple(paths)) \
			for repo_name, paths in ignored_map.items())

		self.missing_repo_names = frozenset(repo.location
			for repo in prepos.values()
			if repo.location is not None and repo.missing_repo_name)

		#Take aliases into account.
		new_prepos = {}
		for repo_name, repo in prepos.items():
			names = set()
			names.add(repo_name)
			if repo.aliases:
				aliases = stack_lists([repo.aliases], incremental=True)
				names.update(aliases)

			for name in names:
				if name in new_prepos:
					writemsg_level(_("!!! Repository name or alias '%s', " + \
						"defined for repository '%s', overrides " + \
						"existing alias or repository.\n") % (name, repo_name), level=logging.WARNING, noiselevel=-1)
				new_prepos[name] = repo
		prepos = new_prepos

		for (name, r) in prepos.items():
			if r.location is not None:
				location_map[r.location] = name
				treemap[name] = r.location

		# filter duplicates from aliases, by only including
		# items where repo.name == key

		prepos_order = sorted(prepos.items(), key=lambda r:r[1].priority or 0)

		prepos_order = [repo.name for (key, repo) in prepos_order
			if repo.name == key and repo.location is not None]

		if prepos['DEFAULT'].main_repo is None or \
			prepos['DEFAULT'].main_repo not in prepos:
			#setting main_repo if it was not set in repos.conf
			if portdir in location_map:
				prepos['DEFAULT'].main_repo = location_map[portdir]
			elif portdir in ignored_location_map:
				prepos['DEFAULT'].main_repo = ignored_location_map[portdir]
			else:
				prepos['DEFAULT'].main_repo = None
				writemsg(_("!!! main-repo not set in DEFAULT and PORTDIR is empty. \n"), noiselevel=-1)

		self.prepos = prepos
		self.prepos_order = prepos_order
		self.ignored_repos = ignored_repos
		self.location_map = location_map
		self.treemap = treemap
		self._prepos_changed = True
		self._repo_location_list = []

		#The 'masters' key currently contains repo names. Replace them with the matching RepoConfig.
		for repo_name, repo in prepos.items():
			if repo_name == "DEFAULT":
				continue
			if repo.masters is None:
				if self.mainRepo() and repo_name != self.mainRepo().name:
					repo.masters = self.mainRepo(),
				else:
					repo.masters = ()
			else:
				if repo.masters and isinstance(repo.masters[0], RepoConfig):
					# This one has already been processed
					# because it has an alias.
					continue
				master_repos = []
				for master_name in repo.masters:
					if master_name not in prepos:
						layout_filename = os.path.join(repo.user_location,
							"metadata", "layout.conf")
						writemsg_level(_("Unavailable repository '%s' " \
							"referenced by masters entry in '%s'\n") % \
							(master_name, layout_filename),
							level=logging.ERROR, noiselevel=-1)
					else:
						master_repos.append(prepos[master_name])
				repo.masters = tuple(master_repos)

		#The 'eclass_overrides' key currently contains repo names. Replace them with the matching repo paths.
		for repo_name, repo in prepos.items():
			if repo_name == "DEFAULT":
				continue

			eclass_locations = []
			eclass_locations.extend(master_repo.location for master_repo in repo.masters)
			# Only append the current repo to eclass_locations if it's not
			# there already. This allows masters to have more control over
			# eclass override order, which may be useful for scenarios in
			# which there is a plan to migrate eclasses to a master repo.
			if repo.location not in eclass_locations:
				eclass_locations.append(repo.location)

			if repo.eclass_overrides:
				for other_repo_name in repo.eclass_overrides:
					if other_repo_name in self.treemap:
						eclass_locations.append(self.get_location_for_name(other_repo_name))
					else:
						writemsg_level(_("Unavailable repository '%s' " \
							"referenced by eclass-overrides entry for " \
							"'%s'\n") % (other_repo_name, repo_name), \
							level=logging.ERROR, noiselevel=-1)
			repo.eclass_locations = tuple(eclass_locations)

		eclass_dbs = {}
		for repo_name, repo in prepos.items():
			if repo_name == "DEFAULT":
				continue

			eclass_db = None
			for eclass_location in repo.eclass_locations:
				tree_db = eclass_dbs.get(eclass_location)
				if tree_db is None:
					tree_db = eclass_cache.cache(eclass_location)
					eclass_dbs[eclass_location] = tree_db
				if eclass_db is None:
					eclass_db = tree_db.copy()
				else:
					eclass_db.append(tree_db)
			repo.eclass_db = eclass_db

		self._prepos_changed = True
		self._repo_location_list = []

		self._check_locations()
Пример #6
0
	def __init__(self, paths, settings):
		"""Load config from files in paths"""

		prepos = {}
		location_map = {}
		treemap = {}
		ignored_map = {}
		ignored_location_map = {}

		portdir = settings.get('PORTDIR', '')
		portdir_overlay = settings.get('PORTDIR_OVERLAY', '')

		self._parse(paths, prepos, ignored_map, ignored_location_map)

		# If PORTDIR_OVERLAY contains a repo with the same repo_name as
		# PORTDIR, then PORTDIR is overridden.
		portdir = self._add_repositories(portdir, portdir_overlay, prepos,
			ignored_map, ignored_location_map)
		if portdir and portdir.strip():
			portdir = os.path.realpath(portdir)

		ignored_repos = tuple((repo_name, tuple(paths)) \
			for repo_name, paths in ignored_map.items())

		self.missing_repo_names = frozenset(repo.location
			for repo in prepos.values()
			if repo.location is not None and repo.missing_repo_name)

		#Take aliases into account.
		new_prepos = {}
		for repo_name, repo in prepos.items():
			names = set()
			names.add(repo_name)
			if repo.aliases:
				aliases = stack_lists([repo.aliases], incremental=True)
				names.update(aliases)

			for name in names:
				if name in new_prepos:
					writemsg_level(_("!!! Repository name or alias '%s', " + \
						"defined for repository '%s', overrides " + \
						"existing alias or repository.\n") % (name, repo_name), level=logging.WARNING, noiselevel=-1)
				new_prepos[name] = repo
		prepos = new_prepos

		for (name, r) in prepos.items():
			if r.location is not None:
				location_map[r.location] = name
				treemap[name] = r.location

		# filter duplicates from aliases, by only including
		# items where repo.name == key

		prepos_order = sorted(prepos.items(), key=lambda r:r[1].priority or 0)

		prepos_order = [repo.name for (key, repo) in prepos_order
			if repo.name == key and repo.location is not None]

		if prepos['DEFAULT'].main_repo is None or \
			prepos['DEFAULT'].main_repo not in prepos:
			#setting main_repo if it was not set in repos.conf
			if portdir in location_map:
				prepos['DEFAULT'].main_repo = location_map[portdir]
			elif portdir in ignored_location_map:
				prepos['DEFAULT'].main_repo = ignored_location_map[portdir]
			else:
				prepos['DEFAULT'].main_repo = None
				if not portage._sync_disabled_warnings:
					writemsg(_("Portage repository is currently empty.\n"), noiselevel=-1)

		self.prepos = prepos
		self.prepos_order = prepos_order
		self.ignored_repos = ignored_repos
		self.location_map = location_map
		self.treemap = treemap
		self._prepos_changed = True
		self._repo_location_list = []

		#The 'masters' key currently contains repo names. Replace them with the matching RepoConfig.
		for repo_name, repo in prepos.items():
			if repo_name == "DEFAULT":
				continue
			if repo.masters is None:
				if self.mainRepo() and repo_name != self.mainRepo().name:
					repo.masters = self.mainRepo(),
				else:
					repo.masters = ()
			else:
				if repo.masters and isinstance(repo.masters[0], RepoConfig):
					# This one has already been processed
					# because it has an alias.
					continue
				master_repos = []
				for master_name in repo.masters:
					if master_name not in prepos:
						layout_filename = os.path.join(repo.user_location,
							"metadata", "layout.conf")
						writemsg_level(_("Unavailable repository '%s' " \
							"referenced by masters entry in '%s'\n") % \
							(master_name, layout_filename),
							level=logging.ERROR, noiselevel=0)
					else:
						master_repos.append(prepos[master_name])
				repo.masters = tuple(master_repos)

		#The 'eclass_overrides' key currently contains repo names. Replace them with the matching repo paths.
		for repo_name, repo in prepos.items():
			if repo_name == "DEFAULT":
				continue

			eclass_locations = []
			eclass_locations.extend(master_repo.location for master_repo in repo.masters)
			# Only append the current repo to eclass_locations if it's not
			# there already. This allows masters to have more control over
			# eclass override order, which may be useful for scenarios in
			# which there is a plan to migrate eclasses to a master repo.
			if repo.location not in eclass_locations:
				eclass_locations.append(repo.location)

			if repo.eclass_overrides:
				for other_repo_name in repo.eclass_overrides:
					if other_repo_name in self.treemap:
						eclass_locations.append(self.get_location_for_name(other_repo_name))
					else:
						writemsg_level(_("Unavailable repository '%s' " \
							"referenced by eclass-overrides entry for " \
							"'%s'\n") % (other_repo_name, repo_name), \
							level=logging.ERROR, noiselevel=0)
			repo.eclass_locations = tuple(eclass_locations)

		eclass_dbs = {}
		for repo_name, repo in prepos.items():
			if repo_name == "DEFAULT":
				continue

			eclass_db = None
			for eclass_location in repo.eclass_locations:
				tree_db = eclass_dbs.get(eclass_location)
				if tree_db is None:
					tree_db = eclass_cache.cache(eclass_location)
					eclass_dbs[eclass_location] = tree_db
				if eclass_db is None:
					eclass_db = tree_db.copy()
				else:
					eclass_db.append(tree_db)
			repo.eclass_db = eclass_db

		self._prepos_changed = True
		self._repo_location_list = []

		self._check_locations()
Пример #7
0
    def __init__(self, _unused_param=None, mysettings=None):
        """
		@param _unused_param: deprecated, use mysettings['PORTDIR'] instead
		@type _unused_param: None
		@param mysettings: an immutable config instance
		@type mysettings: portage.config
		"""
        portdbapi.portdbapi_instances.append(self)

        from portage import config
        if mysettings:
            self.settings = mysettings
        else:
            from portage import settings
            self.settings = config(clone=settings)

        porttree_root = self.settings['PORTDIR']

        if _unused_param is not None:
            warnings.warn("The first parameter of the " + \
             "portage.dbapi.porttree.portdbapi" + \
             " constructor is now unused. Use " + \
             "mysettings['PORTDIR'] instead.",
             DeprecationWarning, stacklevel=2)

        # This is strictly for use in aux_get() doebuild calls when metadata
        # is generated by the depend phase.  It's safest to use a clone for
        # this purpose because doebuild makes many changes to the config
        # instance that is passed in.
        self.doebuild_settings = config(clone=self.settings)
        self.depcachedir = os.path.realpath(self.settings.depcachedir)

        if os.environ.get("SANDBOX_ON") == "1":
            # Make api consumers exempt from sandbox violations
            # when doing metadata cache updates.
            sandbox_write = os.environ.get("SANDBOX_WRITE", "").split(":")
            if self.depcachedir not in sandbox_write:
                sandbox_write.append(self.depcachedir)
                os.environ["SANDBOX_WRITE"] = \
                 ":".join(filter(None, sandbox_write))

        porttrees = [os.path.realpath(porttree_root)]
        porttrees.extend(os.path.realpath(x) for x in \
         shlex_split(self.settings.get('PORTDIR_OVERLAY', '')))
        treemap = {}
        repository_map = {}
        self.treemap = treemap
        self._repository_map = repository_map
        identically_named_paths = {}
        for path in porttrees:
            if path in repository_map:
                continue
            repo_name_path = os.path.join(path, REPO_NAME_LOC)
            try:
                repo_name = codecs.open(
                    _unicode_encode(repo_name_path,
                                    encoding=_encodings['fs'],
                                    errors='strict'),
                    mode='r',
                    encoding=_encodings['repo.content'],
                    errors='replace').readline().strip()
            except EnvironmentError:
                # warn about missing repo_name at some other time, since we
                # don't want to see a warning every time the portage module is
                # imported.
                pass
            else:
                identically_named_path = treemap.get(repo_name)
                if identically_named_path is not None:
                    # The earlier one is discarded.
                    del repository_map[identically_named_path]
                    identically_named_paths[identically_named_path] = repo_name
                    if identically_named_path == porttrees[0]:
                        # Found another repo with the same name as
                        # $PORTDIR, so update porttrees[0] to match.
                        porttrees[0] = path
                treemap[repo_name] = path
                repository_map[path] = repo_name

        # Ensure that each repo_name is unique. Later paths override
        # earlier ones that correspond to the same name.
        porttrees = [x for x in porttrees if x not in identically_named_paths]
        ignored_map = {}
        for path, repo_name in identically_named_paths.items():
            ignored_map.setdefault(repo_name, []).append(path)
        self._ignored_repos = tuple((repo_name, tuple(paths)) \
         for repo_name, paths in ignored_map.items())

        self.porttrees = porttrees
        porttree_root = porttrees[0]
        self.porttree_root = porttree_root

        self.eclassdb = eclass_cache.cache(porttree_root)

        # This is used as sanity check for aux_get(). If there is no
        # root eclass dir, we assume that PORTDIR is invalid or
        # missing. This check allows aux_get() to detect a missing
        # portage tree and return early by raising a KeyError.
        self._have_root_eclass_dir = os.path.isdir(
            os.path.join(self.porttree_root, "eclass"))

        self.metadbmodule = self.settings.load_best_module(
            "portdbapi.metadbmodule")

        #if the portdbapi is "frozen", then we assume that we can cache everything (that no updates to it are happening)
        self.xcache = {}
        self.frozen = 0

        self._repo_info = {}
        eclass_dbs = {porttree_root: self.eclassdb}
        local_repo_configs = self.settings._local_repo_configs
        default_loc_repo_config = None
        repo_aliases = {}
        if local_repo_configs is not None:
            default_loc_repo_config = local_repo_configs.get('DEFAULT')
            for repo_name, loc_repo_conf in local_repo_configs.items():
                if loc_repo_conf.aliases is not None:
                    for alias in loc_repo_conf.aliases:
                        overridden_alias = repo_aliases.get(alias)
                        if overridden_alias is not None:
                            writemsg_level(_("!!! Alias '%s' " \
                             "created for '%s' overrides " \
                             "'%s' alias in " \
                             "'%s'\n") % (alias, repo_name,
                             overridden_alias,
                             self.settings._local_repo_conf_path),
                             level=logging.WARNING, noiselevel=-1)
                        repo_aliases[alias] = repo_name

        for path in self.porttrees:
            if path in self._repo_info:
                continue

            repo_name = self._repository_map.get(path)

            loc_repo_conf = None
            if local_repo_configs is not None:
                if repo_name is not None:
                    loc_repo_conf = local_repo_configs.get(repo_name)
                if loc_repo_conf is None:
                    loc_repo_conf = default_loc_repo_config

            layout_filename = os.path.join(path, "metadata/layout.conf")
            layout_file = KeyValuePairFileLoader(layout_filename, None, None)
            layout_data, layout_errors = layout_file.load()
            porttrees = []

            masters = None
            if loc_repo_conf is not None and \
             loc_repo_conf.masters is not None:
                masters = loc_repo_conf.masters
            else:
                masters = layout_data.get('masters', '').split()

            for master_name in masters:
                master_name = repo_aliases.get(master_name, master_name)
                master_path = self.treemap.get(master_name)
                if master_path is None:
                    writemsg_level(_("Unavailable repository '%s' " \
                     "referenced by masters entry in '%s'\n") % \
                     (master_name, layout_filename),
                     level=logging.ERROR, noiselevel=-1)
                else:
                    porttrees.append(master_path)

            if not porttrees and path != porttree_root:
                # Make PORTDIR the default master, but only if our
                # heuristics suggest that it's necessary.
                profiles_desc = os.path.join(path, 'profiles', 'profiles.desc')
                eclass_dir = os.path.join(path, 'eclass')
                if not os.path.isfile(profiles_desc) or \
                 not os.path.isdir(eclass_dir):
                    porttrees.append(porttree_root)

            porttrees.append(path)

            if loc_repo_conf is not None and \
              loc_repo_conf.eclass_overrides is not None:
                for other_name in loc_repo_conf.eclass_overrides:
                    other_path = self.treemap.get(other_name)
                    if other_path is None:
                        writemsg_level(_("Unavailable repository '%s' " \
                         "referenced by eclass-overrides entry in " \
                         "'%s'\n") % (other_name,
                         self.settings._local_repo_conf_path),
                         level=logging.ERROR, noiselevel=-1)
                        continue
                    porttrees.append(other_path)

            eclass_db = None
            for porttree in porttrees:
                tree_db = eclass_dbs.get(porttree)
                if tree_db is None:
                    tree_db = eclass_cache.cache(porttree)
                    eclass_dbs[porttree] = tree_db
                if eclass_db is None:
                    eclass_db = tree_db.copy()
                else:
                    eclass_db.append(tree_db)

            self._repo_info[path] = _repo_info(repo_name, path, eclass_db)

        self.auxdbmodule = self.settings.load_best_module(
            "portdbapi.auxdbmodule")
        self.auxdb = {}
        self._pregen_auxdb = {}
        self._init_cache_dirs()
        depcachedir_w_ok = os.access(self.depcachedir, os.W_OK)
        cache_kwargs = {'gid': portage_gid, 'perms': 0o664}

        if secpass < 1:
            # portage_gid is irrelevant, so just obey umask
            cache_kwargs['gid'] = -1
            cache_kwargs['perms'] = -1

        # XXX: REMOVE THIS ONCE UNUSED_0 IS YANKED FROM auxdbkeys
        # ~harring
        filtered_auxdbkeys = [
            x for x in auxdbkeys if not x.startswith("UNUSED_0")
        ]
        filtered_auxdbkeys.sort()
        from portage.cache import metadata_overlay, volatile
        if not depcachedir_w_ok:
            for x in self.porttrees:
                db_ro = self.auxdbmodule(self.depcachedir,
                                         x,
                                         filtered_auxdbkeys,
                                         gid=portage_gid,
                                         readonly=True)
                self.auxdb[x] = metadata_overlay.database(
                    self.depcachedir,
                    x,
                    filtered_auxdbkeys,
                    gid=portage_gid,
                    db_rw=volatile.database,
                    db_ro=db_ro)
        else:
            for x in self.porttrees:
                if x in self.auxdb:
                    continue
                # location, label, auxdbkeys
                self.auxdb[x] = self.auxdbmodule(self.depcachedir, x,
                                                 filtered_auxdbkeys,
                                                 **cache_kwargs)
                if self.auxdbmodule is metadata_overlay.database:
                    self.auxdb[x].db_ro.ec = self._repo_info[x].eclass_db
        if "metadata-transfer" not in self.settings.features:
            for x in self.porttrees:
                if x in self._pregen_auxdb:
                    continue
                if os.path.isdir(os.path.join(x, "metadata", "cache")):
                    self._pregen_auxdb[x] = self.metadbmodule(
                        x, "metadata/cache", filtered_auxdbkeys, readonly=True)
                    try:
                        self._pregen_auxdb[x].ec = self._repo_info[x].eclass_db
                    except AttributeError:
                        pass
        # Selectively cache metadata in order to optimize dep matching.
        self._aux_cache_keys = set([
            "DEPEND", "EAPI", "INHERITED", "IUSE", "KEYWORDS", "LICENSE",
            "PDEPEND", "PROPERTIES", "PROVIDE", "RDEPEND", "repository",
            "RESTRICT", "SLOT", "DEFINED_PHASES", "REQUIRED_USE"
        ])

        self._aux_cache = {}
        self._broken_ebuilds = set()