1 # Copyright 1999-2009 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
5 from __future__ import print_function
10 from portage.output import bold, bold as white, darkgreen, green, red
11 from portage.util import writemsg_stdout
13 from _emerge.Package import Package
14 from _emerge.visible import visible
27 def __init__(self, root_config, spinner, searchdesc,
28 verbose, usepkg, usepkgonly):
29 """Searches the available and installed packages for the supplied search key.
30 The list of available and installed packages is created at object instantiation.
31 This makes successive searches faster."""
32 self.settings = root_config.settings
33 self.vartree = root_config.trees["vartree"]
34 self.spinner = spinner
35 self.verbose = verbose
36 self.searchdesc = searchdesc
37 self.root_config = root_config
38 self.setconfig = root_config.setconfig
39 self.matches = {"pkg" : []}
44 self.portdb = fake_portdb
45 for attrib in ("aux_get", "cp_all",
46 "xmatch", "findname", "getFetchMap"):
47 setattr(fake_portdb, attrib, getattr(self, "_"+attrib))
51 portdb = root_config.trees["porttree"].dbapi
52 bindb = root_config.trees["bintree"].dbapi
53 vardb = root_config.trees["vartree"].dbapi
55 if not usepkgonly and portdb._have_root_eclass_dir:
56 self._dbs.append(portdb)
58 if (usepkg or usepkgonly) and bindb.cp_all():
59 self._dbs.append(bindb)
61 self._dbs.append(vardb)
64 def _spinner_update(self):
71 cp_all.update(db.cp_all())
72 return list(sorted(cp_all))
74 def _aux_get(self, *args, **kwargs):
77 return db.aux_get(*args, **kwargs)
82 def _findname(self, *args, **kwargs):
84 if db is not self._portdb:
85 # We don't want findname to return anything
86 # unless it's an ebuild in a portage tree.
87 # Otherwise, it's already built and we don't
90 func = getattr(db, "findname", None)
92 value = func(*args, **kwargs)
97 def _getFetchMap(self, *args, **kwargs):
99 func = getattr(db, "getFetchMap", None)
101 value = func(*args, **kwargs)
106 def _visible(self, db, cpv, metadata):
107 installed = db is self.vartree.dbapi
108 built = installed or db is not self._portdb
111 pkg_type = "installed"
114 return visible(self.settings,
115 Package(type_name=pkg_type, root_config=self.root_config,
116 cpv=cpv, built=built, installed=installed, metadata=metadata))
118 def _xmatch(self, level, atom):
120 This method does not expand old-style virtuals because it
121 is restricted to returning matches for a single ${CATEGORY}/${PN}
122 and old-style virual matches unreliable for that when querying
123 multiple package databases. If necessary, old-style virtuals
124 can be performed on atoms prior to calling this method.
126 cp = portage.dep_getkey(atom)
127 if level == "match-all":
130 if hasattr(db, "xmatch"):
131 matches.update(db.xmatch(level, atom))
133 matches.update(db.match(atom))
134 result = list(x for x in matches if portage.cpv_getkey(x) == cp)
135 db._cpv_sort_ascending(result)
136 elif level == "match-visible":
139 if hasattr(db, "xmatch"):
140 matches.update(db.xmatch(level, atom))
142 db_keys = list(db._aux_cache_keys)
143 for cpv in db.match(atom):
144 metadata = zip(db_keys,
145 db.aux_get(cpv, db_keys))
146 if not self._visible(db, cpv, metadata):
149 result = list(x for x in matches if portage.cpv_getkey(x) == cp)
150 db._cpv_sort_ascending(result)
151 elif level == "bestmatch-visible":
154 if hasattr(db, "xmatch"):
155 cpv = db.xmatch("bestmatch-visible", atom)
156 if not cpv or portage.cpv_getkey(cpv) != cp:
158 if not result or cpv == portage.best([cpv, result]):
161 db_keys = Package.metadata_keys
162 # break out of this loop with highest visible
163 # match, checked in descending order
164 for cpv in reversed(db.match(atom)):
165 if portage.cpv_getkey(cpv) != cp:
167 metadata = zip(db_keys,
168 db.aux_get(cpv, db_keys))
169 if not self._visible(db, cpv, metadata):
171 if not result or cpv == portage.best([cpv, result]):
175 raise NotImplementedError(level)
178 def execute(self,searchkey):
179 """Performs the search for the supplied search key"""
181 self.searchkey=searchkey
182 self.packagematches = []
185 self.matches = {"pkg":[], "desc":[], "set":[]}
188 self.matches = {"pkg":[], "set":[]}
189 print("Searching... ", end=' ')
192 if self.searchkey.startswith('%'):
194 self.searchkey = self.searchkey[1:]
195 if self.searchkey.startswith('@'):
197 self.searchkey = self.searchkey[1:]
199 self.searchre=re.compile(self.searchkey,re.I)
201 self.searchre=re.compile(re.escape(self.searchkey), re.I)
202 for package in self.portdb.cp_all():
203 self._spinner_update()
206 match_string = package[:]
208 match_string = package.split("/")[-1]
211 if self.searchre.search(match_string):
212 if not self.portdb.xmatch("match-visible", package):
214 self.matches["pkg"].append([package,masked])
215 elif self.searchdesc: # DESCRIPTION searching
216 full_package = self.portdb.xmatch("bestmatch-visible", package)
218 #no match found; we don't want to query description
219 full_package = portage.best(
220 self.portdb.xmatch("match-all", package))
226 full_desc = self.portdb.aux_get(
227 full_package, ["DESCRIPTION"])[0]
229 print("emerge: search: aux_get() failed, skipping")
231 if self.searchre.search(full_desc):
232 self.matches["desc"].append([full_package,masked])
234 self.sdict = self.setconfig.getSets()
235 for setname in self.sdict:
236 self._spinner_update()
238 match_string = setname
240 match_string = setname.split("/")[-1]
242 if self.searchre.search(match_string):
243 self.matches["set"].append([setname, False])
244 elif self.searchdesc:
245 if self.searchre.search(
246 self.sdict[setname].getMetadata("DESCRIPTION")):
247 self.matches["set"].append([setname, False])
250 for mtype in self.matches:
251 self.matches[mtype].sort()
252 self.mlen += len(self.matches[mtype])
255 if not self.portdb.xmatch("match-all", cp):
258 if not self.portdb.xmatch("bestmatch-visible", cp):
260 self.matches["pkg"].append([cp, masked])
264 """Outputs the results of the search."""
265 print("\b\b \n[ Results for search key : "+white(self.searchkey)+" ]")
266 print("[ Applications found : "+white(str(self.mlen))+" ]")
268 vardb = self.vartree.dbapi
269 for mtype in self.matches:
270 for match,masked in self.matches[mtype]:
274 full_package = self.portdb.xmatch(
275 "bestmatch-visible", match)
277 #no match found; we don't want to query description
279 full_package = portage.best(
280 self.portdb.xmatch("match-all",match))
281 elif mtype == "desc":
283 match = portage.cpv_getkey(match)
286 msg.append(green("*") + " " + bold(match) + "\n")
288 msg.append(" " + darkgreen("Description:") + \
290 self.sdict[match].getMetadata("DESCRIPTION") \
292 writemsg_stdout(''.join(msg), noiselevel=-1)
295 desc, homepage, license = self.portdb.aux_get(
296 full_package, ["DESCRIPTION","HOMEPAGE","LICENSE"])
298 print("emerge: search: aux_get() failed, skipping")
301 print(green("*")+" "+white(match)+" "+red("[ Masked ]"))
303 print(green("*")+" "+white(match))
304 myversion = self.getVersion(full_package, search.VERSION_RELEASE)
308 mycat = match.split("/")[0]
309 mypkg = match.split("/")[1]
310 mycpv = match + "-" + myversion
311 myebuild = self.portdb.findname(mycpv)
313 pkgdir = os.path.dirname(myebuild)
314 from portage import manifest
315 mf = manifest.Manifest(
316 pkgdir, self.settings["DISTDIR"])
318 uri_map = self.portdb.getFetchMap(mycpv)
319 except portage.exception.InvalidDependString as e:
320 file_size_str = "Unknown (%s)" % (e,)
324 mysum[0] = mf.getDistfilesSize(uri_map)
325 except KeyError as e:
326 file_size_str = "Unknown (missing " + \
327 "digest for %s)" % (e,)
332 if db is not vardb and \
333 db.cpv_exists(mycpv):
335 if not myebuild and hasattr(db, "bintree"):
336 myebuild = db.bintree.getname(mycpv)
338 mysum[0] = os.stat(myebuild).st_size
343 if myebuild and file_size_str is None:
344 mystr = str(mysum[0] / 1024)
348 mystr = mystr[:mycount] + "," + mystr[mycount:]
349 file_size_str = mystr + " kB"
354 print(" ", darkgreen("Latest version available:"),myversion)
355 print(" ", self.getInstallationStatus(mycat+'/'+mypkg))
358 (darkgreen("Size of files:"), file_size_str))
359 msg.append(" " + darkgreen("Homepage:") + \
360 " " + homepage + "\n")
361 msg.append(" " + darkgreen("Description:") \
363 msg.append(" " + darkgreen("License:") + \
364 " " + license + "\n\n")
365 writemsg_stdout(''.join(msg), noiselevel=-1)
369 def getInstallationStatus(self,package):
370 installed_package = self.vartree.dep_bestmatch(package)
372 version = self.getVersion(installed_package,search.VERSION_RELEASE)
374 result = darkgreen("Latest version installed:")+" "+version
376 result = darkgreen("Latest version installed:")+" [ Not Installed ]"
379 def getVersion(self,full_package,detail):
380 if len(full_package) > 1:
381 package_parts = portage.catpkgsplit(full_package)
382 if detail == search.VERSION_RELEASE and package_parts[3] != 'r0':
383 result = package_parts[2]+ "-" + package_parts[3]
385 result = package_parts[2]