Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH] Display emerge search results incrementally (412471)
Date: Wed, 05 Nov 2014 04:32:41
Message-Id: 1415161950-31767-1-git-send-email-zmedico@gentoo.org
1 This makes emerge --search / --searchdesc display individual search
2 results as soon as they become available. A search._iter_search method
3 is split out from the search.execute method, and the search.output
4 method operates on that. The spinner is now disabled, but the spinner
5 code remains, in case we later decide to enable it optionally.
6
7 X-Gentoo-Bug: 412471
8 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=412471
9 ---
10 Note that this patch has been split out from the series for bug 525718.
11
12 pym/_emerge/search.py | 120 +++++++++++++++++++++++++++++---------------------
13 1 file changed, 71 insertions(+), 49 deletions(-)
14
15 diff --git a/pym/_emerge/search.py b/pym/_emerge/search.py
16 index 4b0fd9f..7276c0e 100644
17 --- a/pym/_emerge/search.py
18 +++ b/pym/_emerge/search.py
19 @@ -1,8 +1,6 @@
20 # Copyright 1999-2014 Gentoo Foundation
21 # Distributed under the terms of the GNU General Public License v2
22
23 -from __future__ import print_function
24 -
25 import re
26 import portage
27 from portage import os
28 @@ -30,10 +28,12 @@ class search(object):
29 The list of available and installed packages is created at object instantiation.
30 This makes successive searches faster."""
31 self.settings = root_config.settings
32 - self.vartree = root_config.trees["vartree"]
33 - self.spinner = spinner
34 self.verbose = verbose
35 self.searchdesc = searchdesc
36 + self.searchkey = None
37 + # Disable the spinner since search results are displayed
38 + # incrementally.
39 + self.spinner = None
40 self.root_config = root_config
41 self.setconfig = root_config.setconfig
42 self.matches = {"pkg" : []}
43 @@ -53,6 +53,7 @@ class search(object):
44
45 self._dbs.append(vardb)
46 self._portdb = portdb
47 + self._vardb = vardb
48
49 def _spinner_update(self):
50 if self.spinner:
51 @@ -97,7 +98,7 @@ class search(object):
52 return {}
53
54 def _visible(self, db, cpv, metadata):
55 - installed = db is self.vartree.dbapi
56 + installed = db is self._vardb
57 built = installed or db is not self._portdb
58 pkg_type = "ebuild"
59 if installed:
60 @@ -171,8 +172,11 @@ class search(object):
61
62 def execute(self,searchkey):
63 """Performs the search for the supplied search key"""
64 + self.searchkey = searchkey
65 +
66 + def _iter_search(self):
67 +
68 match_category = 0
69 - self.searchkey=searchkey
70 self.packagematches = []
71 if self.searchdesc:
72 self.searchdesc=1
73 @@ -180,7 +184,7 @@ class search(object):
74 else:
75 self.searchdesc=0
76 self.matches = {"pkg":[], "set":[]}
77 - print("Searching... ", end=' ')
78 + writemsg_stdout("Searching...\n\n", noiselevel=-1)
79
80 regexsearch = False
81 if self.searchkey.startswith('%'):
82 @@ -202,29 +206,28 @@ class search(object):
83 else:
84 match_string = package.split("/")[-1]
85
86 - masked=0
87 if self.searchre.search(match_string):
88 - if not self._xmatch("match-visible", package):
89 - masked=1
90 - self.matches["pkg"].append([package,masked])
91 + yield ("pkg", package)
92 elif self.searchdesc: # DESCRIPTION searching
93 - full_package = self._xmatch("bestmatch-visible", package)
94 + # Use match-all to avoid an expensive visibility check,
95 + # since the visibility check can be avoided entirely
96 + # when the DESCRIPTION does not match.
97 + full_package = self._xmatch("match-all", package)
98 if not full_package:
99 - #no match found; we don't want to query description
100 - full_package = portage.best(
101 - self._xmatch("match-all", package))
102 - if not full_package:
103 - continue
104 - else:
105 - masked=1
106 + continue
107 + full_package = full_package[-1]
108 try:
109 full_desc = self._aux_get(
110 full_package, ["DESCRIPTION"])[0]
111 except KeyError:
112 - print("emerge: search: aux_get() failed, skipping")
113 + portage.writemsg(
114 + "emerge: search: aux_get() failed, skipping\n",
115 + noiselevel=-1)
116 continue
117 - if self.searchre.search(full_desc):
118 - self.matches["desc"].append([full_package,masked])
119 + if not self.searchre.search(full_desc):
120 + continue
121 +
122 + yield ("desc", package)
123
124 self.sdict = self.setconfig.getSets()
125 for setname in self.sdict:
126 @@ -235,51 +238,56 @@ class search(object):
127 match_string = setname.split("/")[-1]
128
129 if self.searchre.search(match_string):
130 - self.matches["set"].append([setname, False])
131 + yield ("set", setname, False)
132 elif self.searchdesc:
133 if self.searchre.search(
134 self.sdict[setname].getMetadata("DESCRIPTION")):
135 - self.matches["set"].append([setname, False])
136 -
137 - self.mlen=0
138 - for mtype in self.matches:
139 - self.matches[mtype].sort()
140 - self.mlen += len(self.matches[mtype])
141 + yield ("set", setname)
142
143 def addCP(self, cp):
144 if not self._xmatch("match-all", cp):
145 return
146 - masked = 0
147 - if not self._xmatch("bestmatch-visible", cp):
148 - masked = 1
149 - self.matches["pkg"].append([cp, masked])
150 + self.matches["pkg"].append(cp)
151 self.mlen += 1
152
153 def output(self):
154 """Outputs the results of the search."""
155 - msg = []
156 +
157 + class msg(object):
158 + @staticmethod
159 + def append(msg):
160 + writemsg_stdout(msg, noiselevel=-1)
161 +
162 msg.append("\b\b \n[ Results for search key : " + \
163 bold(self.searchkey) + " ]\n")
164 - msg.append("[ Applications found : " + \
165 - bold(str(self.mlen)) + " ]\n\n")
166 - vardb = self.vartree.dbapi
167 + vardb = self._vardb
168 metadata_keys = set(Package.metadata_keys)
169 metadata_keys.update(["DESCRIPTION", "HOMEPAGE", "LICENSE", "SRC_URI"])
170 metadata_keys = tuple(metadata_keys)
171 - for mtype in self.matches:
172 - for match,masked in self.matches[mtype]:
173 +
174 + if self.searchkey is None:
175 + # Handle results added via addCP
176 + addCP_matches = []
177 + for mytype, match in self.matches.items():
178 + addCP_matches.append(mytype, match)
179 + iterator = iter(addCP_matches)
180 +
181 + else:
182 + # Do a normal search
183 + iterator = self._iter_search()
184 +
185 + for mtype, match in iterator:
186 + self.mlen += 1
187 + masked = False
188 full_package = None
189 - if mtype == "pkg":
190 + if mtype in ("pkg", "desc"):
191 full_package = self._xmatch(
192 "bestmatch-visible", match)
193 if not full_package:
194 - #no match found; we don't want to query description
195 - masked=1
196 - full_package = portage.best(
197 - self._xmatch("match-all",match))
198 - elif mtype == "desc":
199 - full_package = match
200 - match = portage.cpv_getkey(match)
201 + masked = True
202 + full_package = self._xmatch("match-all", match)
203 + if full_package:
204 + full_package = full_package[-1]
205 elif mtype == "set":
206 msg.append(green("*") + " " + bold(match) + "\n")
207 if self.verbose:
208 @@ -367,12 +375,26 @@ class search(object):
209 + " " + desc + "\n")
210 msg.append(" " + darkgreen("License:") + \
211 " " + license + "\n\n")
212 - writemsg_stdout(''.join(msg), noiselevel=-1)
213 +
214 + msg.append("[ Applications found : " + \
215 + bold(str(self.mlen)) + " ]\n\n")
216 +
217 + # This method can be called multiple times, so
218 + # reset the match count for the next call. Don't
219 + # reset it at the beginning of this method, since
220 + # that would lose modfications from the addCP
221 + # method.
222 + self.mlen = 0
223 +
224 #
225 # private interface
226 #
227 def getInstallationStatus(self,package):
228 - installed_package = self.vartree.dep_bestmatch(package)
229 + installed_package = self._vardb.match(package)
230 + if installed_package:
231 + installed_package = installed_package[-1]
232 + else:
233 + installed_package = ""
234 result = ""
235 version = self.getVersion(installed_package,search.VERSION_RELEASE)
236 if len(version) > 0:
237 --
238 2.0.4