From 9a54bfff5138f3ba9757fa974c024fe56cc9e272 Mon Sep 17 00:00:00 2001 From: Fabian Groffen Date: Wed, 24 Oct 2007 14:00:06 +0000 Subject: [PATCH] Merged from trunk 8251:8259 | 8252 | protect variables specified in PROFILE_ONLY_VARIABLES from | | genone | being set by the user | | 8253 | make PROFILE_ONLY_VARIABLES incremental | | genone | | | 8254 | make 'world' and 'system' behave like their sets/ | | genone | counterparts | | 8255 | Optimize PROFILE_ONLY_VARIABLES handling. | | zmedico | | | 8256 | just pass the SetConfig instance instead of only the | | genone | settings and trees attributes | | 8257 | move base classes for package sets into a separate module | | genone | | | 8258 | revert r8256 (plans changed) | | genone | | | 8259 | document PROFILE_ONLY_VARIABLES | | genone | | svn path=/main/branches/prefix/; revision=8273 --- man/portage.5 | 6 +- pym/_emerge/__init__.py | 6 +- pym/portage/__init__.py | 14 ++- pym/portage/const.py | 2 +- pym/portage/sets/__init__.py | 159 +--------------------------------- pym/portage/sets/base.py | 160 +++++++++++++++++++++++++++++++++++ pym/portage/sets/dbapi.py | 3 +- pym/portage/sets/files.py | 3 +- pym/portage/sets/profiles.py | 2 +- pym/portage/sets/security.py | 2 +- pym/portage/sets/shell.py | 2 +- 11 files changed, 190 insertions(+), 169 deletions(-) create mode 100644 pym/portage/sets/base.py diff --git a/man/portage.5 b/man/portage.5 index b94b2fdbd..0599c5e09 100644 --- a/man/portage.5 +++ b/man/portage.5 @@ -163,9 +163,13 @@ Architecture type (x86/ppc/hppa/etc...). .B USERLAND = \fI"GNU"\fR Support BSD/cygwin/etc... .TP -.B PORTAGE_LIBC = \fI"glibc"\fR +.B ELIBC = \fI"glibc"\fR Support uClibc/BSD libc/etc... .TP +.B PROFILE_ONLY_VARIABLES = \fI"ARCH"\fR +Prevent critical variables from being changed by the user in make.conf +or the env. +.TP .BR PROFILE_ARCH Distinguish machines classes that have the same \fBARCH\fR. All sparc machines have ARCH=sparc but set this to either 'sparc32' or 'sparc64'. diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py index b39a5edb6..3dfc39606 100644 --- a/pym/_emerge/__init__.py +++ b/pym/_emerge/__init__.py @@ -53,8 +53,9 @@ from portage.const import EPREFIX, BPREFIX from portage.data import secpass from portage.util import normalize_path as normpath from portage.util import writemsg -from portage.sets import InternalPackageSet, SetConfig, make_default_config +from portage.sets import SetConfig, make_default_config from portage.sets.profiles import PackagesSystemSet as SystemSet +from portage.sets.base import InternalPackageSet from portage.sets.files import WorldSet from itertools import chain, izip @@ -350,8 +351,7 @@ def create_depgraph_params(myopts, myaction): if "--update" in myopts or \ "--newuse" in myopts or \ "--reinstall" in myopts or \ - "--noreplace" in myopts or \ - myaction in ("system", "world"): + "--noreplace" in myopts: myparams.add("selective") if "--emptytree" in myopts: myparams.add("empty") diff --git a/pym/portage/__init__.py b/pym/portage/__init__.py index 1568d2618..e29c14f43 100644 --- a/pym/portage/__init__.py +++ b/pym/portage/__init__.py @@ -1194,6 +1194,13 @@ class config(object): "this. Do not use them.\n", noiselevel=-1) sys.exit(1) + + # Don't allow the user to override certain variables in make.conf + profile_only_variables = self.configdict["defaults"].get( + "PROFILE_ONLY_VARIABLES", "").split() + for k in profile_only_variables: + self.mygcfg.pop(k, None) + # Allow ROOT setting to come from make.conf if it's not overridden # by the constructor argument (from the calling environment). As a # special exception for a very common use case, config_root == "/" @@ -1217,7 +1224,12 @@ class config(object): self.configlist.append(self.backupenv) # XXX Why though? self.configdict["backupenv"]=self.configlist[-1] - self.configlist.append(os.environ.copy()) + myenv = os.environ.copy() + # Don't allow the user to override certain variables in the env + for k in profile_only_variables: + myenv.pop(k, None) + + self.configlist.append(myenv) self.configdict["env"]=self.configlist[-1] # make lookuplist for loading package.* diff --git a/pym/portage/const.py b/pym/portage/const.py index 53232f161..708eb7177 100644 --- a/pym/portage/const.py +++ b/pym/portage/const.py @@ -63,7 +63,7 @@ REPO_NAME_LOC = "profiles" + "/" + REPO_NAME_FILE INCREMENTALS = ["USE", "USE_EXPAND", "USE_EXPAND_HIDDEN", "FEATURES", "ACCEPT_KEYWORDS", "ACCEPT_LICENSE", "CONFIG_PROTECT_MASK", "CONFIG_PROTECT", - "PRELINK_PATH", "PRELINK_PATH_MASK"] + "PRELINK_PATH", "PRELINK_PATH_MASK", "PROFILE_ONLY_VARIABLES"] EBUILD_PHASES = ["setup", "unpack", "compile", "test", "install", "preinst", "postinst", "prerm", "postrm", "other"] diff --git a/pym/portage/sets/__init__.py b/pym/portage/sets/__init__.py index ac3f4b0cb..b757c43c4 100644 --- a/pym/portage/sets/__init__.py +++ b/pym/portage/sets/__init__.py @@ -4,169 +4,12 @@ import os from ConfigParser import SafeConfigParser, NoOptionError -from portage import flatten, load_mod -from portage.dep import isvalidatom, match_from_list, \ - best_match_to_list, dep_getkey, use_reduce, paren_reduce -from portage.exception import InvalidAtom +from portage import load_mod -OPERATIONS = ["merge", "unmerge"] DEFAULT_SETS = ["world", "system", "everything", "security"] \ +["package_"+x for x in ["mask", "unmask", "use", "keywords"]] del x -__all__ = ["PackageSet", "EditablePackageSet", "InternalPackageSet", \ - "SetConfigError", "SetConfig", "make_default_config"] - -class PackageSet(object): - # Set this to operations that are supported by your subclass. While - # technically there is no difference between "merge" and "unmerge" regarding - # package sets, the latter doesn't make sense for some sets like "system" - # or "security" and therefore isn't supported by them. - _operations = ["merge"] - description = "generic package set" - - def __init__(self): - self._atoms = set() - self._atommap = {} - self._loaded = False - self._loading = False - self.errors = [] - - def __contains__(self, atom): - return atom in self.getAtoms() - - def __iter__(self): - for x in self.getAtoms(): - yield x - - def supportsOperation(self, op): - if not op in OPERATIONS: - raise ValueError(op) - return op in self._operations - - def getAtoms(self): - if not (self._loaded or self._loading): - self._loading = True - self.load() - self._loaded = True - self._loading = False - return self._atoms - - def _setAtoms(self, atoms): - atoms = map(str.strip, atoms) - for a in atoms[:]: - if a == "": - atoms.remove(a) - elif not isvalidatom(a): - raise InvalidAtom(a) - self._atoms = set(atoms) - self._updateAtomMap() - - def load(self): - # This method must be overwritten by subclasses - # Editable sets should use the value of self._mtime to determine if they - # need to reload themselves - raise NotImplementedError() - - def containsCPV(self, cpv): - for a in self.getAtoms(): - if match_from_list(a, [cpv]): - return True - return False - - def getMetadata(self, key): - if hasattr(self, key.lower()): - return getattr(self, key.lower()) - else: - return "" - - def _updateAtomMap(self, atoms=None): - """Update self._atommap for specific atoms or all atoms.""" - if not atoms: - self._atommap.clear() - atoms = self._atoms - for a in atoms: - cp = dep_getkey(a) - self._atommap.setdefault(cp, set()) - self._atommap[cp].add(a) - - # Not sure if this one should really be in PackageSet - def findAtomForPackage(self, cpv, metadata): - """Return the best match for a given package from the arguments, or - None if there are no matches. This matches virtual arguments against - the PROVIDE metadata. This can raise an InvalidDependString exception - if an error occurs while parsing PROVIDE.""" - cpv_slot = "%s:%s" % (cpv, metadata["SLOT"]) - cp = dep_getkey(cpv) - self.getAtoms() # make sure the atoms are loaded - atoms = self._atommap.get(cp) - if atoms: - best_match = best_match_to_list(cpv_slot, atoms) - if best_match: - return best_match - if not metadata["PROVIDE"]: - return None - provides = flatten(use_reduce(paren_reduce(metadata["PROVIDE"]), - uselist=metadata["USE"].split())) - for provide in provides: - provided_cp = dep_getkey(provide) - atoms = self._atommap.get(provided_cp) - if atoms: - atoms = list(atoms) - transformed_atoms = [atom.replace(provided_cp, cp) for atom in atoms] - best_match = best_match_to_list(cpv_slot, transformed_atoms) - if best_match: - return atoms[transformed_atoms.index(best_match)] - return None - -class EditablePackageSet(PackageSet): - - def update(self, atoms): - self.getAtoms() - self._atoms.update(atoms) - self._updateAtomMap(atoms=atoms) - self.write() - - def add(self, atom): - self.update([atom]) - - def replace(self, atoms): - self._setAtoms(atoms) - self.write() - - def remove(self, atom): - self.getAtoms() - self._atoms.discard(atom) - self._updateAtomMap() - self.write() - - def removePackageAtoms(self, cp): - for a in list(self.getAtoms()): - if dep_getkey(a) == cp: - self.remove(a) - self.write() - - def write(self): - # This method must be overwritten in subclasses that should be editable - raise NotImplementedError() - -class InternalPackageSet(EditablePackageSet): - def __init__(self, initial_atoms=None): - super(InternalPackageSet, self).__init__() - if initial_atoms != None: - self.update(initial_atoms) - - def clear(self): - self._atoms.clear() - self._updateAtomMap() - - def load(self): - pass - - def write(self): - pass - - class SetConfigError(Exception): pass diff --git a/pym/portage/sets/base.py b/pym/portage/sets/base.py new file mode 100644 index 000000000..b5ea88928 --- /dev/null +++ b/pym/portage/sets/base.py @@ -0,0 +1,160 @@ +# Copyright 2007 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id$ + +from portage import flatten +from portage.dep import isvalidatom, match_from_list, \ + best_match_to_list, dep_getkey, use_reduce, paren_reduce +from portage.exception import InvalidAtom + +OPERATIONS = ["merge", "unmerge"] + +class PackageSet(object): + # Set this to operations that are supported by your subclass. While + # technically there is no difference between "merge" and "unmerge" regarding + # package sets, the latter doesn't make sense for some sets like "system" + # or "security" and therefore isn't supported by them. + _operations = ["merge"] + description = "generic package set" + + def __init__(self): + self._atoms = set() + self._atommap = {} + self._loaded = False + self._loading = False + self.errors = [] + + def __contains__(self, atom): + return atom in self.getAtoms() + + def __iter__(self): + for x in self.getAtoms(): + yield x + + def supportsOperation(self, op): + if not op in OPERATIONS: + raise ValueError(op) + return op in self._operations + + def getAtoms(self): + if not (self._loaded or self._loading): + self._loading = True + self.load() + self._loaded = True + self._loading = False + return self._atoms + + def _setAtoms(self, atoms): + atoms = map(str.strip, atoms) + for a in atoms[:]: + if a == "": + atoms.remove(a) + elif not isvalidatom(a): + raise InvalidAtom(a) + self._atoms = set(atoms) + self._updateAtomMap() + + def load(self): + # This method must be overwritten by subclasses + # Editable sets should use the value of self._mtime to determine if they + # need to reload themselves + raise NotImplementedError() + + def containsCPV(self, cpv): + for a in self.getAtoms(): + if match_from_list(a, [cpv]): + return True + return False + + def getMetadata(self, key): + if hasattr(self, key.lower()): + return getattr(self, key.lower()) + else: + return "" + + def _updateAtomMap(self, atoms=None): + """Update self._atommap for specific atoms or all atoms.""" + if not atoms: + self._atommap.clear() + atoms = self._atoms + for a in atoms: + cp = dep_getkey(a) + self._atommap.setdefault(cp, set()) + self._atommap[cp].add(a) + + # Not sure if this one should really be in PackageSet + def findAtomForPackage(self, cpv, metadata): + """Return the best match for a given package from the arguments, or + None if there are no matches. This matches virtual arguments against + the PROVIDE metadata. This can raise an InvalidDependString exception + if an error occurs while parsing PROVIDE.""" + cpv_slot = "%s:%s" % (cpv, metadata["SLOT"]) + cp = dep_getkey(cpv) + self.getAtoms() # make sure the atoms are loaded + atoms = self._atommap.get(cp) + if atoms: + best_match = best_match_to_list(cpv_slot, atoms) + if best_match: + return best_match + if not metadata["PROVIDE"]: + return None + provides = flatten(use_reduce(paren_reduce(metadata["PROVIDE"]), + uselist=metadata["USE"].split())) + for provide in provides: + provided_cp = dep_getkey(provide) + atoms = self._atommap.get(provided_cp) + if atoms: + atoms = list(atoms) + transformed_atoms = [atom.replace(provided_cp, cp) for atom in atoms] + best_match = best_match_to_list(cpv_slot, transformed_atoms) + if best_match: + return atoms[transformed_atoms.index(best_match)] + return None + +class EditablePackageSet(PackageSet): + + def update(self, atoms): + self.getAtoms() + self._atoms.update(atoms) + self._updateAtomMap(atoms=atoms) + self.write() + + def add(self, atom): + self.update([atom]) + + def replace(self, atoms): + self._setAtoms(atoms) + self.write() + + def remove(self, atom): + self.getAtoms() + self._atoms.discard(atom) + self._updateAtomMap() + self.write() + + def removePackageAtoms(self, cp): + for a in list(self.getAtoms()): + if dep_getkey(a) == cp: + self.remove(a) + self.write() + + def write(self): + # This method must be overwritten in subclasses that should be editable + raise NotImplementedError() + +class InternalPackageSet(EditablePackageSet): + def __init__(self, initial_atoms=None): + super(InternalPackageSet, self).__init__() + if initial_atoms != None: + self.update(initial_atoms) + + def clear(self): + self._atoms.clear() + self._updateAtomMap() + + def load(self): + pass + + def write(self): + pass + diff --git a/pym/portage/sets/dbapi.py b/pym/portage/sets/dbapi.py index bc842ae2c..a1b902fdc 100644 --- a/pym/portage/sets/dbapi.py +++ b/pym/portage/sets/dbapi.py @@ -3,7 +3,8 @@ # $Id$ from portage.versions import catsplit, catpkgsplit -from portage.sets import PackageSet, SetConfigError +from portage.sets.base import PackageSet +from portage.sets import SetConfigError from portage.dbapi.vartree import dblink from portage.util import grabfile diff --git a/pym/portage/sets/files.py b/pym/portage/sets/files.py index 71a2ecd85..9cbb018da 100644 --- a/pym/portage/sets/files.py +++ b/pym/portage/sets/files.py @@ -8,7 +8,8 @@ from portage.util import grabfile, write_atomic, ensure_dirs from portage.const import PRIVATE_PATH, USER_CONFIG_PATH from portage.locks import lockfile, unlockfile from portage import portage_gid -from portage.sets import PackageSet, EditablePackageSet, SetConfigError +from portage.sets.base import PackageSet, EditablePackageSet +from portage.sets import SetConfigError from portage.env.loaders import ItemFileLoader, KeyListFileLoader from portage.env.validators import ValidAtomValidator from portage import dep_getkey, cpv_getkey diff --git a/pym/portage/sets/profiles.py b/pym/portage/sets/profiles.py index fcefaff88..35cf4d87d 100644 --- a/pym/portage/sets/profiles.py +++ b/pym/portage/sets/profiles.py @@ -4,7 +4,7 @@ import os from portage.util import grabfile_package, stack_lists -from portage.sets import PackageSet +from portage.sets.base import PackageSet __all__ = ["PackagesSystemSet"] diff --git a/pym/portage/sets/security.py b/pym/portage/sets/security.py index f58e725f9..b53326990 100644 --- a/pym/portage/sets/security.py +++ b/pym/portage/sets/security.py @@ -6,7 +6,7 @@ import os import portage.glsa as glsa from portage.util import grabfile, write_atomic from portage.const import CACHE_PATH -from portage.sets import PackageSet +from portage.sets.base import PackageSet __all__ = ["SecuritySet", "NewGlsaSet", "NewAffectedSet", "AffectedSet"] diff --git a/pym/portage/sets/shell.py b/pym/portage/sets/shell.py index 56b8ef5ef..cae28fa46 100644 --- a/pym/portage/sets/shell.py +++ b/pym/portage/sets/shell.py @@ -5,7 +5,7 @@ import subprocess import os -from portage.sets import PackageSet, SetConfigError +from portage.sets.base import PackageSet, SetConfigError __all__ = ["CommandOutputSet"] -- 2.26.2