Package portage :: Package _sets :: Module base
[hide private]

Source Code for Module portage._sets.base

  1  # Copyright 2007-2011 Gentoo Foundation 
  2  # Distributed under the terms of the GNU General Public License v2 
  3   
  4  import sys 
  5  from portage.dep import Atom, ExtendedAtomDict, best_match_to_list, match_from_list 
  6  from portage.exception import InvalidAtom 
  7  from portage.versions import cpv_getkey 
  8   
  9  if sys.hexversion >= 0x3000000: 
 10          basestring = str 
 11   
 12  OPERATIONS = ["merge", "unmerge"] 
 13   
14 -class PackageSet(object):
15 # Set this to operations that are supported by your subclass. While 16 # technically there is no difference between "merge" and "unmerge" regarding 17 # package sets, the latter doesn't make sense for some sets like "system" 18 # or "security" and therefore isn't supported by them. 19 _operations = ["merge"] 20 description = "generic package set" 21
22 - def __init__(self, allow_wildcard=False, allow_repo=False):
23 self._atoms = set() 24 self._atommap = ExtendedAtomDict(set) 25 self._loaded = False 26 self._loading = False 27 self.errors = [] 28 self._nonatoms = set() 29 self.world_candidate = False 30 self._allow_wildcard = allow_wildcard 31 self._allow_repo = allow_repo
32
33 - def __contains__(self, atom):
34 self._load() 35 return atom in self._atoms or atom in self._nonatoms
36
37 - def __iter__(self):
38 self._load() 39 for x in self._atoms: 40 yield x 41 for x in self._nonatoms: 42 yield x
43
44 - def __bool__(self):
45 self._load() 46 return bool(self._atoms or self._nonatoms)
47 48 if sys.hexversion < 0x3000000: 49 __nonzero__ = __bool__ 50
51 - def supportsOperation(self, op):
52 if not op in OPERATIONS: 53 raise ValueError(op) 54 return op in self._operations
55
56 - def _load(self):
57 if not (self._loaded or self._loading): 58 self._loading = True 59 self.load() 60 self._loaded = True 61 self._loading = False
62
63 - def getAtoms(self):
64 self._load() 65 return self._atoms.copy()
66
67 - def getNonAtoms(self):
68 self._load() 69 return self._nonatoms.copy()
70
71 - def _setAtoms(self, atoms):
72 self._atoms.clear() 73 self._nonatoms.clear() 74 for a in atoms: 75 if not isinstance(a, Atom): 76 if isinstance(a, basestring): 77 a = a.strip() 78 if not a: 79 continue 80 try: 81 a = Atom(a, allow_wildcard=True, allow_repo=True) 82 except InvalidAtom: 83 self._nonatoms.add(a) 84 continue 85 if not self._allow_wildcard and a.extended_syntax: 86 raise InvalidAtom("extended atom syntax not allowed here") 87 if not self._allow_repo and a.repo: 88 raise InvalidAtom("repository specification not allowed here") 89 self._atoms.add(a) 90 91 self._updateAtomMap()
92
93 - def load(self):
94 # This method must be overwritten by subclasses 95 # Editable sets should use the value of self._mtime to determine if they 96 # need to reload themselves 97 raise NotImplementedError()
98
99 - def containsCPV(self, cpv):
100 self._load() 101 for a in self._atoms: 102 if match_from_list(a, [cpv]): 103 return True 104 return False
105
106 - def getMetadata(self, key):
107 if hasattr(self, key.lower()): 108 return getattr(self, key.lower()) 109 else: 110 return ""
111
112 - def _updateAtomMap(self, atoms=None):
113 """Update self._atommap for specific atoms or all atoms.""" 114 if not atoms: 115 self._atommap.clear() 116 atoms = self._atoms 117 for a in atoms: 118 self._atommap.setdefault(a.cp, set()).add(a)
119 120 # Not sure if this one should really be in PackageSet
121 - def findAtomForPackage(self, pkg, modified_use=None):
122 """Return the best match for a given package from the arguments, or 123 None if there are no matches. This matches virtual arguments against 124 the PROVIDE metadata. This can raise an InvalidDependString exception 125 if an error occurs while parsing PROVIDE.""" 126 127 if modified_use is not None and modified_use is not pkg.use.enabled: 128 pkg = pkg.copy() 129 pkg._metadata["USE"] = " ".join(modified_use) 130 131 # Atoms matched via PROVIDE must be temporarily transformed since 132 # match_from_list() only works correctly when atom.cp == pkg.cp. 133 rev_transform = {} 134 for atom in self.iterAtomsForPackage(pkg): 135 if atom.cp == pkg.cp: 136 rev_transform[atom] = atom 137 else: 138 rev_transform[Atom(atom.replace(atom.cp, pkg.cp, 1), allow_wildcard=True, allow_repo=True)] = atom 139 best_match = best_match_to_list(pkg, iter(rev_transform)) 140 if best_match: 141 return rev_transform[best_match] 142 return None
143
144 - def iterAtomsForPackage(self, pkg):
145 """ 146 Find all matching atoms for a given package. This matches virtual 147 arguments against the PROVIDE metadata. This will raise an 148 InvalidDependString exception if PROVIDE is invalid. 149 """ 150 cpv_slot_list = [pkg] 151 cp = cpv_getkey(pkg.cpv) 152 self._load() # make sure the atoms are loaded 153 154 atoms = self._atommap.get(cp) 155 if atoms: 156 for atom in atoms: 157 if match_from_list(atom, cpv_slot_list): 158 yield atom 159 provides = pkg._metadata['PROVIDE'] 160 if not provides: 161 return 162 provides = provides.split() 163 for provide in provides: 164 try: 165 provided_cp = Atom(provide).cp 166 except InvalidAtom: 167 continue 168 atoms = self._atommap.get(provided_cp) 169 if atoms: 170 for atom in atoms: 171 if match_from_list(atom.replace(provided_cp, cp), 172 cpv_slot_list): 173 yield atom
174
175 -class EditablePackageSet(PackageSet):
176
177 - def __init__(self, allow_wildcard=False, allow_repo=False):
178 super(EditablePackageSet, self).__init__(allow_wildcard=allow_wildcard, allow_repo=allow_repo)
179
180 - def update(self, atoms):
181 self._load() 182 modified = False 183 normal_atoms = [] 184 for a in atoms: 185 if not isinstance(a, Atom): 186 try: 187 a = Atom(a, allow_wildcard=True, allow_repo=True) 188 except InvalidAtom: 189 modified = True 190 self._nonatoms.add(a) 191 continue 192 if not self._allow_wildcard and a.extended_syntax: 193 raise InvalidAtom("extended atom syntax not allowed here") 194 if not self._allow_repo and a.repo: 195 raise InvalidAtom("repository specification not allowed here") 196 normal_atoms.append(a) 197 198 if normal_atoms: 199 modified = True 200 self._atoms.update(normal_atoms) 201 self._updateAtomMap(atoms=normal_atoms) 202 if modified: 203 self.write()
204
205 - def add(self, atom):
206 self.update([atom])
207
208 - def replace(self, atoms):
209 self._setAtoms(atoms) 210 self.write()
211
212 - def remove(self, atom):
213 self._load() 214 self._atoms.discard(atom) 215 self._nonatoms.discard(atom) 216 self._updateAtomMap() 217 self.write()
218
219 - def removePackageAtoms(self, cp):
220 self._load() 221 for a in list(self._atoms): 222 if a.cp == cp: 223 self.remove(a) 224 self.write()
225
226 - def write(self):
227 # This method must be overwritten in subclasses that should be editable 228 raise NotImplementedError()
229
230 -class InternalPackageSet(EditablePackageSet):
231 - def __init__(self, initial_atoms=None, allow_wildcard=False, allow_repo=True):
232 """ 233 Repo atoms are allowed more often than not, so it makes sense for this 234 class to allow them by default. The Atom constructor and isvalidatom() 235 functions default to allow_repo=False, which is sufficient to ensure 236 that repo atoms are prohibited when necessary. 237 """ 238 super(InternalPackageSet, self).__init__(allow_wildcard=allow_wildcard, allow_repo=allow_repo) 239 if initial_atoms != None: 240 self.update(initial_atoms)
241
242 - def clear(self):
243 self._atoms.clear() 244 self._updateAtomMap()
245
246 - def load(self):
247 pass
248
249 - def write(self):
250 pass
251
252 -class DummyPackageSet(PackageSet):
253 - def __init__(self, atoms=None):
254 super(DummyPackageSet, self).__init__() 255 if atoms: 256 self._setAtoms(atoms)
257
258 - def load(self):
259 pass
260
261 - def singleBuilder(cls, options, settings, trees):
262 atoms = options.get("packages", "").split() 263 return DummyPackageSet(atoms=atoms)
264 singleBuilder = classmethod(singleBuilder)
265