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

Source Code for Module portage._sets.base

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