1 # Copyright 2010-2012 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
4 from itertools import permutations
9 from portage import shutil
10 from portage.const import (GLOBAL_CONFIG_PATH, PORTAGE_BASE_PATH,
12 from portage.dep import Atom, _repo_separator
13 from portage.package.ebuild.config import config
14 from portage.package.ebuild.digestgen import digestgen
15 from portage._sets import load_default_config
16 from portage._sets.base import InternalPackageSet
17 from portage.util import ensure_dirs, normalize_path
18 from portage.versions import catsplit
21 from _emerge.actions import calc_depclean
22 from _emerge.Blocker import Blocker
23 from _emerge.create_depgraph_params import create_depgraph_params
24 from _emerge.depgraph import backtrack_depgraph
25 from _emerge.RootConfig import RootConfig
27 if sys.hexversion >= 0x3000000:
30 class ResolverPlayground(object):
32 This class helps to create the necessary files on disk and
33 the needed settings instances, etc. for the resolver to do
37 config_files = frozenset(("eapi", "make.conf", "package.accept_keywords", "package.use",
38 "package.use.stable.mask", "package.mask", "package.keywords",
39 "package.unmask", "package.properties", "package.license", "use.mask", "use.force",
42 metadata_xml_template = """<?xml version="1.0" encoding="UTF-8"?>
43 <!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
47 <email>maintainer-needed@gentoo.org</email>
48 <description>Description of the maintainership</description>
50 <longdescription>Long description of the package</longdescription>
57 def __init__(self, ebuilds={}, binpkgs={}, installed={}, profile={}, repo_configs={}, \
58 user_config={}, sets={}, world=[], world_sets=[], distfiles={}, debug=False):
60 ebuilds: cpv -> metadata mapping simulating available ebuilds.
61 installed: cpv -> metadata mapping simulating installed packages.
62 If a metadata key is missing, it gets a default value.
63 profile: settings defined by the profile.
66 self.eprefix = normalize_path(tempfile.mkdtemp())
67 self.eroot = self.eprefix + os.sep
68 self.distdir = os.path.join(self.eroot, "var", "portage", "distfiles")
69 self.pkgdir = os.path.join(self.eprefix, "pkgdir")
70 self.portdir = os.path.join(self.eroot, "usr/portage")
71 self.vdbdir = os.path.join(self.eroot, "var/db/pkg")
72 os.makedirs(self.portdir)
73 os.makedirs(self.vdbdir)
76 portage.util.noiselimit = -2
79 #Make sure the main repo is always created
80 self._get_repo_dir("test_repo")
82 self._create_distfiles(distfiles)
83 self._create_ebuilds(ebuilds)
84 self._create_binpkgs(binpkgs)
85 self._create_installed(installed)
86 self._create_profile(ebuilds, installed, profile, repo_configs, user_config, sets)
87 self._create_world(world, world_sets)
89 self.settings, self.trees = self._load_config()
91 self._create_ebuild_manifests(ebuilds)
93 portage.util.noiselimit = 0
95 def _get_repo_dir(self, repo):
97 Create the repo directory if needed.
99 if repo not in self.repo_dirs:
100 if repo == "test_repo":
101 repo_path = self.portdir
103 repo_path = os.path.join(self.eroot, "usr", "local", repo)
105 self.repo_dirs[repo] = repo_path
106 profile_path = os.path.join(repo_path, "profiles")
109 os.makedirs(profile_path)
113 repo_name_file = os.path.join(profile_path, "repo_name")
114 f = open(repo_name_file, "w")
115 f.write("%s\n" % repo)
118 return self.repo_dirs[repo]
120 def _create_distfiles(self, distfiles):
121 os.makedirs(self.distdir)
122 for k, v in distfiles.items():
123 with open(os.path.join(self.distdir, k), 'wb') as f:
126 def _create_ebuilds(self, ebuilds):
128 a = Atom("=" + cpv, allow_repo=True)
133 metadata = ebuilds[cpv].copy()
134 copyright_header = metadata.pop("COPYRIGHT_HEADER", None)
135 desc = metadata.pop("DESCRIPTION", None)
136 eapi = metadata.pop("EAPI", 0)
137 lic = metadata.pop("LICENSE", "")
138 properties = metadata.pop("PROPERTIES", "")
139 slot = metadata.pop("SLOT", 0)
140 keywords = metadata.pop("KEYWORDS", "x86")
141 homepage = metadata.pop("HOMEPAGE", None)
142 src_uri = metadata.pop("SRC_URI", None)
143 iuse = metadata.pop("IUSE", "")
144 provide = metadata.pop("PROVIDE", None)
145 depend = metadata.pop("DEPEND", "")
146 rdepend = metadata.pop("RDEPEND", None)
147 pdepend = metadata.pop("PDEPEND", None)
148 required_use = metadata.pop("REQUIRED_USE", None)
149 misc_content = metadata.pop("MISC_CONTENT", None)
152 raise ValueError("metadata of ebuild '%s' contains unknown keys: %s" % (cpv, metadata.keys()))
154 repo_dir = self._get_repo_dir(repo)
155 ebuild_dir = os.path.join(repo_dir, a.cp)
156 ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild")
158 os.makedirs(ebuild_dir)
162 f = open(ebuild_path, "w")
163 if copyright_header is not None:
164 f.write(copyright_header)
165 f.write('EAPI="' + str(eapi) + '"\n')
167 f.write('DESCRIPTION="%s"\n' % desc)
168 if homepage is not None:
169 f.write('HOMEPAGE="%s"\n' % homepage)
170 if src_uri is not None:
171 f.write('SRC_URI="%s"\n' % src_uri)
172 f.write('LICENSE="' + str(lic) + '"\n')
173 f.write('PROPERTIES="' + str(properties) + '"\n')
174 f.write('SLOT="' + str(slot) + '"\n')
175 f.write('KEYWORDS="' + str(keywords) + '"\n')
176 f.write('IUSE="' + str(iuse) + '"\n')
177 if provide is not None:
178 f.write('PROVIDE="%s"\n' % provide)
179 f.write('DEPEND="' + str(depend) + '"\n')
180 if rdepend is not None:
181 f.write('RDEPEND="' + str(rdepend) + '"\n')
182 if pdepend is not None:
183 f.write('PDEPEND="' + str(pdepend) + '"\n')
184 if required_use is not None:
185 f.write('REQUIRED_USE="' + str(required_use) + '"\n')
186 if misc_content is not None:
187 f.write(misc_content)
190 def _create_ebuild_manifests(self, ebuilds):
191 tmpsettings = config(clone=self.settings)
192 tmpsettings['PORTAGE_QUIET'] = '1'
194 a = Atom("=" + cpv, allow_repo=True)
199 repo_dir = self._get_repo_dir(repo)
200 ebuild_dir = os.path.join(repo_dir, a.cp)
201 ebuild_path = os.path.join(ebuild_dir, a.cpv.split("/")[1] + ".ebuild")
203 portdb = self.trees[self.eroot]["porttree"].dbapi
204 tmpsettings['O'] = ebuild_dir
205 if not digestgen(mysettings=tmpsettings, myportdb=portdb):
206 raise AssertionError('digest creation failed for %s' % ebuild_path)
208 def _create_binpkgs(self, binpkgs):
209 for cpv, metadata in binpkgs.items():
210 a = Atom("=" + cpv, allow_repo=True)
215 cat, pf = catsplit(a.cpv)
216 metadata = metadata.copy()
217 metadata.setdefault("SLOT", "0")
218 metadata.setdefault("KEYWORDS", "x86")
219 metadata.setdefault("BUILD_TIME", "0")
220 metadata["repository"] = repo
221 metadata["CATEGORY"] = cat
224 repo_dir = self.pkgdir
225 category_dir = os.path.join(repo_dir, cat)
226 binpkg_path = os.path.join(category_dir, pf + ".tbz2")
227 ensure_dirs(category_dir)
228 t = portage.xpak.tbz2(binpkg_path)
229 t.recompose_mem(portage.xpak.xpak_mem(metadata))
231 def _create_installed(self, installed):
232 for cpv in installed:
233 a = Atom("=" + cpv, allow_repo=True)
238 vdb_pkg_dir = os.path.join(self.vdbdir, a.cpv)
240 os.makedirs(vdb_pkg_dir)
244 metadata = installed[cpv].copy()
245 eapi = metadata.pop("EAPI", 0)
246 lic = metadata.pop("LICENSE", "")
247 properties = metadata.pop("PROPERTIES", "")
248 slot = metadata.pop("SLOT", 0)
249 build_time = metadata.pop("BUILD_TIME", "0")
250 keywords = metadata.pop("KEYWORDS", "~x86")
251 iuse = metadata.pop("IUSE", "")
252 use = metadata.pop("USE", "")
253 provide = metadata.pop("PROVIDE", None)
254 depend = metadata.pop("DEPEND", "")
255 rdepend = metadata.pop("RDEPEND", None)
256 pdepend = metadata.pop("PDEPEND", None)
257 required_use = metadata.pop("REQUIRED_USE", None)
260 raise ValueError("metadata of installed '%s' contains unknown keys: %s" % (cpv, metadata.keys()))
262 def write_key(key, value):
263 f = open(os.path.join(vdb_pkg_dir, key), "w")
264 f.write(str(value) + "\n")
267 write_key("EAPI", eapi)
268 write_key("BUILD_TIME", build_time)
269 write_key("COUNTER", "0")
270 write_key("LICENSE", lic)
271 write_key("PROPERTIES", properties)
272 write_key("SLOT", slot)
273 write_key("LICENSE", lic)
274 write_key("PROPERTIES", properties)
275 write_key("repository", repo)
276 write_key("KEYWORDS", keywords)
277 write_key("IUSE", iuse)
278 write_key("USE", use)
279 if provide is not None:
280 write_key("PROVIDE", provide)
281 write_key("DEPEND", depend)
282 if rdepend is not None:
283 write_key("RDEPEND", rdepend)
284 if pdepend is not None:
285 write_key("PDEPEND", pdepend)
286 if required_use is not None:
287 write_key("REQUIRED_USE", required_use)
289 def _create_profile(self, ebuilds, installed, profile, repo_configs, user_config, sets):
291 user_config_dir = os.path.join(self.eroot, USER_CONFIG_PATH)
294 os.makedirs(user_config_dir)
298 for repo in self.repo_dirs:
299 repo_dir = self._get_repo_dir(repo)
300 profile_dir = os.path.join(self._get_repo_dir(repo), "profiles")
301 metadata_dir = os.path.join(repo_dir, "metadata")
302 os.makedirs(metadata_dir)
304 #Create $REPO/profiles/categories
307 ebuilds_repo = Atom("="+cpv, allow_repo=True).repo
308 if ebuilds_repo is None:
309 ebuilds_repo = "test_repo"
310 if ebuilds_repo == repo:
311 categories.add(catsplit(cpv)[0])
313 categories_file = os.path.join(profile_dir, "categories")
314 f = open(categories_file, "w")
315 for cat in categories:
319 #Create $REPO/profiles/license_groups
320 license_file = os.path.join(profile_dir, "license_groups")
321 f = open(license_file, "w")
322 f.write("EULA TEST\n")
325 repo_config = repo_configs.get(repo)
327 for config_file, lines in repo_config.items():
328 if config_file not in self.config_files:
329 raise ValueError("Unknown config file: '%s'" % config_file)
331 if config_file in ("layout.conf",):
332 file_name = os.path.join(repo_dir, "metadata", config_file)
334 file_name = os.path.join(profile_dir, config_file)
335 f = open(file_name, "w")
337 f.write("%s\n" % line)
340 #Create $profile_dir/eclass (we fail to digest the ebuilds if it's not there)
341 os.makedirs(os.path.join(repo_dir, "eclass"))
343 if repo == "test_repo":
344 #Create a minimal profile in /usr/portage
345 sub_profile_dir = os.path.join(profile_dir, "default", "linux", "x86", "test_profile")
346 os.makedirs(sub_profile_dir)
348 if not (profile and "eapi" in profile):
349 eapi_file = os.path.join(sub_profile_dir, "eapi")
350 f = open(eapi_file, "w")
354 make_defaults_file = os.path.join(sub_profile_dir, "make.defaults")
355 f = open(make_defaults_file, "w")
356 f.write("ARCH=\"x86\"\n")
357 f.write("ACCEPT_KEYWORDS=\"x86\"\n")
360 use_force_file = os.path.join(sub_profile_dir, "use.force")
361 f = open(use_force_file, "w")
365 parent_file = os.path.join(sub_profile_dir, "parent")
366 f = open(parent_file, "w")
371 for config_file, lines in profile.items():
372 if config_file not in self.config_files:
373 raise ValueError("Unknown config file: '%s'" % config_file)
375 file_name = os.path.join(sub_profile_dir, config_file)
376 f = open(file_name, "w")
378 f.write("%s\n" % line)
381 #Create profile symlink
382 os.symlink(sub_profile_dir, os.path.join(user_config_dir, "make.profile"))
384 #Create minimal herds.xml
385 herds_xml = """<?xml version="1.0" encoding="UTF-8"?>
386 <!DOCTYPE herds SYSTEM "http://www.gentoo.org/dtd/herds.dtd">
387 <?xml-stylesheet href="/xsl/herds.xsl" type="text/xsl" ?>
388 <?xml-stylesheet href="/xsl/guide.xsl" type="text/xsl" ?>
391 <name>base-system</name>
392 <email>base-system@gentoo.org</email>
393 <description>Core system utilities and libraries.</description>
395 <email>base-system@gentoo.orgg</email>
396 <name>Base System</name>
397 <role>Base System Maintainer</role>
402 with open(os.path.join(metadata_dir, "metadata.xml"), 'w') as f:
405 # Write empty entries for each repository, in order to exercise
406 # RepoConfigLoader's repos.conf processing.
407 repos_conf_file = os.path.join(user_config_dir, "repos.conf")
408 f = open(repos_conf_file, "w")
409 for repo in sorted(self.repo_dirs.keys()):
410 f.write("[%s]\n" % repo)
414 for config_file, lines in user_config.items():
415 if config_file not in self.config_files:
416 raise ValueError("Unknown config file: '%s'" % config_file)
418 file_name = os.path.join(user_config_dir, config_file)
419 f = open(file_name, "w")
421 f.write("%s\n" % line)
424 #Create /usr/share/portage/config/make.globals
425 make_globals_path = os.path.join(self.eroot,
426 GLOBAL_CONFIG_PATH.lstrip(os.sep), "make.globals")
427 ensure_dirs(os.path.dirname(make_globals_path))
428 os.symlink(os.path.join(PORTAGE_BASE_PATH, "cnf", "make.globals"),
431 #Create /usr/share/portage/config/sets/portage.conf
432 default_sets_conf_dir = os.path.join(self.eroot, "usr/share/portage/config/sets")
435 os.makedirs(default_sets_conf_dir)
439 provided_sets_portage_conf = \
440 os.path.join(PORTAGE_BASE_PATH, "cnf/sets/portage.conf")
441 os.symlink(provided_sets_portage_conf, os.path.join(default_sets_conf_dir, "portage.conf"))
443 set_config_dir = os.path.join(user_config_dir, "sets")
446 os.makedirs(set_config_dir)
450 for sets_file, lines in sets.items():
451 file_name = os.path.join(set_config_dir, sets_file)
452 f = open(file_name, "w")
454 f.write("%s\n" % line)
457 user_config_dir = os.path.join(self.eroot, "etc", "portage")
460 os.makedirs(user_config_dir)
464 for config_file, lines in user_config.items():
465 if config_file not in self.config_files:
466 raise ValueError("Unknown config file: '%s'" % config_file)
468 file_name = os.path.join(user_config_dir, config_file)
469 f = open(file_name, "w")
471 f.write("%s\n" % line)
474 def _create_world(self, world, world_sets):
475 #Create /var/lib/portage/world
476 var_lib_portage = os.path.join(self.eroot, "var", "lib", "portage")
477 os.makedirs(var_lib_portage)
479 world_file = os.path.join(var_lib_portage, "world")
480 world_set_file = os.path.join(var_lib_portage, "world_sets")
482 f = open(world_file, "w")
484 f.write("%s\n" % atom)
487 f = open(world_set_file, "w")
488 for atom in world_sets:
489 f.write("%s\n" % atom)
492 def _load_config(self):
494 for repo_name in sorted(self.repo_dirs):
495 path = self.repo_dirs[repo_name]
496 if path != self.portdir:
497 portdir_overlay.append(path)
500 "ACCEPT_KEYWORDS": "x86",
501 "DISTDIR" : self.distdir,
502 "PKGDIR": self.pkgdir,
503 "PORTDIR": self.portdir,
504 "PORTDIR_OVERLAY": " ".join(portdir_overlay),
505 'PORTAGE_TMPDIR' : os.path.join(self.eroot, 'var/tmp'),
508 if os.environ.get("NOCOLOR"):
509 env["NOCOLOR"] = os.environ["NOCOLOR"]
511 if os.environ.get("SANDBOX_ON") == "1":
512 # avoid problems from nested sandbox instances
513 env["FEATURES"] = "-sandbox"
515 # Pass along PORTAGE_USERNAME and PORTAGE_GRPNAME since they
516 # need to be inherited by ebuild subprocesses.
517 if 'PORTAGE_USERNAME' in os.environ:
518 env['PORTAGE_USERNAME'] = os.environ['PORTAGE_USERNAME']
519 if 'PORTAGE_GRPNAME' in os.environ:
520 env['PORTAGE_GRPNAME'] = os.environ['PORTAGE_GRPNAME']
522 trees = portage.create_trees(env=env, eprefix=self.eprefix)
523 for root, root_trees in trees.items():
524 settings = root_trees["vartree"].settings
525 settings._init_dirs()
526 setconfig = load_default_config(settings, root_trees)
527 root_trees["root_config"] = RootConfig(settings, root_trees, setconfig)
529 return settings, trees
531 def run(self, atoms, options={}, action=None):
532 options = options.copy()
533 options["--pretend"] = True
535 options["--debug"] = True
538 if options.get("--depclean"):
540 elif options.get("--prune"):
543 if "--usepkgonly" in options:
544 options["--usepkg"] = True
546 global_noiselimit = portage.util.noiselimit
547 global_emergelog_disable = _emerge.emergelog._disable
551 portage.util.noiselimit = -2
552 _emerge.emergelog._disable = True
554 if action in ("depclean", "prune"):
555 rval, cleanlist, ordered, req_pkg_count = \
556 calc_depclean(self.settings, self.trees, None,
557 options, action, InternalPackageSet(initial_atoms=atoms, allow_wildcard=True), None)
558 result = ResolverPlaygroundDepcleanResult( \
559 atoms, rval, cleanlist, ordered, req_pkg_count)
561 params = create_depgraph_params(options, action)
562 success, depgraph, favorites = backtrack_depgraph(
563 self.settings, self.trees, options, params, action, atoms, None)
564 depgraph._show_merge_list()
565 depgraph.display_problems()
566 result = ResolverPlaygroundResult(atoms, success, depgraph, favorites)
568 portage.util.noiselimit = global_noiselimit
569 _emerge.emergelog._disable = global_emergelog_disable
573 def run_TestCase(self, test_case):
574 if not isinstance(test_case, ResolverPlaygroundTestCase):
575 raise TypeError("ResolverPlayground needs a ResolverPlaygroundTestCase")
576 for atoms in test_case.requests:
577 result = self.run(atoms, test_case.options, test_case.action)
578 if not test_case.compare_with_result(result):
582 portdb = self.trees[self.eroot]["porttree"].dbapi
583 portdb.close_caches()
584 portage.dbapi.porttree.portdbapi.portdbapi_instances.remove(portdb)
586 print("\nEROOT=%s" % self.eroot)
588 shutil.rmtree(self.eroot)
590 class ResolverPlaygroundTestCase(object):
592 def __init__(self, request, **kwargs):
593 self.all_permutations = kwargs.pop("all_permutations", False)
594 self.ignore_mergelist_order = kwargs.pop("ignore_mergelist_order", False)
595 self.ambiguous_merge_order = kwargs.pop("ambiguous_merge_order", False)
596 self.check_repo_names = kwargs.pop("check_repo_names", False)
597 self.merge_order_assertions = kwargs.pop("merge_order_assertions", False)
599 if self.all_permutations:
600 self.requests = list(permutations(request))
602 self.requests = [request]
604 self.options = kwargs.pop("options", {})
605 self.action = kwargs.pop("action", None)
606 self.test_success = True
608 self._checks = kwargs.copy()
610 def compare_with_result(self, result):
611 checks = dict.fromkeys(result.checks)
612 for key, value in self._checks.items():
613 if not key in checks:
614 raise KeyError("Not an available check: '%s'" % key)
618 for key, value in checks.items():
619 got = getattr(result, key)
622 if key in result.optional_checks and expected is None:
625 if key == "mergelist":
626 if not self.check_repo_names:
627 #Strip repo names if we don't check them
634 new_got.append(cpv.split(_repo_separator)[0])
639 if isinstance(obj, basestring):
641 new_expected.append(obj)
644 obj.split(_repo_separator)[0])
646 new_expected.append(set())
649 cpv = cpv.split(_repo_separator)[0]
650 new_expected[-1].add(cpv)
651 expected = new_expected
652 if self.ignore_mergelist_order and got is not None:
654 expected = set(expected)
656 if self.ambiguous_merge_order and got:
657 expected_stack = list(reversed(expected))
658 got_stack = list(reversed(got))
661 while got_stack and expected_stack:
662 got_token = got_stack.pop()
663 expected_obj = expected_stack.pop()
664 if isinstance(expected_obj, basestring):
665 new_expected.append(expected_obj)
666 if got_token == expected_obj:
668 # result doesn't match, so stop early
671 expected_obj = set(expected_obj)
673 expected_obj.remove(got_token)
675 # result doesn't match, so stop early
678 new_expected.append(got_token)
679 while got_stack and expected_obj:
680 got_token = got_stack.pop()
682 expected_obj.remove(got_token)
686 new_expected.append(got_token)
688 # result doesn't match, so stop early
691 # result does not match, so stop early
693 new_expected.append(tuple(expected_obj))
696 # result does not match, add leftovers to new_expected
698 expected_stack.reverse()
699 new_expected.extend(expected_stack)
700 expected = new_expected
702 if match and self.merge_order_assertions:
703 for node1, node2 in self.merge_order_assertions:
704 if not (got.index(node1) < got.index(node2)):
705 fail_msgs.append("atoms: (" + \
706 ", ".join(result.atoms) + "), key: " + \
707 ("merge_order_assertions, expected: %s" % \
708 str((node1, node2))) + \
709 ", got: " + str(got))
711 elif key in ("unstable_keywords", "needed_p_mask_changes") and expected is not None:
712 expected = set(expected)
715 fail_msgs.append("atoms: (" + ", ".join(result.atoms) + "), key: " + \
716 key + ", expected: " + str(expected) + ", got: " + str(got))
718 self.test_success = False
719 self.fail_msg = "\n".join(fail_msgs)
723 class ResolverPlaygroundResult(object):
726 "success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions",
727 "circular_dependency_solutions", "needed_p_mask_changes",
732 def __init__(self, atoms, success, mydepgraph, favorites):
734 self.success = success
735 self.depgraph = mydepgraph
736 self.favorites = favorites
737 self.mergelist = None
738 self.use_changes = None
739 self.license_changes = None
740 self.unstable_keywords = None
741 self.needed_p_mask_changes = None
742 self.slot_collision_solutions = None
743 self.circular_dependency_solutions = None
745 if self.depgraph._dynamic_config._serialized_tasks_cache is not None:
747 for x in self.depgraph._dynamic_config._serialized_tasks_cache:
748 if isinstance(x, Blocker):
749 self.mergelist.append(x.atom)
752 if x.metadata["repository"] != "test_repo":
753 repo_str = _repo_separator + x.metadata["repository"]
754 mergelist_str = x.cpv + repo_str
756 if x.operation == "merge":
760 mergelist_str = "[%s]%s" % (desc, mergelist_str)
761 self.mergelist.append(mergelist_str)
763 if self.depgraph._dynamic_config._needed_use_config_changes:
764 self.use_changes = {}
765 for pkg, needed_use_config_changes in \
766 self.depgraph._dynamic_config._needed_use_config_changes.items():
767 new_use, changes = needed_use_config_changes
768 self.use_changes[pkg.cpv] = changes
770 if self.depgraph._dynamic_config._needed_unstable_keywords:
771 self.unstable_keywords = set()
772 for pkg in self.depgraph._dynamic_config._needed_unstable_keywords:
773 self.unstable_keywords.add(pkg.cpv)
775 if self.depgraph._dynamic_config._needed_p_mask_changes:
776 self.needed_p_mask_changes = set()
777 for pkg in self.depgraph._dynamic_config._needed_p_mask_changes:
778 self.needed_p_mask_changes.add(pkg.cpv)
780 if self.depgraph._dynamic_config._needed_license_changes:
781 self.license_changes = {}
782 for pkg, missing_licenses in self.depgraph._dynamic_config._needed_license_changes.items():
783 self.license_changes[pkg.cpv] = missing_licenses
785 if self.depgraph._dynamic_config._slot_conflict_handler is not None:
786 self.slot_collision_solutions = []
787 handler = self.depgraph._dynamic_config._slot_conflict_handler
789 for change in handler.changes:
792 new_change[pkg.cpv] = change[pkg]
793 self.slot_collision_solutions.append(new_change)
795 if self.depgraph._dynamic_config._circular_dependency_handler is not None:
796 handler = self.depgraph._dynamic_config._circular_dependency_handler
797 sol = handler.solutions
798 self.circular_dependency_solutions = dict( zip([x.cpv for x in sol.keys()], sol.values()) )
800 class ResolverPlaygroundDepcleanResult(object):
803 "success", "cleanlist", "ordered", "req_pkg_count",
806 "ordered", "req_pkg_count",
809 def __init__(self, atoms, rval, cleanlist, ordered, req_pkg_count):
811 self.success = rval == 0
812 self.cleanlist = cleanlist
813 self.ordered = ordered
814 self.req_pkg_count = req_pkg_count