summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbin/isolated-functions.sh2
-rw-r--r--pym/_emerge/visible.py2
-rw-r--r--pym/portage/__init__.py158
-rw-r--r--pym/portage/dbapi/porttree.py8
4 files changed, 166 insertions, 4 deletions
diff --git a/bin/isolated-functions.sh b/bin/isolated-functions.sh
index bb9b9a042..cd60f05ee 100755
--- a/bin/isolated-functions.sh
+++ b/bin/isolated-functions.sh
@@ -538,7 +538,7 @@ save_ebuild_env() {
${QA_INTERCEPTORS}
# portage config variables and variables set directly by portage
- unset ACCEPT_LICENSE BAD BRACKET BUILD_PREFIX COLS \
+ unset ACCEPT_LICENSE ACCEPT_PROPERTIES BAD BRACKET BUILD_PREFIX COLS \
DISTCC_DIR DISTDIR DOC_SYMLINKS_DIR \
EBUILD_EXIT_STATUS_FILE EBUILD_FORCE_TEST EBUILD_MASTER_PID \
ECLASSDIR ECLASS_DEPTH ENDCOL FAKEROOTKEY \
diff --git a/pym/_emerge/visible.py b/pym/_emerge/visible.py
index f2af7c5c1..8e9a74440 100644
--- a/pym/_emerge/visible.py
+++ b/pym/_emerge/visible.py
@@ -34,6 +34,8 @@ def visible(pkgsettings, pkg):
try:
if pkgsettings._getMissingLicenses(pkg.cpv, pkg.metadata):
return False
+ if pkgsettings._getMissingProperties(pkg.cpv, pkg.metadata):
+ return False
except portage.exception.InvalidDependString:
return False
return True
diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py
index 1ed91a336..0d819393a 100644
--- a/pym/portage/__init__.py
+++ b/pym/portage/__init__.py
@@ -1131,7 +1131,7 @@ class config(object):
# environment in order to prevent sandbox from sourcing /etc/profile
# in it's bashrc (causing major leakage).
_environ_whitelist += [
- "ACCEPT_LICENSE", "BASH_ENV", "BUILD_PREFIX", "D",
+ "ACCEPT_LICENSE", "ACCEPT_PROPERTIES", "BASH_ENV", "BUILD_PREFIX", "D",
"DISTDIR", "DOC_SYMLINKS_DIR", "EBUILD",
"EBUILD_EXIT_STATUS_FILE", "EBUILD_FORCE_TEST",
"EBUILD_PHASE", "ECLASSDIR", "ECLASS_DEPTH", "EMERGE_FROM",
@@ -1274,6 +1274,7 @@ class config(object):
self._accept_license = None
self._accept_license_str = None
self._license_groups = {}
+ self._accept_properties = None
self.virtuals = {}
self.virts_p = {}
@@ -1360,6 +1361,8 @@ class config(object):
self._accept_license = copy.deepcopy(clone._accept_license)
self._plicensedict = copy.deepcopy(clone._plicensedict)
self._license_groups = copy.deepcopy(clone._license_groups)
+ self._accept_properties = copy.deepcopy(clone._accept_properties)
+ self._ppropertiesdict = copy.deepcopy(clone._ppropertiesdict)
else:
def check_var_directory(varname, var):
@@ -1686,6 +1689,7 @@ class config(object):
self.pusedict = {}
self.pkeywordsdict = {}
self._plicensedict = {}
+ self._ppropertiesdict = {}
self.punmaskdict = {}
abs_user_config = os.path.join(config_root, USER_CONFIG_PATH)
@@ -1750,6 +1754,17 @@ class config(object):
self._plicensedict[cp] = cp_dict
cp_dict[k] = self.expandLicenseTokens(v)
+ #package.properties
+ propdict = grabdict_package(os.path.join(
+ abs_user_config, "package.properties"), recursive=1)
+ for k, v in propdict.iteritems():
+ cp = dep_getkey(k)
+ cp_dict = self._ppropertiesdict.get(cp)
+ if not cp_dict:
+ cp_dict = {}
+ self._ppropertiesdict[cp] = cp_dict
+ cp_dict[k] = v
+
self._local_repo_configs = {}
self._local_repo_conf_path = \
os.path.join(abs_user_config, 'repos.conf')
@@ -2147,6 +2162,7 @@ class config(object):
if use is None:
use = frozenset(settings['PORTAGE_USE'].split())
values['ACCEPT_LICENSE'] = self._accept_license(use, settings)
+ values['ACCEPT_PROPERTIES'] = self._accept_properties(use, settings)
values['PORTAGE_RESTRICT'] = self._restrict(use, settings)
return values
@@ -2180,6 +2196,35 @@ class config(object):
licenses = acceptable_licenses
return ' '.join(sorted(licenses))
+ def _accept_properties(self, use, settings):
+ """
+ Generated a pruned version of ACCEPT_PROPERTIES, by intersection with
+ PROPERTIES.
+ Please, look at self._accept_license() to know why it is required.
+ """
+ try:
+ properties = set(flatten(
+ dep.use_reduce(dep.paren_reduce(
+ settings['PROPERTIES']),
+ uselist=use)))
+ except exception.InvalidDependString:
+ properties = set()
+ properties.discard('||')
+ if settings._accept_properties:
+ acceptable_properties = set()
+ for x in settings._accept_properties:
+ if x == '*':
+ acceptable_properties.update(properties)
+ elif x == '-*':
+ acceptable_properties.clear()
+ elif x[1] == '-':
+ acceptable_properties.discard(x[1:])
+ elif x in properties:
+ acceptable_properties.add(x)
+
+ properties = acceptable_properties
+ return ' '.join(sorted(properties))
+
def _restrict(self, use, settings):
try:
restrict = set(flatten(
@@ -2418,6 +2463,8 @@ class config(object):
lazy_vars = self._lazy_vars(built_use, self)
env_configdict.addLazySingleton('ACCEPT_LICENSE',
lazy_vars.__getitem__, 'ACCEPT_LICENSE')
+ env_configdict.addLazySingleton('ACCEPT_PROPERTIES',
+ lazy_vars.__getitem__, 'ACCEPT_PROPERTIES')
env_configdict.addLazySingleton('PORTAGE_RESTRICT',
lazy_vars.__getitem__, 'PORTAGE_RESTRICT')
@@ -2810,6 +2857,87 @@ class config(object):
ret.append(element)
return ret
+ def _getMissingProperties(self, cpv, metadata):
+ """
+ Take a PROPERTIES string and return a list of any properties the user may
+ may need to accept for the given package. The returned list will not
+ contain any properties that have already been accepted. This method
+ can throw an InvalidDependString exception.
+
+ @param cpv: The package name (for package.properties support)
+ @type cpv: String
+ @param metadata: A dictionary of raw package metadata
+ @type metadata: dict
+ @rtype: List
+ @return: A list of properties that have not been accepted.
+ """
+ if not self._accept_properties:
+ return []
+ accept_properties = self._accept_properties
+ cpdict = self._ppropertiesdict.get(dep_getkey(cpv), None)
+ if cpdict:
+ accept_properties = list(self._accept_properties)
+ cpv_slot = "%s:%s" % (cpv, metadata["SLOT"])
+ for atom in match_to_list(cpv_slot, cpdict.keys()):
+ accept_properties.extend(cpdict[atom])
+
+ properties = set(flatten(dep.use_reduce(dep.paren_reduce(
+ metadata["PROPERTIES"]), matchall=1)))
+ properties.discard('||')
+
+ acceptable_properties = set()
+ for x in accept_properties:
+ if x == '*':
+ acceptable_properties.update(properties)
+ elif x == '-*':
+ acceptable_properties.clear()
+ elif x[:1] == '-':
+ acceptable_properties.discard(x[1:])
+ else:
+ acceptable_properties.add(x)
+
+ properties_str = metadata["PROPERTIES"]
+ if "?" in properties_str:
+ use = metadata["USE"].split()
+ else:
+ use = []
+
+ properties_struct = portage.dep.use_reduce(
+ portage.dep.paren_reduce(properties_str), uselist=use)
+ properties_struct = portage.dep.dep_opconvert(properties_struct)
+ return self._getMaskedProperties(properties_struct, acceptable_properties)
+
+ def _getMaskedProperties(self, properties_struct, acceptable_properties):
+ if not properties_struct:
+ return []
+ if properties_struct[0] == "||":
+ ret = []
+ for element in properties_struct[1:]:
+ if isinstance(element, list):
+ if element:
+ ret.append(self._getMaskedProperties(
+ element, acceptable_properties))
+ if not ret[-1]:
+ return []
+ else:
+ if element in acceptable_properties:
+ return[]
+ ret.append(element)
+ # Return all masked properties, since we don't know which combination
+ # (if any) the user will decide to unmask
+ return flatten(ret)
+
+ ret = []
+ for element in properties_struct:
+ if isinstance(element, list):
+ if element:
+ ret.extend(self._getMaskedProperties(element,
+ acceptable_properties))
+ else:
+ if element not in acceptable_properties:
+ ret.append(element)
+ return ret
+
def _accept_chost(self, cpv, metadata):
"""
@return True if pkg CHOST is accepted, False otherwise.
@@ -2957,6 +3085,19 @@ class config(object):
# repoman will accept any license
self._accept_license = ()
+ # ACCEPT_PROPERTIES works like ACCEPT_LICENSE, without groups
+ if self.local_config:
+ mysplit = []
+ for curdb in mydbs:
+ mysplit.extend(curdb.get('ACCEPT_PROPERTIES', '').split())
+ if mysplit:
+ self.configlist[-1]['ACCEPT_PROPERTIES'] = ' '.join(mysplit)
+ if tuple(mysplit) != self._accept_properties:
+ self._accept_properties = tuple(mysplit)
+ else:
+ # repoman will accept any property
+ self._accept_properties = ()
+
for mykey in myincrementals:
myflags=[]
@@ -7709,6 +7850,7 @@ def getmaskingstatus(mycpv, settings=None, portdb=None):
eapi = metadata["EAPI"]
mygroups = settings._getKeywords(mycpv, metadata)
licenses = metadata["LICENSE"]
+ properties = metadata["PROPERTIES"]
slot = metadata["SLOT"]
if eapi.startswith("-"):
eapi = eapi[1:]
@@ -7785,6 +7927,20 @@ def getmaskingstatus(mycpv, settings=None, portdb=None):
except portage.exception.InvalidDependString, e:
rValue.append("LICENSE: "+str(e))
+ try:
+ missing_properties = settings._getMissingProperties(mycpv, metadata)
+ if missing_properties:
+ allowed_tokens = set(["||", "(", ")"])
+ allowed_tokens.update(missing_properties)
+ properties_split = properties.split()
+ properties_split = [x for x in properties_split \
+ if x in allowed_tokens]
+ msg = properties_split[:]
+ msg.append("properties")
+ rValue.append(" ".join(msg))
+ except portage.exception.InvalidDependString, e:
+ rValue.append("PROPERTIES: "+srt(e))
+
# Only show KEYWORDS masks for installed packages
# if they're not masked for any other reason.
if kmask and (not installed or not rValue):
diff --git a/pym/portage/dbapi/porttree.py b/pym/portage/dbapi/porttree.py
index d9b85b18a..7ee889a7c 100644
--- a/pym/portage/dbapi/porttree.py
+++ b/pym/portage/dbapi/porttree.py
@@ -999,12 +999,14 @@ class portdbapi(dbapi):
continue
if local_config:
metadata["USE"] = ""
- if "?" in metadata["LICENSE"]:
+ if "?" in metadata["LICENSE"] or "?" in metadata["PROPERTIES"]:
self.doebuild_settings.setcpv(cpv, mydb=metadata)
metadata["USE"] = self.doebuild_settings.get("USE", "")
try:
if settings._getMissingLicenses(cpv, metadata):
continue
+ if settings._getMissingProperties(cpv, metadata):
+ continue
except InvalidDependString:
continue
if mydep.use:
@@ -1110,12 +1112,14 @@ class portdbapi(dbapi):
if not accept_chost(mycpv, metadata):
continue
metadata["USE"] = ""
- if "?" in metadata["LICENSE"]:
+ if "?" in metadata["LICENSE"] or "?" in metadata["PROPERTIES"]:
self.doebuild_settings.setcpv(mycpv, mydb=metadata)
metadata['USE'] = self.doebuild_settings['PORTAGE_USE']
try:
if self.mysettings._getMissingLicenses(mycpv, metadata):
continue
+ if self.mysettings._getMissingProperties(mycpv, metadata):
+ continue
except InvalidDependString:
continue
newlist.append(mycpv)