Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 525718 | Differences between
and this patch

Collapse All | Expand All

(-)a/bin/egencache (-2 / +41 lines)
Lines 57-63 from portage.util._async.run_main_scheduler import run_main_scheduler Link Here
57
from portage.util._eventloop.global_event_loop import global_event_loop
57
from portage.util._eventloop.global_event_loop import global_event_loop
58
from portage import cpv_getkey
58
from portage import cpv_getkey
59
from portage.dep import Atom, isjustname
59
from portage.dep import Atom, isjustname
60
from portage.versions import pkgsplit, vercmp
60
from portage.versions import pkgsplit, vercmp, _pkg_str
61
61
62
try:
62
try:
63
	from xml.etree import ElementTree
63
	from xml.etree import ElementTree
Lines 91-96 def parse_args(args): Link Here
91
	actions.add_argument("--update-changelogs",
91
	actions.add_argument("--update-changelogs",
92
		action="store_true",
92
		action="store_true",
93
		help="update the ChangeLog files from SCM logs")
93
		help="update the ChangeLog files from SCM logs")
94
	actions.add_argument("--update-pkg-desc-index",
95
		action="store_true",
96
		help="update package description index")
94
	actions.add_argument("--update-manifests",
97
	actions.add_argument("--update-manifests",
95
		action="store_true",
98
		action="store_true",
96
		help="update manifests")
99
		help="update manifests")
Lines 451-456 class GenCache(object): Link Here
451
		if hasattr(trg_cache, '_prune_empty_dirs'):
454
		if hasattr(trg_cache, '_prune_empty_dirs'):
452
			trg_cache._prune_empty_dirs()
455
			trg_cache._prune_empty_dirs()
453
456
457
class GenPkgDescIndex(object):
458
	def __init__(self, portdb, output_file):
459
		self.returncode = os.EX_OK
460
		self._portdb = portdb
461
		self._output_file = output_file
462
463
	def run(self):
464
465
		portage.util.ensure_dirs(os.path.dirname(self._output_file))
466
		f = portage.util.atomic_ofstream(self._output_file,
467
			encoding=_encodings["repo.content"])
468
469
		portdb = self._portdb
470
		for cp in portdb.cp_all():
471
			pkgs = portdb.cp_list(cp)
472
			if not pkgs:
473
				continue
474
			desc, = portdb.aux_get(pkgs[-1], ["DESCRIPTION"])
475
476
			if len(pkgs) == 1:
477
				output = "%s: %s\n" % (pkgs[0], desc)
478
			else:
479
				output = "%s,%s: %s\n" % (pkgs[0],
480
					",".join(_pkg_str(cpv).version
481
					for cpv in pkgs[1:]), desc)
482
			f.write(output)
483
484
		f.close()
485
454
class GenUseLocalDesc(object):
486
class GenUseLocalDesc(object):
455
	def __init__(self, portdb, output=None,
487
	def __init__(self, portdb, output=None,
456
			preserve_comments=False):
488
			preserve_comments=False):
Lines 893-899 def egencache_main(args): Link Here
893
			local_config=False, env=env)
925
			local_config=False, env=env)
894
926
895
	if not (options.update or options.update_use_local_desc or
927
	if not (options.update or options.update_use_local_desc or
896
			options.update_changelogs or options.update_manifests):
928
			options.update_changelogs or options.update_manifests or
929
			options.update_pkg_desc_index):
897
		parser.error('No action specified')
930
		parser.error('No action specified')
898
		return 1
931
		return 1
899
932
Lines 1057-1062 def egencache_main(args): Link Here
1057
		else:
1090
		else:
1058
			ret.append(scheduler.returncode)
1091
			ret.append(scheduler.returncode)
1059
1092
1093
	if options.update_pkg_desc_index:
1094
		gen_index = GenPkgDescIndex(portdb, os.path.join(
1095
			repo_config.location, "metadata", "pkg_desc_index"))
1096
		gen_index.run()
1097
		ret.append(gen_index.returncode)
1098
1060
	if options.update_use_local_desc:
1099
	if options.update_use_local_desc:
