def _add_profile(self, profile_override=None): if profile_override is None: profile = self._find_profile_link() else: profile = normpath(abspath(profile_override)) if not os.path.exists(profile): raise config_errors.UserConfigError( f"{profile!r} doesn't exist") paths = profiles.OnDiskProfile.split_abspath(profile) if paths is None: raise config_errors.UserConfigError( '%r expands to %r, but no profile detected' % (pjoin(self.dir, 'make.profile'), profile)) user_profile_path = pjoin(self.dir, 'profile') if os.path.isdir(user_profile_path): self["profile"] = basics.AutoConfigSection({ "class": "pkgcore.ebuild.profiles.UserProfile", "parent_path": paths[0], "parent_profile": paths[1], "user_path": user_profile_path, }) else: self["profile"] = basics.AutoConfigSection({ "class": "pkgcore.ebuild.profiles.OnDiskProfile", "basepath": paths[0], "profile": paths[1], })
def add_sets(config, root, portage_base_dir): config["world"] = basics.AutoConfigSection({ "class": "pkgcore.pkgsets.filelist.WorldFile", "location": pjoin(root, const.WORLD_FILE)}) config["system"] = basics.AutoConfigSection({ "class": "pkgcore.pkgsets.system.SystemSet", "profile": "profile"}) config["installed"] = basics.AutoConfigSection({ "class": "pkgcore.pkgsets.installed.Installed", "vdb": "vdb"}) config["versioned-installed"] = basics.AutoConfigSection({ "class": "pkgcore.pkgsets.installed.VersionedInstalled", "vdb": "vdb"}) set_fp = pjoin(portage_base_dir, "sets") try: for setname in listdir_files(set_fp): # Potential for name clashes here, those will just make # the set not show up in config. if setname in ("system", "world"): logger.warning("user defined set %s is disallowed; ignoring" % pjoin(set_fp, setname)) continue config[setname] = basics.AutoConfigSection({ "class": "pkgcore.pkgsets.filelist.FileList", "location": pjoin(set_fp, setname)}) except OSError as e: if e.errno != errno.ENOENT: raise
def add_profile(config, config_dir, profile_override=None): if profile_override is None: profile = _find_profile_link(config_dir) else: profile = normpath(abspath(profile_override)) if not os.path.exists(profile): raise_from( errors.ComplexInstantiationError("%s doesn't exist" % (profile, ))) paths = profiles.OnDiskProfile.split_abspath(profile) if paths is None: raise errors.ComplexInstantiationError( '%s expands to %s, but no profile detected' % (pjoin(config_dir, 'make.profile'), profile)) user_profile_path = pjoin(config_dir, 'profile') if os.path.isdir(user_profile_path): config["profile"] = basics.AutoConfigSection({ "class": "pkgcore.ebuild.profiles.UserProfile", "parent_path": paths[0], "parent_profile": paths[1], "user_path": user_profile_path, }) else: config["profile"] = basics.AutoConfigSection({ "class": "pkgcore.ebuild.profiles.OnDiskProfile", "basepath": paths[0], "profile": paths[1], })
def test_typecheck(self): @configurable({'myrepo': 'ref:repo'}, typename='repo') def reporef(myrepo=None): return myrepo @configurable({'myrepo': 'refs:repo'}, typename='repo') def reporefs(myrepo=None): return myrepo @configurable(typename='repo') def myrepo(): return 'repo!' manager = central.ConfigManager([{ 'myrepo': basics.HardCodedConfigSection({'class': myrepo}), 'drawer': basics.HardCodedConfigSection({'class': drawer}), 'right': basics.AutoConfigSection({ 'class': reporef, 'myrepo': 'myrepo' }), 'wrong': basics.AutoConfigSection({ 'class': reporef, 'myrepo': 'drawer' }), }]) self.check_error( "Collapsing section named 'wrong':\n" "Failed collapsing section key 'myrepo':\n" "reference 'drawer' should be of type 'repo', got 'drawer'", self.get_config_obj, manager, 'repo', 'wrong') self.assertEqual('repo!', manager.objects.repo['right']) manager = central.ConfigManager([{ 'myrepo': basics.HardCodedConfigSection({'class': myrepo}), 'drawer': basics.HardCodedConfigSection({'class': drawer}), 'right': basics.AutoConfigSection({ 'class': reporefs, 'myrepo': 'myrepo' }), 'wrong': basics.AutoConfigSection({ 'class': reporefs, 'myrepo': 'drawer' }), }]) self.check_error( "Collapsing section named 'wrong':\n" "Failed collapsing section key 'myrepo':\n" "reference 'drawer' should be of type 'repo', got 'drawer'", self.get_config_obj, manager, 'repo', 'wrong') self.assertEqual(['repo!'], manager.objects.repo['right'])
def make_autodetect_syncer(new_config, basedir): name = 'sync:%s' % basedir new_config[name] = basics.AutoConfigSection({ 'class': 'pkgcore.sync.base.AutodetectSyncer', 'basedir': basedir }) return name
def add_fetcher(config, make_conf): fetchcommand = make_conf.pop("FETCHCOMMAND") resumecommand = make_conf.pop("RESUMECOMMAND", fetchcommand) fetcher_dict = { "class": "pkgcore.fetch.custom.fetcher", "distdir": normpath(os.environ.get("DISTDIR", make_conf.pop("DISTDIR"))), "command": fetchcommand, "resume_command": resumecommand, "attempts": make_conf.pop("FETCH_ATTEMPTS", '10'), } config["fetcher"] = basics.AutoConfigSection(fetcher_dict)
def test_lazy_refs(self): @configurable({'myrepo': 'lazy_ref:repo', 'thing': 'lazy_ref'}, typename='repo') def reporef(myrepo=None, thing=None): return myrepo, thing @configurable({'myrepo': 'lazy_refs:repo', 'thing': 'lazy_refs'}, typename='repo') def reporefs(myrepo=None, thing=None): return myrepo, thing @configurable(typename='repo') def myrepo(): return 'repo!' manager = central.ConfigManager([{ 'myrepo': basics.HardCodedConfigSection({'class': myrepo}), 'drawer': basics.HardCodedConfigSection({'class': drawer}), 'right': basics.AutoConfigSection({'class': reporef, 'myrepo': 'myrepo'}), 'wrong': basics.AutoConfigSection({'class': reporef, 'myrepo': 'drawer'}), }]) self.check_error( "reference 'drawer' should be of type 'repo', got 'drawer'", manager.objects.repo['wrong'][0].collapse) self.assertEqual('repo!', manager.objects.repo['right'][0].instantiate()) manager = central.ConfigManager([{ 'myrepo': basics.HardCodedConfigSection({'class': myrepo}), 'drawer': basics.HardCodedConfigSection({'class': drawer}), 'right': basics.AutoConfigSection({'class': reporefs, 'myrepo': 'myrepo'}), 'wrong': basics.AutoConfigSection({'class': reporefs, 'myrepo': 'drawer'}), }]) self.check_error( "reference 'drawer' should be of type 'repo', got 'drawer'", manager.objects.repo['wrong'][0][0].collapse) self.assertEqual( ['repo!'], [c.instantiate() for c in manager.objects.repo['right'][0]])
def _add_sets(self): self["world"] = basics.AutoConfigSection({ "class": "pkgcore.pkgsets.filelist.WorldFile", "location": pjoin(self.root, econst.WORLD_FILE.lstrip('/')) }) self["system"] = basics.AutoConfigSection({ "class": "pkgcore.pkgsets.system.SystemSet", "profile": "profile" }) self["installed"] = basics.AutoConfigSection({ "class": "pkgcore.pkgsets.installed.Installed", "vdb": "vdb" }) self["versioned-installed"] = basics.AutoConfigSection({ "class": "pkgcore.pkgsets.installed.VersionedInstalled", "vdb": "vdb" }) set_fp = pjoin(self.dir, "sets") try: for setname in listdir_files(set_fp): # Potential for name clashes here, those will just make # the set not show up in config. if setname in ("system", "world"): logger.warning( "user defined set %r is disallowed; ignoring", pjoin(set_fp, setname)) continue self[setname] = basics.AutoConfigSection({ "class": "pkgcore.pkgsets.filelist.FileList", "location": pjoin(set_fp, setname) }) except FileNotFoundError: pass
def make_syncer(new_config, basedir, sync_uri, rsync_opts, allow_timestamps=True): d = {'basedir': basedir, 'uri': sync_uri} if sync_uri.startswith('rsync'): d.update(rsync_opts) if allow_timestamps: d['class'] = 'pkgcore.sync.rsync.rsync_timestamp_syncer' else: d['class'] = 'pkgcore.sync.rsync.rsync_syncer' else: d['class'] = 'pkgcore.sync.base.GenericSyncer' name = 'sync:%s' % basedir new_config[name] = basics.AutoConfigSection(d) return name
def add_fetcher(config, conf_dict, distdir): fetchcommand = conf_dict.pop("FETCHCOMMAND") resumecommand = conf_dict.pop("RESUMECOMMAND", fetchcommand) # copy it to prevent modification. # map a config arg to an obj arg, pop a few values fetcher_dict = dict(conf_dict) if "FETCH_ATTEMPTS" in fetcher_dict: fetcher_dict["attempts"] = fetcher_dict.pop("FETCH_ATTEMPTS") fetcher_dict.pop("readonly", None) fetcher_dict.update({ "class": "pkgcore.fetch.custom.fetcher", "distdir": distdir, "command": fetchcommand, "resume_command": resumecommand, }) config["fetcher"] = basics.AutoConfigSection(fetcher_dict)
def _repo_ebuild_v1(self, repo_name, repo_opts, repo_map, defaults, repo_obj=None, repo_dict=None): """Create ebuild repo v1 configuration.""" repo_path = repo_opts['location'] # XXX: Hack for portage-2 profile format support. if repo_obj is None: repo_obj = repo_objs.RepoConfig(repo_path, repo_name) repo_map[repo_obj.repo_id] = repo_path # repo configs repo_conf = { 'class': 'pkgcore.ebuild.repo_objs.RepoConfig', 'config_name': repo_name, 'location': repo_path, 'syncer': 'sync:' + repo_name, } if repo_dict is not None: repo_conf.update(repo_dict) # repo trees repo = { 'inherit': ('ebuild-repo-common', ), 'repo_config': 'conf:' + repo_name, } # metadata cache if repo_obj.cache_format is not None: cache_name = 'cache:' + repo_name self[cache_name] = self._make_cache(repo_obj.cache_format, repo_path) repo['cache'] = cache_name if repo_name == defaults['main-repo']: repo_conf['default'] = True repo['default'] = True self['conf:' + repo_name] = basics.AutoConfigSection(repo_conf) return repo
def make_cache(cache_format, repo_path): # Use md5 cache if it exists or the option is selected, otherwise default # to the old flat hash format in /var/cache/edb/dep/*. if (os.path.exists(pjoin(repo_path, 'metadata', 'md5-cache')) or cache_format == 'md5-dict'): kls = 'pkgcore.cache.flat_hash.md5_cache' cache_parent_dir = pjoin(repo_path, 'metadata', 'md5-cache') else: kls = 'pkgcore.cache.flat_hash.database' repo_path = pjoin('/var/cache/edb/dep', repo_path.lstrip('/')) cache_parent_dir = repo_path while not os.path.exists(cache_parent_dir): cache_parent_dir = os.path.dirname(cache_parent_dir) readonly = (not access(cache_parent_dir, os.W_OK | os.X_OK)) return basics.AutoConfigSection({ 'class': kls, 'location': repo_path, 'readonly': readonly })
def _make_repo_syncers(self, repos_conf, make_conf, allow_timestamps=True): """generate syncing configs for known repos""" rsync_opts = None usersync = 'usersync' in self.features for repo_name, repo_opts in repos_conf.items(): d = {'basedir': repo_opts['location'], 'usersync': usersync} sync_type = repo_opts.get('sync-type', None) sync_uri = repo_opts.get('sync-uri', None) if sync_uri: # prefix non-native protocols if (sync_type is not None and not sync_uri.startswith(sync_type)): sync_uri = f'{sync_type}+{sync_uri}' d['uri'] = sync_uri d['opts'] = repo_opts.get('sync-opts', '') if sync_type == 'rsync': if rsync_opts is None: # various make.conf options used by rsync-based syncers rsync_opts = self._isolate_rsync_opts(make_conf) d.update(rsync_opts) if allow_timestamps: d['class'] = 'pkgcore.sync.rsync.rsync_timestamp_syncer' else: d['class'] = 'pkgcore.sync.rsync.rsync_syncer' else: d['class'] = 'pkgcore.sync.base.GenericSyncer' elif sync_uri is None: # try to autodetect syncing mechanism if sync-uri is missing d['class'] = 'pkgcore.sync.base.AutodetectSyncer' else: # disable syncing if sync-uri is explicitly unset d['class'] = 'pkgcore.sync.base.DisabledSyncer' name = 'sync:' + repo_name self[name] = basics.AutoConfigSection(d)
def mk_simple_cache(config_root, tree_loc): # TODO: probably should pull RepoConfig objects dynamically from the config # instead of regenerating them repo_config = RepoConfig(tree_loc) if repo_config.cache_format == 'md5-dict': kls = 'pkgcore.cache.flat_hash.md5_cache' tree_loc = pjoin(config_root, tree_loc.lstrip('/'), 'metadata', 'md5-cache') else: kls = 'pkgcore.cache.flat_hash.database' tree_loc = pjoin(config_root, 'var/cache/edb/dep', tree_loc.lstrip('/')) cache_parent_dir = tree_loc while not os.path.exists(cache_parent_dir): cache_parent_dir = os.path.dirname(cache_parent_dir) readonly = (not access(cache_parent_dir, os.W_OK|os.X_OK)) return basics.AutoConfigSection({ 'class': kls, 'location': tree_loc, 'readonly': readonly })
def __init__(self, location=None, profile_override=None, **kwargs): """ Args: location (optional[str]): path to the portage config directory, (defaults to /etc/portage) profile_override (optional[str]): profile to use instead of the current system profile, i.e. the target of the /etc/portage/make.profile symlink configroot (optional[str]): location for various portage config files (defaults to /) root (optional[str]): target root filesystem (defaults to /) buildpkg (optional[bool]): forcibly disable/enable building binpkgs, otherwise FEATURES=buildpkg from make.conf is used Returns: dict: config settings """ self._config = {} location = location if location is not None else '/etc/portage' self.dir = pjoin( os.environ.get('PORTAGE_CONFIGROOT', kwargs.pop('configroot', '/')), location.lstrip('/')) # this actually differs from portage parsing- we allow # make.globals to provide vars used in make.conf, portage keeps # them separate (kind of annoying) # # this isn't preserving incremental behaviour for features/use unfortunately make_conf = {} try: self.load_make_conf(make_conf, pjoin(const.CONFIG_PATH, 'make.globals')) except IGNORED_EXCEPTIONS: raise except Exception as e: raise config_errors.ParsingError( "failed to load make.globals") from e self.load_make_conf(make_conf, pjoin(self.dir, 'make.conf'), required=False, allow_sourcing=True, incrementals=True) self.root = os.environ.get( "ROOT", kwargs.pop('root', make_conf.get("ROOT", "/"))) gentoo_mirrors = [ x.rstrip("/") + "/distfiles" for x in make_conf.pop("GENTOO_MIRRORS", "").split() ] self.features = frozenset( optimize_incrementals(make_conf.get('FEATURES', '').split())) self._add_sets() self._add_profile(profile_override) self['vdb'] = basics.AutoConfigSection({ 'class': 'pkgcore.vdb.ondisk.tree', 'location': pjoin(self.root, 'var', 'db', 'pkg'), 'cache_location': '/var/cache/edb/dep/var/db/pkg', }) try: repos_conf_defaults, repos_conf = self.load_repos_conf( pjoin(self.dir, 'repos.conf')) except config_errors.ParsingError as e: if not getattr(getattr(e, 'exc', None), 'errno', None) == errno.ENOENT: raise try: # fallback to defaults provided by pkgcore repos_conf_defaults, repos_conf = self.load_repos_conf( pjoin(const.CONFIG_PATH, 'repos.conf')) except IGNORED_EXCEPTIONS: raise except Exception as e: raise config_errors.ParsingError( 'failed to find a usable repos.conf') from e self['ebuild-repo-common'] = basics.AutoConfigSection({ 'class': 'pkgcore.ebuild.repository.tree', 'default_mirrors': gentoo_mirrors, 'inherit-only': True, }) repo_map = {} for repo_name, repo_opts in list(repos_conf.items()): repo_cls = repo_opts.pop('repo-type') try: repo = repo_cls(self, repo_name=repo_name, repo_opts=repo_opts, repo_map=repo_map, defaults=repos_conf_defaults) except repo_errors.UnsupportedRepo as e: logger.warning( f'skipping {repo_name!r} repo: unsupported EAPI {str(e.repo.eapi)!r}' ) del repos_conf[repo_name] continue self[repo_name] = basics.AutoConfigSection(repo) # XXX: Hack for portage-2 profile format support. We need to figure out how # to dynamically create this from the config at runtime on attr access. profiles.ProfileNode._repo_map = ImmutableDict(repo_map) self._make_repo_syncers(repos_conf, make_conf) repos = [name for name in repos_conf.keys()] if repos: self['repo-stack'] = basics.FakeIncrementalDictConfigSection( my_convert_hybrid, { 'class': 'pkgcore.repository.multiplex.config_tree', 'repos': tuple(repos) }) self['vuln'] = basics.AutoConfigSection({ 'class': SecurityUpgradesViaProfile, 'ebuild_repo': 'repo-stack', 'vdb': 'vdb', 'profile': 'profile', }) # check if package building was forced on by the user forced_buildpkg = kwargs.pop('buildpkg', False) if forced_buildpkg: make_conf['FEATURES'] += ' buildpkg' # now add the fetcher- we delay it till here to clean out the environ # it passes to the command. # *everything* in make_conf must be str values also. self._add_fetcher(make_conf) # finally... domain. make_conf.update({ 'class': 'pkgcore.ebuild.domain.domain', 'repos': tuple(repos), 'fetcher': 'fetcher', 'default': True, 'vdb': ('vdb', ), 'profile': 'profile', 'name': 'livefs', 'root': self.root, 'config_dir': self.dir, }) self['livefs'] = basics.FakeIncrementalDictConfigSection( my_convert_hybrid, make_conf)
def config_from_make_conf(location="/etc/", profile_override=None, **kwargs): """ generate a config from a file location :param location: location the portage configuration is based in, defaults to /etc :param profile_override: profile to use instead of the current system profile, i.e. the target of the /etc/portage/make.profile (or deprecated /etc/make.profile) symlink """ # this actually differs from portage parsing- we allow # make.globals to provide vars used in make.conf, portage keeps # them separate (kind of annoying) config_root = os.environ.get("PORTAGE_CONFIGROOT", "/") base_path = pjoin(config_root, location.strip("/")) portage_base = pjoin(base_path, "portage") # this isn't preserving incremental behaviour for features/use # unfortunately conf_dict = {} try: load_make_config(conf_dict, pjoin(base_path, 'make.globals')) except errors.ParsingError as e: if not getattr(getattr(e, 'exc', None), 'errno', None) == errno.ENOENT: raise try: load_make_config(conf_dict, const.MAKE_GLOBALS) except IGNORED_EXCEPTIONS: raise except: raise_from( errors.ParsingError("failed to find a usable make.globals")) load_make_config(conf_dict, pjoin(base_path, 'make.conf'), required=False, allow_sourcing=True, incrementals=True) load_make_config(conf_dict, pjoin(portage_base, 'make.conf'), required=False, allow_sourcing=True, incrementals=True) root = os.environ.get("ROOT", conf_dict.get("ROOT", "/")) gentoo_mirrors = [ x.rstrip("/") + "/distfiles" for x in conf_dict.pop("GENTOO_MIRRORS", "").split() ] # this is flawed... it'll pick up -some-feature features = conf_dict.get("FEATURES", "").split() new_config = {} triggers = [] def add_trigger(name, kls_path, **extra_args): d = extra_args.copy() d['class'] = kls_path new_config[name] = basics.ConfigSectionFromStringDict(d) triggers.append(name) # sets... add_sets(new_config, root, portage_base) user_profile_path = pjoin(base_path, "portage", "profile") add_profile(new_config, base_path, user_profile_path, profile_override) kwds = { "class": "pkgcore.vdb.ondisk.tree", "location": pjoin(root, 'var', 'db', 'pkg'), "cache_location": pjoin(config_root, 'var', 'cache', 'edb', 'dep', 'var', 'db', 'pkg'), } new_config["vdb"] = basics.AutoConfigSection(kwds) # options used by rsync-based syncers rsync_opts = isolate_rsync_opts(conf_dict) repo_opts = {} overlay_syncers = {} try: default_repo_opts, repo_opts = load_repos_conf( pjoin(portage_base, 'repos.conf')) except errors.ParsingError as e: if not getattr(getattr(e, 'exc', None), 'errno', None) == errno.ENOENT: raise if repo_opts: main_repo_id = default_repo_opts['main-repo'] main_repo = repo_opts[main_repo_id]['location'] overlay_repos = [ opts['location'] for repo, opts in repo_opts.iteritems() if opts['location'] != main_repo ] main_syncer = repo_opts[main_repo_id].get('sync-uri', None) else: # fallback to PORTDIR and PORTDIR_OVERLAY settings main_repo = normpath( os.environ.get("PORTDIR", conf_dict.pop("PORTDIR", "/usr/portage")).strip()) overlay_repos = os.environ.get("PORTDIR_OVERLAY", conf_dict.pop("PORTDIR_OVERLAY", "")).split() overlay_repos = [normpath(x) for x in overlay_repos] main_syncer = conf_dict.pop("SYNC", None) if overlay_repos and '-layman-sync' not in features: overlay_syncers = add_layman_syncers(new_config, rsync_opts, overlay_repos, config_root=config_root) if main_syncer is not None: make_syncer(new_config, main_repo, main_syncer, rsync_opts) if overlay_repos and '-autodetect-sync' not in features: for path in overlay_repos: if path not in overlay_syncers: overlay_syncers[path] = make_autodetect_syncer( new_config, path) repos = [main_repo] + overlay_repos default_repos = list(reversed(repos)) new_config['ebuild-repo-common'] = basics.AutoConfigSection({ 'class': 'pkgcore.ebuild.repository.slavedtree', 'default_mirrors': gentoo_mirrors, 'inherit-only': True, 'ignore_paludis_versioning': ('ignore-paludis-versioning' in features), }) rsync_portdir_cache = 'metadata-transfer' not in features # if a metadata cache exists, use it. if rsync_portdir_cache: for cache_type, frag in (('flat_hash.md5_cache', 'md5-cache'), ('metadata.database', 'cache')): if not os.path.exists(pjoin(main_repo, 'metadata', frag)): continue new_config["cache:%s/metadata/cache" % (main_repo, )] = basics.AutoConfigSection({ 'class': 'pkgcore.cache.' + cache_type, 'readonly': True, 'location': main_repo, }) break else: rsync_portdir_cache = False repo_map = {} for tree_loc in repos: # XXX: Hack for portage-2 profile format support. repo_config = RepoConfig(tree_loc) repo_map[repo_config.repo_id] = repo_config # repo configs conf = { 'class': 'pkgcore.ebuild.repo_objs.RepoConfig', 'location': tree_loc, } if 'sync:%s' % (tree_loc, ) in new_config: conf['syncer'] = 'sync:%s' % (tree_loc, ) if tree_loc == main_repo: conf['default'] = True new_config['raw:' + tree_loc] = basics.AutoConfigSection(conf) # repo trees kwds = { 'inherit': ('ebuild-repo-common', ), 'raw_repo': ('raw:' + tree_loc), } cache_name = 'cache:%s' % (tree_loc, ) new_config[cache_name] = mk_simple_cache(config_root, tree_loc) kwds['cache'] = cache_name if tree_loc == main_repo: kwds['class'] = 'pkgcore.ebuild.repository.tree' if rsync_portdir_cache: kwds['cache'] = 'cache:%s/metadata/cache %s' % (main_repo, cache_name) else: kwds['parent_repo'] = main_repo new_config[tree_loc] = basics.AutoConfigSection(kwds) new_config['portdir'] = basics.section_alias(main_repo, 'repo') # XXX: Hack for portage-2 profile format support. We need to figure out how # to dynamically create this from the config at runtime on attr access. profiles.ProfileNode._repo_map = ImmutableDict(repo_map) if overlay_repos: new_config['repo-stack'] = basics.FakeIncrementalDictConfigSection( my_convert_hybrid, { 'class': 'pkgcore.repository.multiplex.config_tree', 'repositories': tuple(default_repos) }) else: new_config['repo-stack'] = basics.section_alias(main_repo, 'repo') new_config['vuln'] = basics.AutoConfigSection({ 'class': SecurityUpgradesViaProfile, 'ebuild_repo': 'repo-stack', 'vdb': 'vdb', 'profile': 'profile', }) new_config['glsa'] = basics.section_alias( 'vuln', SecurityUpgradesViaProfile.pkgcore_config_type.typename) # binpkg. buildpkg = 'buildpkg' in features or kwargs.get('buildpkg', False) pkgdir = os.environ.get("PKGDIR", conf_dict.pop('PKGDIR', None)) if pkgdir is not None: try: pkgdir = abspath(pkgdir) except OSError as oe: if oe.errno != errno.ENOENT: raise if buildpkg or set(features).intersection( ('pristine-buildpkg', 'buildsyspkg', 'unmerge-backup')): logger.warning( "disabling buildpkg related features since PKGDIR doesn't exist" ) pkgdir = None else: if not ensure_dirs(pkgdir, mode=0755, minimal=True): logger.warning( "disabling buildpkg related features since PKGDIR either doesn't " "exist, or lacks 0755 minimal permissions") pkgdir = None
def config_from_make_conf(location=None, profile_override=None, **kwargs): """generate a config using portage's config files Args: location (optional[str]): path to the portage config directory, (defaults to /etc/portage) profile_override (optional[str]): profile to use instead of the current system profile, i.e. the target of the /etc/portage/make.profile symlink configroot (optional[str]): location for various portage config files (defaults to /) root (optional[str]): target root filesystem (defaults to /) buildpkg (optional[bool]): forcibly disable/enable building binpkgs, otherwise FEATURES=buildpkg from make.conf is used Returns: dict: config settings """ # this actually differs from portage parsing- we allow # make.globals to provide vars used in make.conf, portage keeps # them separate (kind of annoying) config_dir = location if location is not None else '/etc/portage' config_dir = pjoin( os.environ.get('PORTAGE_CONFIGROOT', kwargs.pop('configroot', '/')), config_dir.lstrip('/')) # this isn't preserving incremental behaviour for features/use unfortunately make_conf = {} try: load_make_conf(make_conf, pjoin(const.CONFIG_PATH, 'make.globals')) except IGNORED_EXCEPTIONS: raise except: raise_from(errors.ParsingError("failed to load make.globals")) load_make_conf(make_conf, pjoin(config_dir, 'make.conf'), required=False, allow_sourcing=True, incrementals=True) root = os.environ.get("ROOT", kwargs.pop('root', make_conf.get("ROOT", "/"))) gentoo_mirrors = [ x.rstrip("/") + "/distfiles" for x in make_conf.pop("GENTOO_MIRRORS", "").split() ] # this is flawed... it'll pick up -some-feature features = make_conf.get("FEATURES", "").split() config = {} triggers = [] def add_trigger(name, kls_path, **extra_args): d = extra_args.copy() d['class'] = kls_path config[name] = basics.ConfigSectionFromStringDict(d) triggers.append(name) # sets... add_sets(config, root, config_dir) add_profile(config, config_dir, profile_override) kwds = { "class": "pkgcore.vdb.ondisk.tree", "location": pjoin(root, 'var', 'db', 'pkg'), "cache_location": '/var/cache/edb/dep/var/db/pkg', } config["vdb"] = basics.AutoConfigSection(kwds) try: repos_conf_defaults, repos_conf = load_repos_conf( pjoin(config_dir, 'repos.conf')) except errors.ParsingError as e: if not getattr(getattr(e, 'exc', None), 'errno', None) == errno.ENOENT: raise try: # fallback to defaults provided by pkgcore repos_conf_defaults, repos_conf = load_repos_conf( pjoin(const.CONFIG_PATH, 'repos.conf')) except IGNORED_EXCEPTIONS: raise except: raise_from( errors.ParsingError("failed to find a usable repos.conf")) make_repo_syncers(config, repos_conf, make_conf) config['ebuild-repo-common'] = basics.AutoConfigSection({ 'class': 'pkgcore.ebuild.repository.tree', 'default_mirrors': gentoo_mirrors, 'inherit-only': True, 'ignore_paludis_versioning': ('ignore-paludis-versioning' in features), }) default_repo_path = repos_conf[ repos_conf_defaults['main-repo']]['location'] repo_map = {} for repo_name, repo_opts in repos_conf.iteritems(): repo_path = repo_opts['location'] # XXX: Hack for portage-2 profile format support. repo_config = RepoConfig(repo_path, repo_name) repo_map[repo_config.repo_id] = repo_config # repo configs repo_conf = { 'class': 'pkgcore.ebuild.repo_objs.RepoConfig', 'config_name': repo_name, 'location': repo_path, 'syncer': 'sync:' + repo_name, } # repo trees repo = { 'inherit': ('ebuild-repo-common', ), 'repo_config': 'conf:' + repo_name, } # metadata cache if repo_config.cache_format is not None: cache_name = 'cache:' + repo_name config[cache_name] = make_cache(repo_config.cache_format, repo_path) repo['cache'] = cache_name if repo_path == default_repo_path: repo_conf['default'] = True config['conf:' + repo_name] = basics.AutoConfigSection(repo_conf) config[repo_name] = basics.AutoConfigSection(repo) # XXX: Hack for portage-2 profile format support. We need to figure out how # to dynamically create this from the config at runtime on attr access. profiles.ProfileNode._repo_map = ImmutableDict(repo_map) repos = [name for name in repos_conf.iterkeys()] if len(repos) > 1: config['repo-stack'] = basics.FakeIncrementalDictConfigSection( my_convert_hybrid, { 'class': 'pkgcore.repository.multiplex.config_tree', 'repositories': tuple(repos) }) else: config['repo-stack'] = basics.section_alias(repos[0], 'repo') config['vuln'] = basics.AutoConfigSection({ 'class': SecurityUpgradesViaProfile, 'ebuild_repo': 'repo-stack', 'vdb': 'vdb', 'profile': 'profile', }) config['glsa'] = basics.section_alias( 'vuln', SecurityUpgradesViaProfile.pkgcore_config_type.typename) # binpkg. buildpkg = 'buildpkg' in features or kwargs.pop('buildpkg', False) pkgdir = os.environ.get("PKGDIR", make_conf.pop('PKGDIR', None)) if pkgdir is not None: try: pkgdir = abspath(pkgdir) except OSError as oe: if oe.errno != errno.ENOENT: raise if buildpkg or set(features).intersection( ('pristine-buildpkg', 'buildsyspkg', 'unmerge-backup')): logger.warning( "disabling buildpkg related features since PKGDIR doesn't exist" ) pkgdir = None else: if not ensure_dirs(pkgdir, mode=0755, minimal=True): logger.warning( "disabling buildpkg related features since PKGDIR either doesn't " "exist, or lacks 0755 minimal permissions") pkgdir = None