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] emerge: add --search-fuzzy and --search-fuzzy-cutoff options (bug 65566)
Date: Mon, 04 Apr 2016 05:03:44
Message-Id: 1459746182-13420-1-git-send-email-zmedico@gentoo.org
1 Add --search-fuzzy option, with adjustable similarity ratio cutoff that
2 defaults to 0.8 (80% similarity).
3
4 X-Gentoo-bug: 65566
5 X-Gentoo-bug-url: https://bugs.gentoo.org/show_bug.cgi?id=65566
6 ---
7 man/emerge.1 | 13 ++++++++++++-
8 pym/_emerge/actions.py | 6 ++++--
9 pym/_emerge/main.py | 32 +++++++++++++++++++++++++++++++-
10 pym/_emerge/search.py | 25 +++++++++++++++++++++++--
11 4 files changed, 70 insertions(+), 6 deletions(-)
12
13 diff --git a/man/emerge.1 b/man/emerge.1
14 index bfa2f73..2727ccb 100644
15 --- a/man/emerge.1
16 +++ b/man/emerge.1
17 @@ -1,4 +1,4 @@
18 -.TH "EMERGE" "1" "Feb 2016" "Portage VERSION" "Portage"
19 +.TH "EMERGE" "1" "Apr 2016" "Portage VERSION" "Portage"
20 .SH "NAME"
21 emerge \- Command\-line interface to the Portage system
22 .SH "SYNOPSIS"
23 @@ -854,6 +854,17 @@ If ebuilds using EAPIs which \fIdo not\fR support \fBHDEPEND\fR are built in
24 the same \fBemerge\fR run as those using EAPIs which \fIdo\fR support
25 \fBHDEPEND\fR, this option affects only the former.
26 .TP
27 +.BR "\-\-search\-fuzzy [ y | n ]"
28 +Enable or disable fuzzy search for search actions.
29 +.TP
30 +.BR "\-\-search\-fuzzy\-cutoff CUTOFF"
31 +Set similarity ratio cutoff (a floating-point number between 0 and 1).
32 +Results with similarity ratios lower than the cutoff are discarded.
33 +This option has no effect unless the \fB\-\-search\-fuzzy\fR option
34 +is enabled.
35 +.br
36 +Defaults to 0.8 (80% similarity).
37 +.TP
38 .BR "\-\-search\-index < y | n >"
39 Enable or disable indexed search for search actions. This option is
40 enabled by default. The search index needs to be regenerated by
41 diff --git a/pym/_emerge/actions.py b/pym/_emerge/actions.py
42 index 59626ad..caae79a 100644
43 --- a/pym/_emerge/actions.py
44 +++ b/pym/_emerge/actions.py
45 @@ -1,4 +1,4 @@
46 -# Copyright 1999-2015 Gentoo Foundation
47 +# Copyright 1999-2016 Gentoo Foundation
48 # Distributed under the terms of the GNU General Public License v2
49
50 from __future__ import division, print_function, unicode_literals
51 @@ -1955,7 +1955,9 @@ def action_search(root_config, myopts, myfiles, spinner):
52 spinner, "--searchdesc" in myopts,
53 "--quiet" not in myopts, "--usepkg" in myopts,
54 "--usepkgonly" in myopts,
55 - search_index = myopts.get("--search-index", "y") != "n")
56 + search_index=myopts.get("--search-index", "y") != "n",
57 + fuzzy=myopts.get("--search-fuzzy", False),
58 + fuzzy_cutoff=myopts.get("--search-fuzzy-cutoff"))
59 for mysearch in myfiles:
60 try:
61 searchinstance.execute(mysearch)
62 diff --git a/pym/_emerge/main.py b/pym/_emerge/main.py
63 index 5dbafee..06c385e 100644
64 --- a/pym/_emerge/main.py
65 +++ b/pym/_emerge/main.py
66 @@ -1,4 +1,4 @@
67 -# Copyright 1999-2015 Gentoo Foundation
68 +# Copyright 1999-2016 Gentoo Foundation
69 # Distributed under the terms of the GNU General Public License v2
70
71 from __future__ import print_function
72 @@ -156,6 +156,7 @@ def insert_optional_args(args):
73 '--rebuild-if-unbuilt' : y_or_n,
74 '--rebuilt-binaries' : y_or_n,
75 '--root-deps' : ('rdeps',),
76 + '--search-fuzzy' : y_or_n,
77 '--select' : y_or_n,
78 '--selective' : y_or_n,
79 "--use-ebuild-visibility": y_or_n,
80 @@ -647,6 +648,16 @@ def parse_opts(tmpcmdline, silent=False):
81 "choices" :("True", "rdeps")
82 },
83
84 + "--search-fuzzy": {
85 + "help": "Enable or disable fuzzy search",
86 + "choices": true_y_or_n
87 + },
88 +
89 + "--search-fuzzy-cutoff": {
90 + "help": "Set similarity ratio cutoff (a floating-point number between 0 and 1)",
91 + "action": "store"
92 + },
93 +
94 "--search-index": {
95 "help": "Enable or disable indexed search (enabled by default)",
96 "choices": y_or_n
97 @@ -908,6 +919,11 @@ def parse_opts(tmpcmdline, silent=False):
98 if myoptions.root_deps in true_y:
99 myoptions.root_deps = True
100
101 + if myoptions.search_fuzzy in true_y:
102 + myoptions.search_fuzzy = True
103 + else:
104 + myoptions.search_fuzzy = None
105 +
106 if myoptions.select in true_y:
107 myoptions.select = True
108 myoptions.oneshot = False
109 @@ -1000,6 +1016,20 @@ def parse_opts(tmpcmdline, silent=False):
110
111 myoptions.rebuilt_binaries_timestamp = rebuilt_binaries_timestamp
112
113 + if myoptions.search_fuzzy_cutoff:
114 + try:
115 + fuzzy_cutoff = float(myoptions.search_fuzzy_cutoff)
116 + except ValueError:
117 + fuzzy_cutoff = 0.0
118 +
119 + if fuzzy_cutoff <= 0.0:
120 + fuzzy_cutoff = None
121 + if not silent:
122 + parser.error("Invalid --search-fuzzy-cutoff parameter: '%s'\n" % \
123 + (myoptions.search_fuzzy_cutoff,))
124 +
125 + myoptions.search_fuzzy_cutoff = fuzzy_cutoff
126 +
127 if myoptions.use_ebuild_visibility in true_y:
128 myoptions.use_ebuild_visibility = True
129 else:
130 diff --git a/pym/_emerge/search.py b/pym/_emerge/search.py
131 index 32d326e..3210854 100644
132 --- a/pym/_emerge/search.py
133 +++ b/pym/_emerge/search.py
134 @@ -1,8 +1,9 @@
135 -# Copyright 1999-2015 Gentoo Foundation
136 +# Copyright 1999-2016 Gentoo Foundation
137 # Distributed under the terms of the GNU General Public License v2
138
139 from __future__ import unicode_literals
140
141 +import difflib
142 import re
143 import portage
144 from portage import os
145 @@ -28,7 +29,8 @@ class search(object):
146 # public interface
147 #
148 def __init__(self, root_config, spinner, searchdesc,
149 - verbose, usepkg, usepkgonly, search_index=True):
150 + verbose, usepkg, usepkgonly, search_index=True,
151 + fuzzy=False, fuzzy_cutoff=None):
152 """Searches the available and installed packages for the supplied search key.
153 The list of available and installed packages is created at object instantiation.
154 This makes successive searches faster."""
155 @@ -42,6 +44,8 @@ class search(object):
156 self.spinner = None
157 self.root_config = root_config
158 self.setconfig = root_config.setconfig
159 + self.fuzzy = fuzzy
160 + self.fuzzy_cutoff = 0.8 if fuzzy_cutoff is None else fuzzy_cutoff
161 self.matches = {"pkg" : []}
162 self.mlen = 0
163
164 @@ -248,11 +252,26 @@ class search(object):
165 if self.searchkey.startswith('@'):
166 match_category = 1
167 self.searchkey = self.searchkey[1:]
168 + fuzzy = False
169 if regexsearch:
170 self.searchre=re.compile(self.searchkey,re.I)
171 else:
172 self.searchre=re.compile(re.escape(self.searchkey), re.I)
173
174 + # Fuzzy search does not support regular expressions, therefore
175 + # it is disabled for regular expression searches.
176 + if self.fuzzy:
177 + fuzzy = True
178 + cutoff = self.fuzzy_cutoff
179 + seq_match = difflib.SequenceMatcher()
180 + seq_match.set_seq2(self.searchkey.lower())
181 +
182 + def fuzzy_search(match_string):
183 + seq_match.set_seq1(match_string.lower())
184 + return (seq_match.real_quick_ratio() >= cutoff and
185 + seq_match.quick_ratio() >= cutoff and
186 + seq_match.ratio() >= cutoff)
187 +
188 for package in self._cp_all():
189 self._spinner_update()
190
191 @@ -280,6 +299,8 @@ class search(object):
192 continue
193
194 yield ("desc", package)
195 + elif fuzzy and fuzzy_search(match_string):
196 + yield ("pkg", package)
197
198 self.sdict = self.setconfig.getSets()
199 for setname in self.sdict:
200 --
201 2.7.4

Replies