Lines 3-15
Link Here
|
3 |
|
3 |
|
4 |
from __future__ import print_function |
4 |
from __future__ import print_function |
5 |
|
5 |
|
|
|
6 |
import io |
6 |
import re |
7 |
import re |
7 |
import portage |
8 |
import portage |
8 |
from portage import os |
9 |
from portage import os, _encodings |
9 |
from portage.dbapi.porttree import _parse_uri_map |
10 |
from portage.dbapi.porttree import _parse_uri_map |
|
|
11 |
from portage.dep import Atom |
12 |
from portage.exception import InvalidData |
10 |
from portage.localization import localized_size |
13 |
from portage.localization import localized_size |
11 |
from portage.output import bold, bold as white, darkgreen, green, red |
14 |
from portage.output import bold, bold as white, darkgreen, green, red |
12 |
from portage.util import writemsg_stdout |
15 |
from portage.util import writemsg_stdout |
|
|
16 |
from portage.versions import _pkg_str |
13 |
|
17 |
|
14 |
from _emerge.Package import Package |
18 |
from _emerge.Package import Package |
15 |
|
19 |
|
Lines 25-36
class search(object):
Link Here
|
25 |
# public interface |
29 |
# public interface |
26 |
# |
30 |
# |
27 |
def __init__(self, root_config, spinner, searchdesc, |
31 |
def __init__(self, root_config, spinner, searchdesc, |
28 |
verbose, usepkg, usepkgonly): |
32 |
verbose, usepkg, usepkgonly, search_index=True): |
29 |
"""Searches the available and installed packages for the supplied search key. |
33 |
"""Searches the available and installed packages for the supplied search key. |
30 |
The list of available and installed packages is created at object instantiation. |
34 |
The list of available and installed packages is created at object instantiation. |
31 |
This makes successive searches faster.""" |
35 |
This makes successive searches faster.""" |
32 |
self.settings = root_config.settings |
36 |
self.settings = root_config.settings |
33 |
self.vartree = root_config.trees["vartree"] |
|
|
34 |
self.spinner = spinner |
37 |
self.spinner = spinner |
35 |
self.verbose = verbose |
38 |
self.verbose = verbose |
36 |
self.searchdesc = searchdesc |
39 |
self.searchdesc = searchdesc |
Lines 45-50
class search(object):
Link Here
|
45 |
bindb = root_config.trees["bintree"].dbapi |
48 |
bindb = root_config.trees["bintree"].dbapi |
46 |
vardb = root_config.trees["vartree"].dbapi |
49 |
vardb = root_config.trees["vartree"].dbapi |
47 |
|
50 |
|
|
|
51 |
if search_index: |
52 |
portdb = IndexedPortdb(portdb) |
53 |
vardb = IndexedVardb(vardb) |
54 |
|
48 |
if not usepkgonly and portdb._have_root_eclass_dir: |
55 |
if not usepkgonly and portdb._have_root_eclass_dir: |
49 |
self._dbs.append(portdb) |
56 |
self._dbs.append(portdb) |
50 |
|
57 |
|
Lines 53-58
class search(object):
Link Here
|
53 |
|
60 |
|
54 |
self._dbs.append(vardb) |
61 |
self._dbs.append(vardb) |
55 |
self._portdb = portdb |
62 |
self._portdb = portdb |
|
|
63 |
self._vardb = vardb |
56 |
|
64 |
|
57 |
def _spinner_update(self): |
65 |
def _spinner_update(self): |
58 |
if self.spinner: |
66 |
if self.spinner: |
Lines 97-103
class search(object):
Link Here
|
97 |
return {} |
105 |
return {} |
98 |
|
106 |
|
99 |
def _visible(self, db, cpv, metadata): |
107 |
def _visible(self, db, cpv, metadata): |
100 |
installed = db is self.vartree.dbapi |
108 |
installed = db is self._vardb |
101 |
built = installed or db is not self._portdb |
109 |
built = installed or db is not self._portdb |
102 |
pkg_type = "ebuild" |
110 |
pkg_type = "ebuild" |
103 |
if installed: |
111 |
if installed: |
Lines 208-213
class search(object):
Link Here
|
208 |
masked=1 |
216 |
masked=1 |
209 |
self.matches["pkg"].append([package,masked]) |
217 |
self.matches["pkg"].append([package,masked]) |
210 |
elif self.searchdesc: # DESCRIPTION searching |
218 |
elif self.searchdesc: # DESCRIPTION searching |
|
|
219 |
# Check for DESCRIPTION match first, so that we can skip |
220 |
# the expensive visiblity check if it doesn't match. |
221 |
full_package = portage.best( |
222 |
self._xmatch("match-all", package)) |
223 |
try: |
224 |
full_desc = self._aux_get( |
225 |
full_package, ["DESCRIPTION"])[0] |
226 |
except KeyError: |
227 |
portage.writemsg( |
228 |
"emerge: search: aux_get() failed, skipping\n", |
229 |
noiselevel=-1) |
230 |
continue |
231 |
if not self.searchre.search(full_desc): |
232 |
continue |
211 |
full_package = self._xmatch("bestmatch-visible", package) |
233 |
full_package = self._xmatch("bestmatch-visible", package) |
212 |
if not full_package: |
234 |
if not full_package: |
213 |
#no match found; we don't want to query description |
235 |
#no match found; we don't want to query description |
Lines 217-230
class search(object):
Link Here
|
217 |
continue |
239 |
continue |
218 |
else: |
240 |
else: |
219 |
masked=1 |
241 |
masked=1 |
220 |
try: |
242 |
|
221 |
full_desc = self._aux_get( |
243 |
self.matches["desc"].append((full_package, masked)) |
222 |
full_package, ["DESCRIPTION"])[0] |
|
|
223 |
except KeyError: |
224 |
print("emerge: search: aux_get() failed, skipping") |
225 |
continue |
226 |
if self.searchre.search(full_desc): |
227 |
self.matches["desc"].append([full_package,masked]) |
228 |
|
244 |
|
229 |
self.sdict = self.setconfig.getSets() |
245 |
self.sdict = self.setconfig.getSets() |
230 |
for setname in self.sdict: |
246 |
for setname in self.sdict: |
Lines 262-268
class search(object):
Link Here
|
262 |
bold(self.searchkey) + " ]\n") |
278 |
bold(self.searchkey) + " ]\n") |
263 |
msg.append("[ Applications found : " + \ |
279 |
msg.append("[ Applications found : " + \ |
264 |
bold(str(self.mlen)) + " ]\n\n") |
280 |
bold(str(self.mlen)) + " ]\n\n") |
265 |
vardb = self.vartree.dbapi |
281 |
vardb = self._vardb |
266 |
metadata_keys = set(Package.metadata_keys) |
282 |
metadata_keys = set(Package.metadata_keys) |
267 |
metadata_keys.update(["DESCRIPTION", "HOMEPAGE", "LICENSE", "SRC_URI"]) |
283 |
metadata_keys.update(["DESCRIPTION", "HOMEPAGE", "LICENSE", "SRC_URI"]) |
268 |
metadata_keys = tuple(metadata_keys) |
284 |
metadata_keys = tuple(metadata_keys) |
Lines 372-378
class search(object):
Link Here
|
372 |
# private interface |
388 |
# private interface |
373 |
# |
389 |
# |
374 |
def getInstallationStatus(self,package): |
390 |
def getInstallationStatus(self,package): |
375 |
installed_package = self.vartree.dep_bestmatch(package) |
391 |
installed_package = self._vardb.match(package) |
|
|
392 |
if installed_package: |
393 |
installed_package = installed_package[-1] |
394 |
else: |
395 |
installed_package = "" |
376 |
result = "" |
396 |
result = "" |
377 |
version = self.getVersion(installed_package,search.VERSION_RELEASE) |
397 |
version = self.getVersion(installed_package,search.VERSION_RELEASE) |
378 |
if len(version) > 0: |
398 |
if len(version) > 0: |
Lines 392-394
class search(object):
Link Here
|
392 |
result = "" |
412 |
result = "" |
393 |
return result |
413 |
return result |
394 |
|
414 |
|
395 |
- |
415 |
|
|
|
416 |
class IndexedPortdb(object): |
417 |
""" |
418 |
A portdbapi interface that uses a package description index to |
419 |
improve performance. If the description index is missing for a |
420 |
particular repository, then all metadata for that repository is |
421 |
obtained using the normal pordbapi.aux_get method. |
422 |
""" |
423 |
def __init__(self, portdb): |
424 |
self._portdb = portdb |
425 |
self.cpv_exists = portdb.cpv_exists |
426 |
self.getFetchMap = portdb.getFetchMap |
427 |
self.findname = portdb.findname |
428 |
self._aux_cache_keys = portdb._aux_cache_keys |
429 |
self._have_root_eclass_dir = portdb._have_root_eclass_dir |
430 |
self._cpv_sort_ascending = portdb._cpv_sort_ascending |
431 |
self._desc_cache = None |
432 |
self._cp_map = None |
433 |
|
434 |
def _init_index(self): |
435 |
cp_map = {} |
436 |
desc_cache = {} |
437 |
for repo_path in self._portdb.porttrees: |
438 |
outside_repo = os.path.join(self._portdb.depcachedir, |
439 |
repo_path.lstrip(os.sep)) |
440 |
for parent_dir in (repo_path, outside_repo): |
441 |
file_path = os.path.join(parent_dir, |
442 |
"metadata", "pkg_desc_index") |
443 |
|
444 |
try: |
445 |
with io.open(file_path, |
446 |
encoding=_encodings["repo.content"]) as f: |
447 |
for line in f: |
448 |
pkgs, desc = line.split(":", 1) |
449 |
desc = desc.strip() |
450 |
pkgs = pkgs.split(",") |
451 |
if not pkgs[0]: |
452 |
continue |
453 |
try: |
454 |
pkg = _pkg_str(pkgs[0]) |
455 |
except InvalidData: |
456 |
continue |
457 |
cp_list = cp_map.get(pkg.cp) |
458 |
if cp_list is None: |
459 |
cp_list = [] |
460 |
cp_map[pkg.cp] = cp_list |
461 |
cp_list.append(pkg) |
462 |
for ver in pkgs[1:]: |
463 |
try: |
464 |
cp_list.append( |
465 |
_pkg_str(pkg.cp + "-" + ver)) |
466 |
except InvalidData: |
467 |
pass |
468 |
for cpv in cp_list: |
469 |
desc_cache[cpv] = desc |
470 |
except IOError: |
471 |
pass |
472 |
else: |
473 |
break |
474 |
else: |
475 |
# No descriptions index was found, so populate |
476 |
# cp_map the slow way. |
477 |
for cp in self._portdb.cp_all(trees=[repo_path]): |
478 |
cp_list = cp_map.get(cp) |
479 |
if cp_list is None: |
480 |
cp_list = [] |
481 |
cp_map[cp] = cp_list |
482 |
for cpv in self._portdb.cp_list(cp, mytree=repo_path): |
483 |
if cpv not in cp_list: |
484 |
cp_list.append(_pkg_str(cpv)) |
485 |
|
486 |
self._desc_cache = desc_cache |
487 |
self._cp_map = cp_map |
488 |
|
489 |
def cp_all(self): |
490 |
if self._cp_map is None: |
491 |
self._init_index() |
492 |
return list(self._cp_map) |
493 |
|
494 |
def match(self, atom): |
495 |
if not isinstance(atom, Atom): |
496 |
atom = Atom(atom) |
497 |
cp_list = self._cp_map.get(atom.cp) |
498 |
if cp_list is None: |
499 |
return [] |
500 |
self._portdb._cpv_sort_ascending(cp_list) |
501 |
return portage.match_from_list(atom, cp_list) |
502 |
|
503 |
def aux_get(self, cpv, attrs, myrepo = None): |
504 |
if len(attrs) == 1 and attrs[0] == "DESCRIPTION": |
505 |
try: |
506 |
return [self._desc_cache[cpv]] |
507 |
except KeyError: |
508 |
pass |
509 |
return self._portdb.aux_get(cpv, attrs) |
510 |
|
511 |
|
512 |
class IndexedVardb(object): |
513 |
""" |
514 |
A vardbapi interface that sacrifices validation in order to |
515 |
improve performance. It takes advantage of vardbdbapi._aux_cache, |
516 |
which is backed by vardb_metadata.pickle. Since _aux_cache is |
517 |
not updated for every single merge/unmerge (see |
518 |
_aux_cache_threshold), the list of packages is obtained directly |
519 |
from the real vardbapi instance. If a package is missing from |
520 |
_aux_cache, then its metadata is obtained using the normal |
521 |
(validated) vardbapi.aux_get method. |
522 |
""" |
523 |
def __init__(self, vardb): |
524 |
self._vardb = vardb |
525 |
self._aux_cache_keys = vardb._aux_cache_keys |
526 |
self._cpv_sort_ascending = vardb._cpv_sort_ascending |
527 |
self._cp_map = {} |
528 |
self.cpv_exists = vardb.cpv_exists |
529 |
|
530 |
def cp_all(self): |
531 |
if self._cp_map: |
532 |
return list(self._cp_map) |
533 |
cp_map = self._cp_map |
534 |
for cpv in self._vardb.cpv_all(): |
535 |
cp = portage.cpv_getkey(cpv) |
536 |
if cp is not None: |
537 |
cp_list = cp_map.get(cp) |
538 |
if cp_list is None: |
539 |
cp_list = [] |
540 |
cp_map[cp] = cp_list |
541 |
cp_list.append(_pkg_str(cpv)) |
542 |
return list(cp_map) |
543 |
|
544 |
def match(self, atom): |
545 |
if not isinstance(atom, Atom): |
546 |
atom = Atom(atom) |
547 |
cp_list = self._cp_map.get(atom.cp) |
548 |
if cp_list is None: |
549 |
return [] |
550 |
self._vardb._cpv_sort_ascending(cp_list) |
551 |
return portage.match_from_list(atom, cp_list) |
552 |
|
553 |
def aux_get(self, cpv, attrs, myrepo = None): |
554 |
pkg_data = self._vardb._aux_cache["packages"].get(cpv) |
555 |
if not isinstance(pkg_data, tuple) or \ |
556 |
len(pkg_data) != 2 or \ |
557 |
not isinstance(pkg_data[1], dict): |
558 |
pkg_data = None |
559 |
if pkg_data is None: |
560 |
# It may be missing from _aux_cache due to |
561 |
# _aux_cache_threshold. |
562 |
return self._vardb.aux_get(cpv, attrs) |
563 |
metadata = pkg_data[1] |
564 |
return [metadata.get(k, "") for k in attrs] |