# 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",
self._accept_license = None
self._accept_license_str = None
self._license_groups = {}
+ self._accept_properties = None
self.virtuals = {}
self.virts_p = {}
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):
self.pusedict = {}
self.pkeywordsdict = {}
self._plicensedict = {}
+ self._ppropertiesdict = {}
self.punmaskdict = {}
abs_user_config = os.path.join(config_root, USER_CONFIG_PATH)
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')
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
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(
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')
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.
# 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=[]
eapi = metadata["EAPI"]
mygroups = settings._getKeywords(mycpv, metadata)
licenses = metadata["LICENSE"]
+ properties = metadata["PROPERTIES"]
slot = metadata["SLOT"]
if eapi.startswith("-"):
eapi = eapi[1:]
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):