# Copyright 2020 Gentoo Authors # Distributed under the terms of the GNU General Public License v2 from collections import OrderedDict from collections.abc import Mapping from hashlib import md5 from portage.localization import _ from portage.util import _recursive_file_list, writemsg from portage.util.configparser import SafeConfigParser, ConfigParserError, read_configs class BinRepoConfig: __slots__ = ( "name", "name_fallback", "fetchcommand", "priority", "resumecommand", "sync_uri", ) def __init__(self, opts): """ Create a BinRepoConfig with options in opts. """ for k in self.__slots__: setattr(self, k, opts.get(k.replace("_", "-"))) def info_string(self): """ Returns a formatted string containing information about the repository. Used by emerge --info. """ indent = " " * 4 repo_msg = [] repo_msg.append(self.name or self.name_fallback) if self.priority is not None: repo_msg.append(indent + "priority: " + str(self.priority)) repo_msg.append(indent + "sync-uri: " + self.sync_uri) repo_msg.append("") return "\n".join(repo_msg) class BinRepoConfigLoader(Mapping): def __init__(self, paths, settings): """Load config from files in paths""" # Defaults for value interpolation. parser_defaults = { "EPREFIX": settings["EPREFIX"], "EROOT": settings["EROOT"], "PORTAGE_CONFIGROOT": settings["PORTAGE_CONFIGROOT"], "ROOT": settings["ROOT"], } try: parser = self._parse(paths, parser_defaults) except ConfigParserError as e: writemsg( _("!!! Error while reading binrepo config file: %s\n") % e, noiselevel=-1, ) parser = SafeConfigParser(defaults=parser_defaults) repos = [] sync_uris = [] for section_name in parser.sections(): repo_data = dict(parser[section_name].items()) repo_data["name"] = section_name repo = BinRepoConfig(repo_data) if repo.sync_uri is None: writemsg( _("!!! Missing sync-uri setting for binrepo %s\n") % (repo.name,), noiselevel=-1, ) continue sync_uri = self._normalize_uri(repo.sync_uri) sync_uris.append(sync_uri) repo.sync_uri = sync_uri if repo.priority is not None: try: repo.priority = int(repo.priority) except ValueError: repo.priority = None repos.append(repo) sync_uris = set(sync_uris) current_priority = 0 for sync_uri in reversed(settings.get("PORTAGE_BINHOST", "").split()): sync_uri = self._normalize_uri(sync_uri) if sync_uri not in sync_uris: current_priority += 1 sync_uris.add(sync_uri) repos.append( BinRepoConfig( { "name-fallback": self._digest_uri(sync_uri), "name": None, "priority": current_priority, "sync-uri": sync_uri, } ) ) self._data = OrderedDict( (repo.name or repo.name_fallback, repo) for repo in sorted( repos, key=lambda repo: (repo.priority or 0, repo.name or repo.name_fallback), ) ) @staticmethod def _digest_uri(uri): return md5(uri.encode("utf_8")).hexdigest() @staticmethod def _normalize_uri(uri): return uri.rstrip("/") @staticmethod def _parse(paths, defaults): parser = SafeConfigParser(defaults=defaults) recursive_paths = [] for p in paths: if isinstance(p, str): recursive_paths.extend(_recursive_file_list(p)) else: recursive_paths.append(p) read_configs(parser, recursive_paths) return parser def __iter__(self): return iter(self._data) def __contains__(self, key): return key in self._data def __getitem__(self, key): return self._data[key] def __len__(self): return len(self._data)