1061
		gen_desc = GenUseLocalDesc(portdb,
1100
		gen_desc = GenUseLocalDesc(portdb,
1062
			output=options.uld_output,
1101
			output=options.uld_output,
(-)a/man/egencache.1 (+4 lines)
Lines 19-24 for the details on package atom syntax. Link Here
19
.BR "\-\-update\-changelogs"
19
.BR "\-\-update\-changelogs"
20
Update the ChangeLog files from SCM logs (supported only in git repos).
20
Update the ChangeLog files from SCM logs (supported only in git repos).
21
.TP
21
.TP
22
.BR "\-\-update\-pkg\-desc\-index"
23
Update the package description index which is located at
24
\fImetadata/pkg_desc_index\fR in the repository.
25
.TP
22
.BR "\-\-update\-use\-local\-desc"
26
.BR "\-\-update\-use\-local\-desc"
23
Update the \fIprofiles/use.local.desc\fR file from metadata.xml.
27
Update the \fIprofiles/use.local.desc\fR file from metadata.xml.
24
.TP
28
.TP
(-)a/man/emerge.1 (+8 lines)
Lines 790-795 If ebuilds using EAPIs which \fIdo not\fR support \fBHDEPEND\fR are built in Link Here
790
the same \fBemerge\fR run as those using EAPIs which \fIdo\fR support
790
the same \fBemerge\fR run as those using EAPIs which \fIdo\fR support
791
\fBHDEPEND\fR, this option affects only the former.
791
\fBHDEPEND\fR, this option affects only the former.
792
.TP
792
.TP
793
.BR "\-\-search\-index < y | n >"
794
Enable or disable indexed search for search actions. This option is
795
enabled by default. The search index needs to be regenerated by
796
\fBegencache\fR(1) after changes are made to a repository (see the
797
\fB\-\-update\-pkg\-desc\-index\fR action). This setting can be added
798
to \fBEMERGE_DEFAULT_OPTS\fR (see \fBmake.conf\fR(5)) and later
799
overridden via the command line.
800
.TP
793
.BR "\-\-select [ y | n ] (\-w short option)"
801
.BR "\-\-select [ y | n ] (\-w short option)"
794
Add specified packages to the world set (inverse of
802
Add specified packages to the world set (inverse of
795
\fB\-\-oneshot\fR). This is useful if you want to
803
\fB\-\-oneshot\fR). This is useful if you want to
(-)a/man/portage.5 (+6 lines)
Lines 75-80 user\-defined package sets Link Here
75
.BR /usr/portage/metadata/
75
.BR /usr/portage/metadata/
76
.nf
76
.nf
77
layout.conf
77
layout.conf
78
pkg_desc_index
78
.fi
79
.fi
79
.TP
80
.TP
80
.BR /usr/portage/profiles/
81
.BR /usr/portage/profiles/
Lines 1110-1115 cache\-formats = md5-dict pms Link Here
1110
profile\-formats = portage-2
1111
profile\-formats = portage-2
1111
.fi
1112
.fi
1112
.RE
1113
.RE
1114
.TP
1115
.BR pkg_desc_index
1116
This is an index of packages and descriptions which may be generated
1117
by \fBegencache\fR(1) in order to optimize \fBemerge\fR(1) search
1118
actions.
1113
.RE
1119
.RE
1114
.TP
1120
.TP
1115
.BR /usr/portage/profiles/
1121
.BR /usr/portage/profiles/
(-)a/pym/_emerge/actions.py (-1 / +2 lines)
Lines 2015-2021 def action_search(root_config, myopts, myfiles, spinner): Link Here
2015
		searchinstance = search(root_config,
2015
		searchinstance = search(root_config,
2016
			spinner, "--searchdesc" in myopts,
2016
			spinner, "--searchdesc" in myopts,
2017
			"--quiet" not in myopts, "--usepkg" in myopts,
2017
			"--quiet" not in myopts, "--usepkg" in myopts,
2018
			"--usepkgonly" in myopts)
2018
			"--usepkgonly" in myopts,
2019
			search_index = myopts.get("--search-index", "y") != "n")
2019
		for mysearch in myfiles:
2020
		for mysearch in myfiles:
2020
			try:
2021
			try:
2021
				searchinstance.execute(mysearch)
2022
				searchinstance.execute(mysearch)
(-)a/pym/_emerge/main.py (+5 lines)
Lines 616-621 def parse_opts(tmpcmdline, silent=False): Link Here
616
			"choices" :("True", "rdeps")
616
			"choices" :("True", "rdeps")
617
		},
617
		},
618
618
619
		"--search-index": {
620
			"help": "Enable or disable indexed search (enabled by default)",
621
			"choices": y_or_n
622
		},
623
619
		"--select": {
624
		"--select": {
620
			"shortopt" : "-w",
625
			"shortopt" : "-w",
621
			"help"    : "add specified packages to the world set " + \
626
			"help"    : "add specified packages to the world set " + \
(-)a/pym/_emerge/search.py (-15 / +184 lines)
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]

Return to bug 525718