summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pym/_emerge/depgraph.py127
-rw-r--r--pym/portage/package/ebuild/getmaskingstatus.py2
-rw-r--r--pym/portage/tests/resolver/ResolverPlayground.py8
-rw-r--r--pym/portage/tests/resolver/test_autounmask.py39
4 files changed, 139 insertions, 37 deletions
diff --git a/pym/_emerge/depgraph.py b/pym/_emerge/depgraph.py
index 6a7eb04b7..fe375b7bb 100644
--- a/pym/_emerge/depgraph.py
+++ b/pym/_emerge/depgraph.py
@@ -122,7 +122,7 @@ class _frozen_depgraph_config(object):
class _dynamic_depgraph_config(object):
def __init__(self, depgraph, myparams, allow_backtracking,
- runtime_pkg_mask, needed_unstable_keywords, needed_use_config_changes):
+ runtime_pkg_mask, needed_unstable_keywords, needed_use_config_changes, needed_license_changes):
self.myparams = myparams.copy()
self._vdb_loaded = False
self._allow_backtracking = allow_backtracking
@@ -206,6 +206,11 @@ class _dynamic_depgraph_config(object):
else:
self._needed_unstable_keywords = needed_unstable_keywords.copy()
+ if needed_license_changes is None:
+ self._needed_license_changes = {}
+ else:
+ self._needed_license_changes = needed_license_changes.copy()
+
if needed_use_config_changes is None:
self._needed_use_config_changes = {}
else:
@@ -295,13 +300,14 @@ class depgraph(object):
def __init__(self, settings, trees, myopts, myparams, spinner,
frozen_config=None, runtime_pkg_mask=None, needed_unstable_keywords=None, \
- needed_use_config_changes=None, allow_backtracking=False):
+ needed_use_config_changes=None, needed_license_changes=None, allow_backtracking=False):
if frozen_config is None:
frozen_config = _frozen_depgraph_config(settings, trees,
myopts, spinner)
self._frozen_config = frozen_config
self._dynamic_config = _dynamic_depgraph_config(self, myparams,
- allow_backtracking, runtime_pkg_mask, needed_unstable_keywords, needed_use_config_changes)
+ allow_backtracking, runtime_pkg_mask, needed_unstable_keywords, \
+ needed_use_config_changes, needed_license_changes)
self._select_atoms = self._select_atoms_highest_available
self._select_package = self._select_pkg_highest_available
@@ -1900,7 +1906,9 @@ class depgraph(object):
if set(self._dynamic_config.digraph).intersection( \
self._dynamic_config._needed_unstable_keywords) or \
set(self._dynamic_config.digraph).intersection( \
- self._dynamic_config._needed_use_config_changes) :
+ self._dynamic_config._needed_use_config_changes) or \
+ set(self._dynamic_config.digraph).intersection( \
+ self._dynamic_config._needed_license_changes) :
#We failed if the user needs to change the configuration
return False, myfavorites
@@ -2519,23 +2527,21 @@ class depgraph(object):
not self._want_installed_pkg(pkg):
pkg = None
- for allow_unstable_keywords in False, True:
+ for only_use_changes in True, False:
if pkg is not None:
break
pkg, existing = \
self._wrapped_select_pkg_highest_available_imp(
root, atom, onlydeps=onlydeps,
- allow_use_changes=True, allow_unstable_keywords=allow_unstable_keywords)
+ allow_use_changes=True,
+ allow_unstable_keywords=(not only_use_changes),
+ allow_license_changes=(not only_use_changes))
if pkg is not None and \
pkg.installed and \
not self._want_installed_pkg(pkg):
pkg = None
-
- if pkg is not None and \
- not pkg.visible and allow_unstable_keywords:
- self._dynamic_config._needed_unstable_keywords.add(pkg)
if self._dynamic_config._need_restart:
return None, None
@@ -2547,26 +2553,59 @@ class depgraph(object):
return pkg, existing
- def _pkg_visibility_check(self, pkg, allow_unstable_keywords=False):
- if pkg.visible:
- return True
+ def _pkg_visibility_check(self, pkg, allow_unstable_keywords=False, allow_license_changes=False):
- if pkg in self._dynamic_config._needed_unstable_keywords:
+ if pkg.visible:
return True
- if not allow_unstable_keywords:
- return False
-
pkgsettings = self._frozen_config.pkgsettings[pkg.root]
root_config = self._frozen_config.roots[pkg.root]
mreasons = _get_masking_status(pkg, pkgsettings, root_config, use=self._pkg_use_enabled(pkg))
- if len(mreasons) == 1 and \
- mreasons[0].unmask_hint and \
- mreasons[0].unmask_hint.key == 'unstable keyword':
+
+ masked_by_unstable_keywords = False
+ missing_licenses = None
+ masked_by_something_else = False
+
+ for reason in mreasons:
+ hint = reason.unmask_hint
+
+ if hint is None:
+ masked_by_something_else = True
+ elif hint.key == "unstable keyword":
+ masked_by_unstable_keywords = True
+ elif hint.key == "license":
+ missing_licenses = hint.value
+ else:
+ masked_by_something_else = True
+
+ if masked_by_something_else:
+ return False
+
+ if pkg in self._dynamic_config._needed_unstable_keywords:
+ #If the package is already keyworded, remove the mask.
+ masked_by_unstable_keywords = False
+
+ if missing_licenses:
+ #If the needed licenses are already unmasked, remove the mask.
+ missing_licenses.difference_update(self._dynamic_config._needed_license_changes.get(pkg, set()))
+
+ if not (masked_by_unstable_keywords or missing_licenses):
+ #Package has already been unmasked.
return True
- else:
+
+ if (masked_by_unstable_keywords and not allow_unstable_keywords) or \
+ (missing_licenses and not allow_license_changes):
+ #We are not allowed to do the needed changes.
return False
+ if masked_by_unstable_keywords:
+ self._dynamic_config._needed_unstable_keywords.add(pkg)
+
+ if missing_licenses:
+ self._dynamic_config._needed_license_changes.setdefault(pkg, set()).update(missing_licenses)
+
+ return True
+
def _pkg_use_enabled(self, pkg, target_use=None):
"""
If target_use is None, returns pkg.use.enabled + changes in _needed_use_config_changes.
@@ -2646,7 +2685,7 @@ class depgraph(object):
return new_use
def _wrapped_select_pkg_highest_available_imp(self, root, atom, onlydeps=False, \
- allow_use_changes=False, allow_unstable_keywords=False):
+ allow_use_changes=False, allow_unstable_keywords=False, allow_license_changes=False):
root_config = self._frozen_config.roots[root]
pkgsettings = self._frozen_config.pkgsettings[root]
dbs = self._dynamic_config._filtered_trees[root]["dbs"]
@@ -2748,7 +2787,9 @@ class depgraph(object):
# were installed can be automatically downgraded
# to an unmasked version.
- if not self._pkg_visibility_check(pkg, allow_unstable_keywords=allow_unstable_keywords):
+ if not self._pkg_visibility_check(pkg, \
+ allow_unstable_keywords=allow_unstable_keywords,
+ allow_license_changes=allow_license_changes):
continue
# Enable upgrade or downgrade to a version
@@ -2783,7 +2824,8 @@ class depgraph(object):
continue
else:
if not self._pkg_visibility_check(pkg_eb, \
- allow_unstable_keywords=allow_unstable_keywords):
+ allow_unstable_keywords=allow_unstable_keywords,
+ allow_license_changes=allow_license_changes):
continue
# Calculation of USE for unbuilt ebuilds is relatively
@@ -3007,12 +3049,14 @@ class depgraph(object):
if avoid_update:
for pkg in matched_packages:
if pkg.installed and self._pkg_visibility_check(pkg, \
- allow_unstable_keywords=allow_unstable_keywords):
+ allow_unstable_keywords=allow_unstable_keywords,
+ allow_license_changes=allow_license_changes):
return pkg, existing_node
bestmatch = portage.best(
[pkg.cpv for pkg in matched_packages \
- if self._pkg_visibility_check(pkg, allow_unstable_keywords=allow_unstable_keywords)])
+ if self._pkg_visibility_check(pkg, allow_unstable_keywords=allow_unstable_keywords,
+ allow_license_changes=allow_license_changes)])
if not bestmatch:
# all are masked, so ignore visibility
bestmatch = portage.best(
@@ -5422,14 +5466,13 @@ class depgraph(object):
pkgsettings = self._frozen_config.pkgsettings[pkg.root]
mreasons = _get_masking_status(pkg, pkgsettings, pkg.root_config,
use=self._pkg_use_enabled(pkg))
- if len(mreasons) == 1 and \
- mreasons[0].unmask_hint and \
- mreasons[0].unmask_hint.key == 'unstable keyword':
- keyword = mreasons[0].unmask_hint.value
- else:
- keyword = '~' + pkgsettings.get('ARCH', '*')
- unstable_keyword_msg.append(get_dep_chain(pkg))
- unstable_keyword_msg.append("=%s %s\n" % (pkg.cpv, keyword))
+ for reason in mreasons:
+ if reason.unmask_hint and \
+ reason.unmask_hint.key == 'unstable keyword':
+ keyword = reason.unmask_hint.value
+
+ unstable_keyword_msg.append(get_dep_chain(pkg))
+ unstable_keyword_msg.append("=%s %s\n" % (pkg.cpv, keyword))
use_changes_msg = []
for pkg, needed_use_config_change in self._dynamic_config._needed_use_config_changes.items():
@@ -5445,6 +5488,13 @@ class depgraph(object):
use_changes_msg.append(get_dep_chain(pkg))
use_changes_msg.append("=%s %s\n" % (pkg.cpv, " ".join(adjustments)))
+ license_msg = []
+ for pkg, missing_licenses in self._dynamic_config._needed_license_changes.items():
+ self._show_merge_list()
+ if pkg in self._dynamic_config.digraph:
+ license_msg.append(get_dep_chain(pkg))
+ license_msg.append("=%s %s\n" % (pkg.cpv, " ".join(sorted(missing_licenses))))
+
if unstable_keyword_msg:
writemsg_stdout("\nThe following " + colorize("BAD", "keyword changes") + \
" are necessary to proceed:\n", noiselevel=-1)
@@ -5455,6 +5505,11 @@ class depgraph(object):
" are necessary to proceed:\n", noiselevel=-1)
writemsg_stdout("".join(use_changes_msg), noiselevel=-1)
+ if license_msg:
+ writemsg_stdout("\nThe following " + colorize("BAD", "license changes") + \
+ " are necessary to proceed:\n", noiselevel=-1)
+ writemsg_stdout("".join(license_msg), noiselevel=-1)
+
# TODO: Add generic support for "set problem" handlers so that
# the below warnings aren't special cases for world only.
@@ -5849,7 +5904,9 @@ class depgraph(object):
"runtime_pkg_mask":
self._dynamic_config._runtime_pkg_mask.copy(),
"needed_use_config_changes":
- self._dynamic_config._needed_use_config_changes.copy()
+ self._dynamic_config._needed_use_config_changes.copy(),
+ "needed_license_changes":
+ self._dynamic_config._needed_license_changes.copy(),
}
diff --git a/pym/portage/package/ebuild/getmaskingstatus.py b/pym/portage/package/ebuild/getmaskingstatus.py
index 434b4b2eb..1eb6afed2 100644
--- a/pym/portage/package/ebuild/getmaskingstatus.py
+++ b/pym/portage/package/ebuild/getmaskingstatus.py
@@ -156,7 +156,7 @@ def _getmaskingstatus(mycpv, settings, portdb):
if x in allowed_tokens]
msg = license_split[:]
msg.append("license(s)")
- rValue.append(_MaskReason("LICENSE", " ".join(msg)))
+ rValue.append(_MaskReason("LICENSE", " ".join(msg), _UnmaskHint("license", set(missing_licenses))))
except portage.exception.InvalidDependString as e:
rValue.append(_MaskReason("invalid", "LICENSE: "+str(e)))
diff --git a/pym/portage/tests/resolver/ResolverPlayground.py b/pym/portage/tests/resolver/ResolverPlayground.py
index 52198b6f1..f05bdf184 100644
--- a/pym/portage/tests/resolver/ResolverPlayground.py
+++ b/pym/portage/tests/resolver/ResolverPlayground.py
@@ -522,7 +522,7 @@ class ResolverPlaygroundTestCase(object):
class ResolverPlaygroundResult(object):
checks = (
- "success", "mergelist", "use_changes", "unstable_keywords", "slot_collision_solutions",
+ "success", "mergelist", "use_changes", "license_changes", "unstable_keywords", "slot_collision_solutions",
"circular_dependency_solutions",
)
optional_checks = (
@@ -535,6 +535,7 @@ class ResolverPlaygroundResult(object):
self.favorites = favorites
self.mergelist = None
self.use_changes = None
+ self.license_changes = None
self.unstable_keywords = None
self.slot_collision_solutions = None
self.circular_dependency_solutions = None
@@ -562,6 +563,11 @@ class ResolverPlaygroundResult(object):
for pkg in self.depgraph._dynamic_config._needed_unstable_keywords:
self.unstable_keywords.add(pkg.cpv)
+ if self.depgraph._dynamic_config._needed_license_changes:
+ self.license_changes = {}
+ for pkg, missing_licenses in self.depgraph._dynamic_config._needed_license_changes.items():
+ self.license_changes[pkg.cpv] = missing_licenses
+
if self.depgraph._dynamic_config._slot_conflict_handler is not None:
self.slot_collision_solutions = []
handler = self.depgraph._dynamic_config._slot_conflict_handler
diff --git a/pym/portage/tests/resolver/test_autounmask.py b/pym/portage/tests/resolver/test_autounmask.py
index df541120d..ce3ce38f0 100644
--- a/pym/portage/tests/resolver/test_autounmask.py
+++ b/pym/portage/tests/resolver/test_autounmask.py
@@ -187,3 +187,42 @@ class AutounmaskTestCase(TestCase):
self.assertEqual(test_case.test_success, True, test_case.fail_msg)
finally:
playground.cleanup()
+
+ def testAutounmaskForLicenses(self):
+
+ ebuilds = {
+ "dev-libs/A-1": { "LICENSE": "TEST" },
+ "dev-libs/B-1": { "LICENSE": "TEST", "IUSE": "foo", "KEYWORDS": "~x86"},
+ "dev-libs/C-1": { "DEPEND": "dev-libs/B[foo]", "EAPI": 2 },
+ }
+
+ test_cases = (
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-1"],
+ options = {"--autounmask": False},
+ success = False),
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/A-1"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["dev-libs/A-1"],
+ license_changes = { "dev-libs/A-1": set(["TEST"]) }),
+
+ #Test license+keyword+use change at once.
+ ResolverPlaygroundTestCase(
+ ["=dev-libs/C-1"],
+ options = {"--autounmask": True},
+ success = False,
+ mergelist = ["dev-libs/B-1", "dev-libs/C-1"],
+ license_changes = { "dev-libs/B-1": set(["TEST"]) },
+ unstable_keywords = ["dev-libs/B-1"],
+ use_changes = { "dev-libs/B-1": { "foo": True } }),
+ )
+
+ playground = ResolverPlayground(ebuilds=ebuilds)
+ try:
+ for test_case in test_cases:
+ playground.run_TestCase(test_case)
+ self.assertEqual(test_case.test_success, True, test_case.fail_msg)
+ finally:
+ playground.cleanup()