Esempio n. 1
0
    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],
            })
Esempio n. 2
0
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
Esempio n. 3
0
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],
        })
Esempio n. 4
0
    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'])
Esempio n. 5
0
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
Esempio n. 6
0
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)
Esempio n. 7
0
    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]])
Esempio n. 8
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
Esempio n. 9
0
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
Esempio n. 10
0
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)
Esempio n. 11
0
    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
Esempio n. 12
0
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
    })
Esempio n. 13
0
    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)
Esempio n. 14
0
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
    })
Esempio n. 15
0
    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)
Esempio n. 16
0
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
Esempio n. 17
0
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