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()
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()
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()
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()
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()
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()
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()