diff options
Diffstat (limited to 'pym/portage/tests/resolver/ResolverPlayground.py')
-rw-r--r-- | pym/portage/tests/resolver/ResolverPlayground.py | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py new file mode 100644 index 00000000..b4ff4180 --- /dev/null +++ b/pym/portage/tests/resolver/ResolverPlayground.py @@ -0,0 +1,227 @@ +# Copyright 2010 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +from itertools import chain +import shutil +import tempfile +import portage +from portage import os +from portage.dbapi.vartree import vartree +from portage.dbapi.porttree import portagetree +from portage.dbapi.bintree import binarytree +from portage.dep import Atom +from portage.package.ebuild.config import config +from portage.sets import load_default_config +from portage.versions import catsplit + +from _emerge.Blocker import Blocker +from _emerge.create_depgraph_params import create_depgraph_params +from _emerge.depgraph import backtrack_depgraph +from _emerge.RootConfig import RootConfig + +class ResolverPlayground(object): + """ + This class help to create the necessary files on disk and + the needed settings instances, etc. for the resolver to do + it's work. + """ + + def __init__(self, ebuilds={}, installed={}, profile={}): + """ + ebuilds: cpv -> metadata mapping simulating avaiable ebuilds. + installed: cpv -> metadata mapping simulating installed packages. + If a metadata key is missing, it gets a default value. + profile: settings defined by the profile. + """ + self.root = tempfile.mkdtemp() + os.path.sep + self.portdir = os.path.join(self.root, "usr/portage") + self.vdbdir = os.path.join(self.root, "var/db/pkg") + os.makedirs(self.portdir) + os.makedirs(self.vdbdir) + + self._create_ebuilds(ebuilds) + self._create_installed(installed) + self._create_profile(ebuilds, installed, profile) + + self.settings, self.trees = self._load_config() + + self._create_ebuild_manifests(ebuilds) + + def _create_ebuilds(self, ebuilds): + for cpv in ebuilds: + a = Atom("=" + cpv) + ebuild_dir = os.path.join(self.portdir, a.cp) + ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild") + try: + os.makedirs(ebuild_dir) + except os.error: + pass + + metadata = ebuilds[cpv] + eapi = metadata.get("EAPI", 0) + slot = metadata.get("SLOT", 0) + keywords = metadata.get("KEYWORDS", "x86") + iuse = metadata.get("IUSE", "") + depend = metadata.get("DEPEND", "") + rdepend = metadata.get("RDEPEND", None) + pdepend = metadata.get("PDEPEND", None) + + f = open(ebuild_path, "w") + f.write('EAPI="' + str(eapi) + '"\n') + f.write('SLOT="' + str(slot) + '"\n') + f.write('KEYWORDS="' + str(keywords) + '"\n') + f.write('IUSE="' + str(iuse) + '"\n') + f.write('DEPEND="' + str(depend) + '"\n') + if rdepend is not None: + f.write('RDEPEND="' + str(rdepend) + '"\n') + if rdepend is not None: + f.write('PDEPEND="' + str(pdepend) + '"\n') + f.close() + + def _create_ebuild_manifests(self, ebuilds): + for cpv in ebuilds: + a = Atom("=" + cpv) + ebuild_dir = os.path.join(self.portdir, a.cp) + ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild") + + portage.util.noiselimit = -1 + tmpsettings = config(clone=self.settings) + portdb = self.trees[self.root]["porttree"].dbapi + portage.doebuild(ebuild_path, "digest", self.root, tmpsettings, + tree="porttree", mydbapi=portdb) + portage.util.noiselimit = 0 + + def _create_installed(self, installed): + for cpv in installed: + a = Atom("=" + cpv) + vdb_pkg_dir = os.path.join(self.vdbdir, a.cpv) + try: + os.makedirs(vdb_pkg_dir) + except os.error: + pass + + metadata = installed[cpv] + eapi = metadata.get("EAPI", 0) + slot = metadata.get("SLOT", 0) + keywords = metadata.get("KEYWORDS", "~x86") + iuse = metadata.get("IUSE", "") + use = metadata.get("USE", "") + depend = metadata.get("DEPEND", "") + rdepend = metadata.get("RDEPEND", None) + pdepend = metadata.get("PDEPEND", None) + + def write_key(key, value): + f = open(os.path.join(vdb_pkg_dir, key), "w") + f.write(str(value) + "\n") + f.close() + + write_key("EAPI", eapi) + write_key("SLOT", slot) + write_key("KEYWORDS", keywords) + write_key("IUSE", iuse) + write_key("USE", use) + write_key("DEPEND", depend) + if rdepend is not None: + write_key("RDEPEND", rdepend) + if rdepend is not None: + write_key("PDEPEND", pdepend) + + def _create_profile(self, ebuilds, installed, profile): + #Create $PORTDIR/profiles/categories + categories = set() + for cpv in chain(ebuilds.keys(), installed.keys()): + categories.add(catsplit(cpv)[0]) + + profile_dir = os.path.join(self.portdir, "profiles") + try: + os.makedirs(profile_dir) + except os.error: + pass + + categories_file = os.path.join(profile_dir, "categories") + + f = open(categories_file, "w") + for cat in categories: + f.write(cat + "\n") + f.close() + + #Create $PORTDIR/eclass (we fail to digest the ebuilds if it's not there) + os.makedirs(os.path.join(self.portdir, "eclass")) + + if profile: + #This is meant to allow the consumer to set up his own profile, + #with package.mask and what not. + raise NotImplentedError() + + def _load_config(self): + env = { "PORTDIR": self.portdir, "ROOT": self.root, "ACCEPT_KEYWORDS": "x86"} + settings = config(config_root=self.root, target_root=self.root, local_config=False, env=env) + settings.lock() + + trees = { + self.root: { + "virtuals": settings.getvirtuals(), + "vartree": vartree(self.root, categories=settings.categories, settings=settings), + "porttree": portagetree(self.root, settings=settings), + "bintree": binarytree(self.root, os.path.join(self.root, "usr/portage/packages"), settings=settings) + } + } + + for root, root_trees in trees.items(): + settings = root_trees["vartree"].settings + settings._init_dirs() + setconfig = load_default_config(settings, root_trees) + root_trees["root_config"] = RootConfig(settings, root_trees, setconfig) + + return settings, trees + + def run(self, myfiles, myopts={}, myaction=None): + myopts["--pretend"] = True + myopts["--quiet"] = True + myopts["--root"] = self.root + myopts["--config-root"] = self.root + myopts["--root-deps"] = "rdeps" + # Add a fake _test_ option that can be used for + # conditional test code. + myopts["_test_"] = True + + portage.util.noiselimit = -2 + myparams = create_depgraph_params(myopts, myaction) + success, mydepgraph, favorites = backtrack_depgraph( + self.settings, self.trees, myopts, myparams, myaction, myfiles, None) + result = ResolverPlaygroundResult(success, mydepgraph, favorites) + portage.util.noiselimit = 0 + + return result + + def cleanup(self): + shutil.rmtree(self.root) + +class ResolverPlaygroundResult(object): + def __init__(self, success, mydepgraph, favorites): + self.success = success + self.depgraph = mydepgraph + self.favorites = favorites + self.mergelist = None + self.use_changes = None + self.unstable_keywords = None + + if self.depgraph._dynamic_config._serialized_tasks_cache is not None: + self.mergelist = [] + for x in self.depgraph._dynamic_config._serialized_tasks_cache: + if isinstance(x, Blocker): + self.mergelist.append(x.atom) + else: + self.mergelist.append(x.cpv) + + if self.depgraph._dynamic_config._needed_use_config_changes: + self.use_changes = {} + for pkg, needed_use_config_changes in \ + self.depgraph._dynamic_config._needed_use_config_changes.items(): + new_use, changes = needed_use_config_changes + self.use_changes[pkg.cpv] = changes + + if self.depgraph._dynamic_config._needed_unstable_keywords: + self.unstable_keywords = set() + for pkg in self.depgraph._dynamic_config._needed_unstable_keywords: + self.unstable_keywords.add(pkg.cpv) |