1 # Copyright 1998-2009 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
9 portage.proxy.lazyimport.lazyimport(globals(),
10 'portage.dbapi.dep_expand:dep_expand@_dep_expand',
11 'portage.dep:match_from_list',
12 'portage.locks:unlockfile',
13 'portage.output:colorize',
14 'portage.util:cmp_sort_key,writemsg',
15 'portage.versions:catsplit,catpkgsplit,vercmp',
18 from portage import os
19 from portage import auxdbkeys
20 from portage.localization import _
23 _category_re = re.compile(r'^\w[-.+\w]*$')
24 _pkg_dir_name_re = re.compile(r'^\w[-+\w]*$')
27 _known_keys = frozenset(x for x in auxdbkeys
28 if not x.startswith("UNUSED_0"))
35 Use self.cp_all() to generate a category list. Mutable instances
36 can delete the self._categories attribute in cases when the cached
37 categories become invalid and need to be regenerated.
39 if self._categories is not None:
40 return self._categories
41 self._categories = tuple(sorted(set(catsplit(x)[0] \
42 for x in self.cp_all())))
43 return self._categories
45 def close_caches(self):
48 def cp_list(self, cp, use_cache=1):
49 raise NotImplementedError(self)
51 def _cpv_sort_ascending(self, cpv_list):
53 Use this to sort self.cp_list() results in ascending
54 order. It sorts in place and returns None.
57 # If the cpv includes explicit -r0, it has to be preserved
58 # for consistency in findname and aux_get calls, so use a
59 # dict to map strings back to their original values.
62 ver_map[cpv] = '-'.join(catpkgsplit(cpv)[2:])
63 def cmp_cpv(cpv1, cpv2):
64 return vercmp(ver_map[cpv1], ver_map[cpv2])
65 cpv_list.sort(key=cmp_sort_key(cmp_cpv))
68 """Return all CPVs in the db
72 A list of Strings, 1 per CPV
74 This function relies on a subclass implementing cp_all, this is why the hasattr is there
77 if not hasattr(self, "cp_all"):
78 raise NotImplementedError
80 for cp in self.cp_all():
81 cpv_list.extend(self.cp_list(cp))
85 """ Implement this in a child class
89 A list of strings 1 per CP in the datastore
91 return NotImplementedError
93 def aux_get(self, mycpv, mylist):
94 """Return the metadata keys in mylist for mycpv
96 mycpv - "sys-apps/foo-1.0"
97 mylist - ["SLOT","DEPEND","HOMEPAGE"]
99 a list of results, in order of keys in mylist, such as:
100 ["0",">=sys-libs/bar-1.0","http://www.foo.com"] or [] if mycpv not found'
102 raise NotImplementedError
104 def aux_update(self, cpv, metadata_updates):
107 cpv - "sys-apps/foo-1.0"
108 metadata_updates = { key : newvalue }
112 raise NotImplementedError
114 def match(self, origdep, use_cache=1):
115 """Given a dependency, try to find packages that match
117 origdep - Depend atom
118 use_cache - Boolean indicating if we should use the cache or not
119 NOTE: Do we ever not want the cache?
121 a list of packages that match origdep
123 mydep = _dep_expand(origdep, mydb=self, settings=self.settings)
124 return list(self._iter_match(mydep,
125 self.cp_list(mydep.cp, use_cache=use_cache)))
127 def _iter_match(self, atom, cpv_iter):
128 cpv_iter = iter(match_from_list(atom, cpv_iter))
130 cpv_iter = self._iter_match_slot(atom, cpv_iter)
132 cpv_iter = self._iter_match_use(atom, cpv_iter)
135 def _iter_match_slot(self, atom, cpv_iter):
138 if self.aux_get(cpv, ["SLOT"])[0] == atom.slot:
143 def _iter_match_use(self, atom, cpv_iter):
145 1) Check for required IUSE intersection (need implicit IUSE here).
146 2) Check enabled/disabled flag states.
149 iuse_implicit_re = self.settings._iuse_implicit_re
152 iuse, slot, use = self.aux_get(cpv, ["IUSE", "SLOT", "USE"])
156 iuse = frozenset(x.lstrip('+-') for x in iuse.split())
158 for x in atom.use.required:
159 if x not in iuse and iuse_implicit_re.match(x) is None:
164 if not self._use_mutable:
165 if atom.use.enabled.difference(use):
167 if atom.use.disabled.intersection(use):
170 # Check masked and forced flags for repoman.
171 mysettings = getattr(self, 'settings', None)
172 if mysettings is not None and not mysettings.local_config:
174 pkg = "%s:%s" % (cpv, slot)
175 usemask = mysettings._getUseMask(pkg)
176 if usemask.intersection(atom.use.enabled):
179 useforce = mysettings._getUseForce(pkg).difference(usemask)
180 if useforce.intersection(atom.use.disabled):
185 def invalidentry(self, mypath):
186 if mypath.endswith('portage_lockfile'):
187 if "PORTAGE_MASTER_PID" not in os.environ:
188 writemsg(_("Lockfile removed: %s\n") % mypath, 1)
189 unlockfile((mypath, None, None))
191 # Nothing we can do about it. We're probably sandboxed.
193 elif '/-MERGING-' in mypath:
194 if os.path.exists(mypath):
195 writemsg(colorize("BAD", _("INCOMPLETE MERGE:"))+" %s\n" % mypath,
198 writemsg("!!! Invalid db entry: %s\n" % mypath, noiselevel=-1)
200 def update_ents(self, updates, onProgress=None, onUpdate=None):
202 Update metadata of all packages for package moves.
203 @param updates: A list of move commands
205 @param onProgress: A progress callback function
206 @type onProgress: a callable that takes 2 integer arguments: maxval and curval
207 @param onUpdate: A progress callback function called only
208 for packages that are modified by updates.
209 @type onUpdate: a callable that takes 2 integer arguments:
212 cpv_all = self.cpv_all()
214 maxval = len(cpv_all)
215 aux_get = self.aux_get
216 aux_update = self.aux_update
217 update_keys = ["DEPEND", "RDEPEND", "PDEPEND", "PROVIDE"]
218 from portage.update import update_dbentries
222 onProgress(maxval, 0)
223 for i, cpv in enumerate(cpv_all):
224 metadata = dict(zip(update_keys, aux_get(cpv, update_keys)))
225 metadata_updates = update_dbentries(updates, metadata)
227 aux_update(cpv, metadata_updates)
229 onUpdate(maxval, i+1)
231 onProgress(maxval, i+1)
233 def move_slot_ent(self, mylist, repo_name = None):
234 """This function takes a sequence:
236 mylist: a sequence of (package, originalslot, newslot)
237 repo_name: repository from which update is originated
239 The number of slotmoves this function did
244 origmatches = self.match(pkg)
248 for mycpv in origmatches:
249 slot = self.aux_get(mycpv, ["SLOT"])[0]
252 if repo_name and self.aux_get(mycpv, ['repository'])[0] != repo_name:
255 mydata = {"SLOT": newslot+"\n"}
256 self.aux_update(mycpv, mydata)