-# Copyright 2010-2011 Gentoo Foundation
+# Copyright 2010-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
from itertools import permutations
-import shutil
import sys
import tempfile
import portage
from portage import os
-from portage.const import PORTAGE_BASE_PATH
-from portage.dbapi.vartree import vartree
-from portage.dbapi.porttree import portagetree
-from portage.dbapi.bintree import binarytree
+from portage import shutil
+from portage.const import (GLOBAL_CONFIG_PATH, PORTAGE_BASE_PATH,
+ USER_CONFIG_PATH)
from portage.dep import Atom, _repo_separator
from portage.package.ebuild.config import config
from portage.package.ebuild.digestgen import digestgen
from portage._sets import load_default_config
from portage._sets.base import InternalPackageSet
+from portage.util import ensure_dirs, normalize_path
from portage.versions import catsplit
import _emerge
its work.
"""
- config_files = frozenset(("package.use", "package.mask", "package.keywords", \
- "package.unmask", "package.properties", "package.license", "use.mask", "use.force"))
-
- def __init__(self, ebuilds={}, installed={}, profile={}, repo_configs={}, \
- user_config={}, sets={}, world=[], debug=False):
+ config_files = frozenset(("eapi", "layout.conf", "make.conf", "package.accept_keywords",
+ "package.keywords", "package.license", "package.mask", "package.properties",
+ "package.unmask", "package.use", "package.use.aliases", "package.use.stable.mask",
+ "use.aliases", "use.force", "use.mask", "layout.conf"))
+
+ metadata_xml_template = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+<herd>%(herd)s</herd>
+<maintainer>
+<email>maintainer-needed@gentoo.org</email>
+<description>Description of the maintainership</description>
+</maintainer>
+<longdescription>Long description of the package</longdescription>
+<use>
+%(flags)s
+</use>
+</pkgmetadata>
+"""
+
+ def __init__(self, ebuilds={}, binpkgs={}, installed={}, profile={}, repo_configs={}, \
+ user_config={}, sets={}, world=[], world_sets=[], distfiles={},
+ targetroot=False, debug=False):
"""
ebuilds: cpv -> metadata mapping simulating available ebuilds.
installed: cpv -> metadata mapping simulating installed packages.
profile: settings defined by the profile.
"""
self.debug = debug
- self.root = "/"
- self.eprefix = tempfile.mkdtemp()
- self.eroot = self.root + self.eprefix.lstrip(os.sep) + os.sep
+ self.eprefix = normalize_path(tempfile.mkdtemp())
+ self.eroot = self.eprefix + os.sep
+ if targetroot:
+ self.target_root = os.path.join(self.eroot, 'target_root')
+ else:
+ self.target_root = os.sep
+ self.distdir = os.path.join(self.eroot, "var", "portage", "distfiles")
+ self.pkgdir = os.path.join(self.eprefix, "pkgdir")
self.portdir = os.path.join(self.eroot, "usr/portage")
self.vdbdir = os.path.join(self.eroot, "var/db/pkg")
os.makedirs(self.portdir)
#Make sure the main repo is always created
self._get_repo_dir("test_repo")
+ self._create_distfiles(distfiles)
self._create_ebuilds(ebuilds)
+ self._create_binpkgs(binpkgs)
self._create_installed(installed)
self._create_profile(ebuilds, installed, profile, repo_configs, user_config, sets)
- self._create_world(world)
+ self._create_world(world, world_sets)
self.settings, self.trees = self._load_config()
return self.repo_dirs[repo]
+ def _create_distfiles(self, distfiles):
+ os.makedirs(self.distdir)
+ for k, v in distfiles.items():
+ with open(os.path.join(self.distdir, k), 'wb') as f:
+ f.write(v)
+
def _create_ebuilds(self, ebuilds):
for cpv in ebuilds:
a = Atom("=" + cpv, allow_repo=True)
repo = "test_repo"
metadata = ebuilds[cpv].copy()
- eapi = metadata.pop("EAPI", 0)
- lic = metadata.pop("LICENSE", "")
- properties = metadata.pop("PROPERTIES", "")
- slot = metadata.pop("SLOT", 0)
- keywords = metadata.pop("KEYWORDS", "x86")
- iuse = metadata.pop("IUSE", "")
- depend = metadata.pop("DEPEND", "")
- rdepend = metadata.pop("RDEPEND", None)
- pdepend = metadata.pop("PDEPEND", None)
- required_use = metadata.pop("REQUIRED_USE", None)
-
- if metadata:
- raise ValueError("metadata of ebuild '%s' contains unknown keys: %s" % (cpv, metadata.keys()))
+ copyright_header = metadata.pop("COPYRIGHT_HEADER", None)
+ eapi = metadata.pop("EAPI", "0")
+ misc_content = metadata.pop("MISC_CONTENT", None)
+ metadata.setdefault("DEPEND", "")
+ metadata.setdefault("SLOT", "0")
+ metadata.setdefault("KEYWORDS", "x86")
+ metadata.setdefault("IUSE", "")
+
+ unknown_keys = set(metadata).difference(
+ portage.dbapi.dbapi._known_keys)
+ if unknown_keys:
+ raise ValueError("metadata of ebuild '%s' contains unknown keys: %s" %
+ (cpv, sorted(unknown_keys)))
repo_dir = self._get_repo_dir(repo)
ebuild_dir = os.path.join(repo_dir, a.cp)
pass
f = open(ebuild_path, "w")
- f.write('EAPI="' + str(eapi) + '"\n')
- f.write('LICENSE="' + str(lic) + '"\n')
- f.write('PROPERTIES="' + str(properties) + '"\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 pdepend is not None:
- f.write('PDEPEND="' + str(pdepend) + '"\n')
- if required_use is not None:
- f.write('REQUIRED_USE="' + str(required_use) + '"\n')
+ if copyright_header is not None:
+ f.write(copyright_header)
+ f.write('EAPI="%s"\n' % eapi)
+ for k, v in metadata.items():
+ f.write('%s="%s"\n' % (k, v))
+ if misc_content is not None:
+ f.write(misc_content)
f.close()
def _create_ebuild_manifests(self, ebuilds):
ebuild_dir = os.path.join(repo_dir, a.cp)
ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild")
- portdb = self.trees[self.root]["porttree"].dbapi
+ portdb = self.trees[self.eroot]["porttree"].dbapi
tmpsettings['O'] = ebuild_dir
if not digestgen(mysettings=tmpsettings, myportdb=portdb):
raise AssertionError('digest creation failed for %s' % ebuild_path)
+ def _create_binpkgs(self, binpkgs):
+ for cpv, metadata in binpkgs.items():
+ a = Atom("=" + cpv, allow_repo=True)
+ repo = a.repo
+ if repo is None:
+ repo = "test_repo"
+
+ cat, pf = catsplit(a.cpv)
+ metadata = metadata.copy()
+ metadata.setdefault("SLOT", "0")
+ metadata.setdefault("KEYWORDS", "x86")
+ metadata.setdefault("BUILD_TIME", "0")
+ metadata["repository"] = repo
+ metadata["CATEGORY"] = cat
+ metadata["PF"] = pf
+
+ repo_dir = self.pkgdir
+ category_dir = os.path.join(repo_dir, cat)
+ binpkg_path = os.path.join(category_dir, pf + ".tbz2")
+ ensure_dirs(category_dir)
+ t = portage.xpak.tbz2(binpkg_path)
+ t.recompose_mem(portage.xpak.xpak_mem(metadata))
+
def _create_installed(self, installed):
for cpv in installed:
a = Atom("=" + cpv, allow_repo=True)
pass
metadata = installed[cpv].copy()
- eapi = metadata.pop("EAPI", 0)
- lic = metadata.pop("LICENSE", "")
- properties = metadata.pop("PROPERTIES", "")
- slot = metadata.pop("SLOT", 0)
- keywords = metadata.pop("KEYWORDS", "~x86")
- iuse = metadata.pop("IUSE", "")
- use = metadata.pop("USE", "")
- depend = metadata.pop("DEPEND", "")
- rdepend = metadata.pop("RDEPEND", None)
- pdepend = metadata.pop("PDEPEND", None)
- required_use = metadata.pop("REQUIRED_USE", None)
-
- if metadata:
- raise ValueError("metadata of installed '%s' contains unknown keys: %s" % (cpv, metadata.keys()))
-
- 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("LICENSE", lic)
- write_key("PROPERTIES", properties)
- write_key("SLOT", slot)
- write_key("LICENSE", lic)
- write_key("PROPERTIES", properties)
- write_key("repository", repo)
- 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 pdepend is not None:
- write_key("PDEPEND", pdepend)
- if required_use is not None:
- write_key("REQUIRED_USE", required_use)
+ metadata.setdefault("SLOT", "0")
+ metadata.setdefault("BUILD_TIME", "0")
+ metadata.setdefault("COUNTER", "0")
+ metadata.setdefault("KEYWORDS", "~x86")
+
+ unknown_keys = set(metadata).difference(
+ portage.dbapi.dbapi._known_keys)
+ unknown_keys.discard("BUILD_TIME")
+ unknown_keys.discard("COUNTER")
+ unknown_keys.discard("repository")
+ unknown_keys.discard("USE")
+ if unknown_keys:
+ raise ValueError("metadata of installed '%s' contains unknown keys: %s" %
+ (cpv, sorted(unknown_keys)))
+
+ metadata["repository"] = repo
+ for k, v in metadata.items():
+ with open(os.path.join(vdb_pkg_dir, k), "w") as f:
+ f.write("%s\n" % v)
def _create_profile(self, ebuilds, installed, profile, repo_configs, user_config, sets):
+ user_config_dir = os.path.join(self.eroot, USER_CONFIG_PATH)
+
+ try:
+ os.makedirs(user_config_dir)
+ except os.error:
+ pass
+
for repo in self.repo_dirs:
repo_dir = self._get_repo_dir(repo)
profile_dir = os.path.join(self._get_repo_dir(repo), "profiles")
+ metadata_dir = os.path.join(repo_dir, "metadata")
+ os.makedirs(metadata_dir)
#Create $REPO/profiles/categories
categories = set()
for config_file, lines in repo_config.items():
if config_file not in self.config_files:
raise ValueError("Unknown config file: '%s'" % config_file)
-
- file_name = os.path.join(profile_dir, config_file)
+
+ if config_file in ("layout.conf",):
+ file_name = os.path.join(repo_dir, "metadata", config_file)
+ else:
+ file_name = os.path.join(profile_dir, config_file)
f = open(file_name, "w")
for line in lines:
f.write("%s\n" % line)
sub_profile_dir = os.path.join(profile_dir, "default", "linux", "x86", "test_profile")
os.makedirs(sub_profile_dir)
- eapi_file = os.path.join(sub_profile_dir, "eapi")
- f = open(eapi_file, "w")
- f.write("0\n")
- f.close()
+ if not (profile and "eapi" in profile):
+ eapi_file = os.path.join(sub_profile_dir, "eapi")
+ f = open(eapi_file, "w")
+ f.write("0\n")
+ f.close()
make_defaults_file = os.path.join(sub_profile_dir, "make.defaults")
f = open(make_defaults_file, "w")
f.write("x86\n")
f.close()
+ parent_file = os.path.join(sub_profile_dir, "parent")
+ f = open(parent_file, "w")
+ f.write("..\n")
+ f.close()
+
if profile:
for config_file, lines in profile.items():
if config_file not in self.config_files:
f.close()
#Create profile symlink
- os.makedirs(os.path.join(self.eroot, "etc"))
- os.symlink(sub_profile_dir, os.path.join(self.eroot, "etc", "make.profile"))
-
- user_config_dir = os.path.join(self.eroot, "etc", "portage")
-
- try:
- os.makedirs(user_config_dir)
- except os.error:
- pass
-
+ os.symlink(sub_profile_dir, os.path.join(user_config_dir, "make.profile"))
+
+ #Create minimal herds.xml
+ herds_xml = """<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE herds SYSTEM "http://www.gentoo.org/dtd/herds.dtd">
+<?xml-stylesheet href="/xsl/herds.xsl" type="text/xsl" ?>
+<?xml-stylesheet href="/xsl/guide.xsl" type="text/xsl" ?>
+<herds>
+<herd>
+ <name>base-system</name>
+ <email>base-system@gentoo.org</email>
+ <description>Core system utilities and libraries.</description>
+ <maintainer>
+ <email>base-system@gentoo.orgg</email>
+ <name>Base System</name>
+ <role>Base System Maintainer</role>
+ </maintainer>
+</herd>
+</herds>
+"""
+ with open(os.path.join(metadata_dir, "metadata.xml"), 'w') as f:
+ f.write(herds_xml)
+
+ # Write empty entries for each repository, in order to exercise
+ # RepoConfigLoader's repos.conf processing.
repos_conf_file = os.path.join(user_config_dir, "repos.conf")
f = open(repos_conf_file, "w")
- priority = 0
for repo in sorted(self.repo_dirs.keys()):
f.write("[%s]\n" % repo)
- f.write("LOCATION=%s\n" % self.repo_dirs[repo])
- if repo == "test_repo":
- f.write("PRIORITY=%s\n" % -1000)
- else:
- f.write("PRIORITY=%s\n" % priority)
- priority += 1
+ f.write("\n")
f.close()
- for config_file, lines in user_config.items():
+ portdir_overlay = []
+ for repo_name in sorted(self.repo_dirs):
+ path = self.repo_dirs[repo_name]
+ if path != self.portdir:
+ portdir_overlay.append(path)
+
+ make_conf = {
+ "ACCEPT_KEYWORDS": "x86",
+ "CLEAN_DELAY": "0",
+ "DISTDIR" : self.distdir,
+ "EMERGE_WARNING_DELAY": "0",
+ "PKGDIR": self.pkgdir,
+ "PORTDIR": self.portdir,
+ "PORTAGE_INST_GID": str(portage.data.portage_gid),
+ "PORTAGE_INST_UID": str(portage.data.portage_uid),
+ "PORTDIR_OVERLAY": " ".join("'%s'" % x for x in portdir_overlay),
+ "PORTAGE_TMPDIR": os.path.join(self.eroot, 'var/tmp'),
+ }
+
+ if os.environ.get("NOCOLOR"):
+ make_conf["NOCOLOR"] = os.environ["NOCOLOR"]
+
+ # Pass along PORTAGE_USERNAME and PORTAGE_GRPNAME since they
+ # need to be inherited by ebuild subprocesses.
+ if 'PORTAGE_USERNAME' in os.environ:
+ make_conf['PORTAGE_USERNAME'] = os.environ['PORTAGE_USERNAME']
+ if 'PORTAGE_GRPNAME' in os.environ:
+ make_conf['PORTAGE_GRPNAME'] = os.environ['PORTAGE_GRPNAME']
+
+ make_conf_lines = []
+ for k_v in make_conf.items():
+ make_conf_lines.append('%s="%s"' % k_v)
+
+ if "make.conf" in user_config:
+ make_conf_lines.extend(user_config["make.conf"])
+
+ if not portage.process.sandbox_capable or \
+ os.environ.get("SANDBOX_ON") == "1":
+ # avoid problems from nested sandbox instances
+ make_conf_lines.append('FEATURES="${FEATURES} -sandbox"')
+
+ configs = user_config.copy()
+ configs["make.conf"] = make_conf_lines
+
+ for config_file, lines in configs.items():
if config_file not in self.config_files:
raise ValueError("Unknown config file: '%s'" % config_file)
f.write("%s\n" % line)
f.close()
+ #Create /usr/share/portage/config/make.globals
+ make_globals_path = os.path.join(self.eroot,
+ GLOBAL_CONFIG_PATH.lstrip(os.sep), "make.globals")
+ ensure_dirs(os.path.dirname(make_globals_path))
+ os.symlink(os.path.join(PORTAGE_BASE_PATH, "cnf", "make.globals"),
+ make_globals_path)
+
#Create /usr/share/portage/config/sets/portage.conf
default_sets_conf_dir = os.path.join(self.eroot, "usr/share/portage/config/sets")
f.write("%s\n" % line)
f.close()
- user_config_dir = os.path.join(self.eroot, "etc", "portage")
-
- try:
- os.makedirs(user_config_dir)
- except os.error:
- pass
-
- for config_file, lines in user_config.items():
- if config_file not in self.config_files:
- raise ValueError("Unknown config file: '%s'" % config_file)
-
- file_name = os.path.join(user_config_dir, config_file)
- f = open(file_name, "w")
- for line in lines:
- f.write("%s\n" % line)
- f.close()
-
- def _create_world(self, world):
+ def _create_world(self, world, world_sets):
#Create /var/lib/portage/world
var_lib_portage = os.path.join(self.eroot, "var", "lib", "portage")
os.makedirs(var_lib_portage)
world_file = os.path.join(var_lib_portage, "world")
+ world_set_file = os.path.join(var_lib_portage, "world_sets")
f = open(world_file, "w")
for atom in world:
f.write("%s\n" % atom)
f.close()
- def _load_config(self):
- portdir_overlay = []
- for repo_name in sorted(self.repo_dirs):
- path = self.repo_dirs[repo_name]
- if path != self.portdir:
- portdir_overlay.append(path)
-
- env = {
- "ACCEPT_KEYWORDS": "x86",
- "PORTDIR": self.portdir,
- "PORTDIR_OVERLAY": " ".join(portdir_overlay),
- 'PORTAGE_TMPDIR' : os.path.join(self.eroot, 'var/tmp'),
- }
+ f = open(world_set_file, "w")
+ for atom in world_sets:
+ f.write("%s\n" % atom)
+ f.close()
- # Pass along PORTAGE_USERNAME and PORTAGE_GRPNAME since they
- # need to be inherited by ebuild subprocesses.
- if 'PORTAGE_USERNAME' in os.environ:
- env['PORTAGE_USERNAME'] = os.environ['PORTAGE_USERNAME']
- if 'PORTAGE_GRPNAME' in os.environ:
- env['PORTAGE_GRPNAME'] = os.environ['PORTAGE_GRPNAME']
+ def _load_config(self):
- settings = config(_eprefix=self.eprefix, env=env)
- settings.lock()
+ create_trees_kwargs = {}
+ if self.target_root != os.sep:
+ create_trees_kwargs["target_root"] = self.target_root
- trees = {
- self.root: {
- "vartree": vartree(settings=settings),
- "porttree": portagetree(self.root, settings=settings),
- "bintree": binarytree(self.root,
- os.path.join(self.eroot, "usr/portage/packages"),
- settings=settings)
- }
- }
+ trees = portage.create_trees(env={}, eprefix=self.eprefix,
+ **create_trees_kwargs)
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
+
+ return trees[trees._target_eroot]["vartree"].settings, trees
def run(self, atoms, options={}, action=None):
options = options.copy()
if self.debug:
options["--debug"] = True
+ if action is None:
+ if options.get("--depclean"):
+ action = "depclean"
+ elif options.get("--prune"):
+ action = "prune"
+
+ if "--usepkgonly" in options:
+ options["--usepkg"] = True
+
global_noiselimit = portage.util.noiselimit
global_emergelog_disable = _emerge.emergelog._disable
try:
portage.util.noiselimit = -2
_emerge.emergelog._disable = True
- if options.get("--depclean"):
+ if action in ("depclean", "prune"):
rval, cleanlist, ordered, req_pkg_count = \
calc_depclean(self.settings, self.trees, None,
- options, "depclean", InternalPackageSet(initial_atoms=atoms, allow_wildcard=True), None)
+ options, action, InternalPackageSet(initial_atoms=atoms, allow_wildcard=True), None)
result = ResolverPlaygroundDepcleanResult( \
atoms, rval, cleanlist, ordered, req_pkg_count)
else:
return
def cleanup(self):
- portdb = self.trees[self.root]["porttree"].dbapi
- portdb.close_caches()
- portage.dbapi.porttree.portdbapi.portdbapi_instances.remove(portdb)
+ for eroot in self.trees:
+ portdb = self.trees[eroot]["porttree"].dbapi
+ portdb.close_caches()
+ portage.dbapi.porttree.portdbapi.portdbapi_instances.remove(portdb)
if self.debug:
print("\nEROOT=%s" % self.eroot)
else:
if cpv[:1] == "!":
new_got.append(cpv)
continue
- a = Atom("="+cpv, allow_repo=True)
- new_got.append(a.cpv)
+ new_got.append(cpv.split(_repo_separator)[0])
got = new_got
if expected:
new_expected = []
if obj[:1] == "!":
new_expected.append(obj)
continue
- a = Atom("="+obj, allow_repo=True)
- new_expected.append(a.cpv)
+ new_expected.append(
+ obj.split(_repo_separator)[0])
continue
new_expected.append(set())
for cpv in obj:
- a = Atom("="+cpv, allow_repo=True)
- new_expected[-1].add(a.cpv)
+ if cpv[:1] != "!":
+ cpv = cpv.split(_repo_separator)[0]
+ new_expected[-1].add(cpv)
expected = new_expected
if self.ignore_mergelist_order and got is not None:
got = set(got)
if got_token == expected_obj:
continue
# result doesn't match, so stop early
+ match = False
break
expected_obj = set(expected_obj)
try:
expected_obj.remove(got_token)
except KeyError:
# result doesn't match, so stop early
+ match = False
break
new_expected.append(got_token)
while got_stack and expected_obj:
if self.depgraph._dynamic_config._serialized_tasks_cache is not None:
self.mergelist = []
+ host_root = self.depgraph._frozen_config._running_root.root
for x in self.depgraph._dynamic_config._serialized_tasks_cache:
if isinstance(x, Blocker):
self.mergelist.append(x.atom)
repo_str = ""
if x.metadata["repository"] != "test_repo":
repo_str = _repo_separator + x.metadata["repository"]
- self.mergelist.append(x.cpv + repo_str)
+ mergelist_str = x.cpv + repo_str
+ if x.built:
+ if x.operation == "merge":
+ desc = x.type_name
+ else:
+ desc = x.operation
+ mergelist_str = "[%s]%s" % (desc, mergelist_str)
+ if x.root != host_root:
+ mergelist_str += "{targetroot}"
+ self.mergelist.append(mergelist_str)
if self.depgraph._dynamic_config._needed_use_config_changes:
self.use_changes = {}