summaryrefslogtreecommitdiffstats
path: root/pym/portage/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'pym/portage/__init__.py')
-rw-r--r--pym/portage/__init__.py155
1 files changed, 153 insertions, 2 deletions
diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py
index 129804632..660e114e0 100644
--- a/pym/portage/__init__.py
+++ b/pym/portage/__init__.py
@@ -907,6 +907,9 @@ class config:
self.dirVirtuals = copy.deepcopy(clone.dirVirtuals)
self.treeVirtuals = copy.deepcopy(clone.treeVirtuals)
self.features = copy.deepcopy(clone.features)
+
+ self._accept_license = copy.deepcopy(clone._accept_license)
+ self._plicensedict = copy.deepcopy(clone._plicensedict)
else:
# backupenv is for calculated incremental variables.
@@ -1208,6 +1211,7 @@ class config:
self.pusedict = {}
self.pkeywordsdict = {}
+ self._plicensedict = {}
self.punmaskdict = {}
abs_user_config = os.path.join(config_root,
USER_CONFIG_PATH.lstrip(os.path.sep))
@@ -1260,6 +1264,17 @@ class config:
if not self.pkeywordsdict.has_key(cp):
self.pkeywordsdict[cp] = {}
self.pkeywordsdict[cp][key] = pkgdict[key]
+
+ #package.license
+ licdict = grabdict_package(os.path.join(
+ abs_user_config, "package.license"), recursive=1)
+ for k, v in licdict.iteritems():
+ cp = dep_getkey(k)
+ cp_dict = self._plicensedict.get(cp)
+ if not cp_dict:
+ cp_dict = {}
+ self._plicensedict[cp] = cp_dict
+ cp_dict[k] = self.expandLicenseTokens(v)
#package.unmask
pkgunmasklines = grabfile_package(
@@ -1334,6 +1349,12 @@ class config:
else:
self.pprovideddict[mycatpkg]=[x]
+ # parse licensegroups
+ self._license_groups = {}
+ for x in locations:
+ self._license_groups.update(
+ grabdict(os.path.join(x, "license_groups")))
+
# reasonable defaults; this is important as without USE_ORDER,
# USE will always be "" (nothing set)!
if "USE_ORDER" not in self:
@@ -1369,6 +1390,18 @@ class config:
self["PORTAGE_PYM_PATH"] = PORTAGE_PYM_PATH
self.backup_changes("PORTAGE_PYM_PATH")
+ # Expand license groups
+ # This has to do be done for each config layer before regenerate()
+ # in order for incremental negation to work properly.
+ if local_config:
+ for c in self.configdict.itervalues():
+ v = c.get("ACCEPT_LICENSE")
+ if not v:
+ continue
+ v = " ".join(self.expandLicenseTokens(v.split()))
+ c["ACCEPT_LICENSE"] = v
+ del c, v
+
for var in ("PORTAGE_INST_UID", "PORTAGE_INST_GID"):
try:
self[var] = str(int(self.get(var, "0")))
@@ -1382,6 +1415,20 @@ class config:
self.regenerate()
self.features = portage.util.unique_array(self["FEATURES"].split())
+ if local_config:
+ self._accept_license = \
+ set(self.get("ACCEPT_LICENSE", "").split())
+ # In order to enforce explicit acceptance for restrictive
+ # licenses that require it, "*" will not be allowed in the
+ # user config. Don't enforce this until license groups are
+ # fully implemented in the tree.
+ #self._accept_license.discard("*")
+ if not self._accept_license:
+ self._accept_license = set(["*"])
+ else:
+ # repoman will accept any license
+ self._accept_license = set(["*"])
+
if "gpg" in self.features:
if not os.path.exists(self["PORTAGE_GPG_DIR"]) or \
not os.path.isdir(self["PORTAGE_GPG_DIR"]):
@@ -1437,6 +1484,51 @@ class config:
writemsg("!!! %s\n" % str(e),
noiselevel=-1)
+ def expandLicenseTokens(self, tokens):
+ """ Take a token from ACCEPT_LICENSE or package.license and expand it
+ if it's a group token (indicated by @) or just return it if it's not a
+ group. If a group is negated then negate all group elements."""
+ expanded_tokens = []
+ for x in tokens:
+ expanded_tokens.extend(self._expandLicenseToken(x, None))
+ return expanded_tokens
+
+ def _expandLicenseToken(self, token, traversed_groups):
+ negate = False
+ rValue = []
+ if token.startswith("-"):
+ negate = True
+ license_name = token[1:]
+ else:
+ license_name = token
+ if not license_name.startswith("@"):
+ rValue.append(token)
+ return rValue
+ group_name = license_name[1:]
+ if not traversed_groups:
+ traversed_groups = set()
+ license_group = self._license_groups.get(group_name)
+ if group_name in traversed_groups:
+ writemsg(("Circular license group reference" + \
+ " detected in '%s'\n") % group_name, noiselevel=-1)
+ rValue.append("@"+group_name)
+ elif license_group:
+ traversed_groups.add(group_name)
+ for l in license_group:
+ if l.startswith("-"):
+ writemsg(("Skipping invalid element %s" + \
+ " in license group '%s'\n") % (l, group_name),
+ noiselevel=-1)
+ else:
+ rValue.extend(self._expandLicenseToken(l, traversed_groups))
+ else:
+ writemsg("Undefined license group '%s'\n" % group_name,
+ noiselevel=-1)
+ rValue.append("@"+group_name)
+ if negate:
+ rvalue = ["-" + token for token in rValue]
+ return rValue
+
def validate(self):
"""Validate miscellaneous settings and display warnings if necessary.
(This code was previously in the global scope of portage.py)"""
@@ -1656,6 +1748,49 @@ class config:
if has_changed:
self.reset(keeping_pkg=1,use_cache=use_cache)
+ def getMissingLicenses(self, licenses, cpv):
+ cpdict = self._plicensedict.get(dep_getkey(cpv), None)
+ acceptable_licenses = self._accept_license.copy()
+ if cpdict:
+ for atom in match_to_list(cpv, cpdict.keys()):
+ acceptable_licenses.update(cpdict[atom])
+ if "*" in acceptable_licenses:
+ return []
+ if "?" in licenses:
+ self.setcpv(cpv)
+ license_struct = portage.dep.paren_reduce(licenses)
+ license_struct = portage.dep.use_reduce(
+ license_struct, uselist=self["USE"].split())
+ license_struct = portage.dep.dep_opconvert(license_struct)
+ return self._getMissingLicenses(license_struct, acceptable_licenses)
+
+ def _getMissingLicenses(self, license_struct, acceptable_licenses):
+ if not license_struct:
+ return []
+ if license_struct[0] == "||":
+ ret = []
+ for element in license_struct[1:]:
+ if isinstance(element, list):
+ if element:
+ ret.append(self._getMissingLicenses(element))
+ else:
+ if element in acceptable_licenses:
+ return []
+ ret.append(element)
+ # Return all masked licenses, since we don't know which combination
+ # (if any) the user will decide to unmask.
+ return flatten(ret)
+
+ ret = []
+ for element in license_struct:
+ if isinstance(element, list):
+ if element:
+ ret.extend(self._getMissingLicenses(element))
+ else:
+ if element not in acceptable_licenses:
+ ret.append(element)
+ return ret
+
def setinst(self,mycpv,mydbapi):
self.modifying()
if len(self.virtuals) == 0:
@@ -4479,7 +4614,7 @@ def getmaskingreason(mycpv, settings=None, portdb=None, return_location=False):
def getmaskingstatus(mycpv, settings=None, portdb=None):
if settings is None:
- settings = globals()["settings"]
+ settings = config(clone=globals()["settings"])
if portdb is None:
portdb = globals()["portdb"]
mysplit = catpkgsplit(mycpv)
@@ -4508,7 +4643,8 @@ def getmaskingstatus(mycpv, settings=None, portdb=None):
# keywords checking
try:
- mygroups, eapi = portdb.aux_get(mycpv, ["KEYWORDS", "EAPI"])
+ mygroups, licenses, eapi = portdb.aux_get(
+ mycpv, ["KEYWORDS", "LICENSE", "EAPI"])
except KeyError:
# The "depend" phase apparently failed for some reason. An associated
# error message will have already been printed to stderr.
@@ -4563,6 +4699,21 @@ def getmaskingstatus(mycpv, settings=None, portdb=None):
if kmask:
rValue.append(kmask+" keyword")
+
+ try:
+ missing_licenses = settings.getMissingLicenses(licenses, mycpv)
+ if missing_licenses:
+ allowed_tokens = set(["||", "(", ")"])
+ allowed_tokens.update(missing_licenses)
+ license_split = licenses.split()
+ license_split = [x for x in license_split \
+ if x in allowed_tokens]
+ msg = license_split[:]
+ msg.append("license(s)")
+ rValue.append(" ".join(msg))
+ except portage.exception.InvalidDependString, e:
+ rValue.append("LICENSE: "+str(e))
+
return rValue