Merge lp:~jelmer/brz/promote-grep into lp:brz
- promote-grep
- Merge into trunk
Proposed by
Jelmer Vernooij
Status: | Merged |
---|---|
Approved by: | Jelmer Vernooij |
Approved revision: | no longer in the source branch. |
Merge reported by: | The Breezy Bot |
Merged at revision: | not available |
Proposed branch: | lp:~jelmer/brz/promote-grep |
Merge into: | lp:brz |
Diff against target: |
790 lines (+245/-394) 9 files modified
breezy/builtins.py (+178/-0) breezy/grep.py (+46/-11) breezy/plugins/grep/.bzrignore (+0/-1) breezy/plugins/grep/NEWS (+0/-73) breezy/plugins/grep/__init__.py (+0/-38) breezy/plugins/grep/cmds.py (+0/-254) breezy/tests/__init__.py (+1/-0) breezy/tests/test_grep.py (+17/-17) doc/en/release-notes/brz-3.0.txt (+3/-0) |
To merge this branch: | bzr merge lp:~jelmer/brz/promote-grep |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Packman | Approve | ||
Review via email: mp+359487@code.launchpad.net |
Commit message
Move grep into core.
Description of the change
Move grep into core.
To post a comment you must log in.
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
https:/
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
https:/
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'breezy/builtins.py' | |||
2 | --- breezy/builtins.py 2019-01-27 18:48:32 +0000 | |||
3 | +++ breezy/builtins.py 2019-02-04 01:01:36 +0000 | |||
4 | @@ -6831,6 +6831,184 @@ | |||
5 | 6831 | cmd_reconcile().run(".") | 6831 | cmd_reconcile().run(".") |
6 | 6832 | 6832 | ||
7 | 6833 | 6833 | ||
8 | 6834 | class cmd_grep(Command): | ||
9 | 6835 | """Print lines matching PATTERN for specified files and revisions. | ||
10 | 6836 | |||
11 | 6837 | This command searches the specified files and revisions for a given | ||
12 | 6838 | pattern. The pattern is specified as a Python regular expressions[1]. | ||
13 | 6839 | |||
14 | 6840 | If the file name is not specified, the revisions starting with the | ||
15 | 6841 | current directory are searched recursively. If the revision number is | ||
16 | 6842 | not specified, the working copy is searched. To search the last committed | ||
17 | 6843 | revision, use the '-r -1' or '-r last:1' option. | ||
18 | 6844 | |||
19 | 6845 | Unversioned files are not searched unless explicitly specified on the | ||
20 | 6846 | command line. Unversioned directores are not searched. | ||
21 | 6847 | |||
22 | 6848 | When searching a pattern, the output is shown in the 'filepath:string' | ||
23 | 6849 | format. If a revision is explicitly searched, the output is shown as | ||
24 | 6850 | 'filepath~N:string', where N is the revision number. | ||
25 | 6851 | |||
26 | 6852 | --include and --exclude options can be used to search only (or exclude | ||
27 | 6853 | from search) files with base name matches the specified Unix style GLOB | ||
28 | 6854 | pattern. The GLOB pattern an use *, ?, and [...] as wildcards, and \\ | ||
29 | 6855 | to quote wildcard or backslash character literally. Note that the glob | ||
30 | 6856 | pattern is not a regular expression. | ||
31 | 6857 | |||
32 | 6858 | [1] http://docs.python.org/library/re.html#regular-expression-syntax | ||
33 | 6859 | """ | ||
34 | 6860 | |||
35 | 6861 | encoding_type = 'replace' | ||
36 | 6862 | takes_args = ['pattern', 'path*'] | ||
37 | 6863 | takes_options = [ | ||
38 | 6864 | 'verbose', | ||
39 | 6865 | 'revision', | ||
40 | 6866 | Option('color', type=text_type, argname='when', | ||
41 | 6867 | help='Show match in color. WHEN is never, always or auto.'), | ||
42 | 6868 | Option('diff', short_name='p', | ||
43 | 6869 | help='Grep for pattern in changeset for each revision.'), | ||
44 | 6870 | ListOption('exclude', type=text_type, argname='glob', short_name='X', | ||
45 | 6871 | help="Skip files whose base name matches GLOB."), | ||
46 | 6872 | ListOption('include', type=text_type, argname='glob', short_name='I', | ||
47 | 6873 | help="Search only files whose base name matches GLOB."), | ||
48 | 6874 | Option('files-with-matches', short_name='l', | ||
49 | 6875 | help='Print only the name of each input file in ' | ||
50 | 6876 | 'which PATTERN is found.'), | ||
51 | 6877 | Option('files-without-match', short_name='L', | ||
52 | 6878 | help='Print only the name of each input file in ' | ||
53 | 6879 | 'which PATTERN is not found.'), | ||
54 | 6880 | Option('fixed-string', short_name='F', | ||
55 | 6881 | help='Interpret PATTERN is a single fixed string (not regex).'), | ||
56 | 6882 | Option('from-root', | ||
57 | 6883 | help='Search for pattern starting from the root of the branch. ' | ||
58 | 6884 | '(implies --recursive)'), | ||
59 | 6885 | Option('ignore-case', short_name='i', | ||
60 | 6886 | help='Ignore case distinctions while matching.'), | ||
61 | 6887 | Option('levels', | ||
62 | 6888 | help='Number of levels to display - 0 for all, 1 for collapsed ' | ||
63 | 6889 | '(1 is default).', | ||
64 | 6890 | argname='N', | ||
65 | 6891 | type=_parse_levels), | ||
66 | 6892 | Option('line-number', short_name='n', | ||
67 | 6893 | help='Show 1-based line number.'), | ||
68 | 6894 | Option('no-recursive', | ||
69 | 6895 | help="Don't recurse into subdirectories. (default is --recursive)"), | ||
70 | 6896 | Option('null', short_name='Z', | ||
71 | 6897 | help='Write an ASCII NUL (\\0) separator ' | ||
72 | 6898 | 'between output lines rather than a newline.'), | ||
73 | 6899 | ] | ||
74 | 6900 | |||
75 | 6901 | @display_command | ||
76 | 6902 | def run(self, verbose=False, ignore_case=False, no_recursive=False, | ||
77 | 6903 | from_root=False, null=False, levels=None, line_number=False, | ||
78 | 6904 | path_list=None, revision=None, pattern=None, include=None, | ||
79 | 6905 | exclude=None, fixed_string=False, files_with_matches=False, | ||
80 | 6906 | files_without_match=False, color=None, diff=False): | ||
81 | 6907 | from breezy import _termcolor | ||
82 | 6908 | from . import grep | ||
83 | 6909 | import re | ||
84 | 6910 | if path_list is None: | ||
85 | 6911 | path_list = ['.'] | ||
86 | 6912 | else: | ||
87 | 6913 | if from_root: | ||
88 | 6914 | raise errors.BzrCommandError( | ||
89 | 6915 | 'cannot specify both --from-root and PATH.') | ||
90 | 6916 | |||
91 | 6917 | if files_with_matches and files_without_match: | ||
92 | 6918 | raise errors.BzrCommandError( | ||
93 | 6919 | 'cannot specify both ' | ||
94 | 6920 | '-l/--files-with-matches and -L/--files-without-matches.') | ||
95 | 6921 | |||
96 | 6922 | global_config = _mod_config.GlobalConfig() | ||
97 | 6923 | |||
98 | 6924 | if color is None: | ||
99 | 6925 | color = global_config.get_user_option('grep_color') | ||
100 | 6926 | |||
101 | 6927 | if color is None: | ||
102 | 6928 | color = 'never' | ||
103 | 6929 | |||
104 | 6930 | if color not in ['always', 'never', 'auto']: | ||
105 | 6931 | raise errors.BzrCommandError('Valid values for --color are ' | ||
106 | 6932 | '"always", "never" or "auto".') | ||
107 | 6933 | |||
108 | 6934 | if levels is None: | ||
109 | 6935 | levels = 1 | ||
110 | 6936 | |||
111 | 6937 | print_revno = False | ||
112 | 6938 | if revision is not None or levels == 0: | ||
113 | 6939 | # print revision numbers as we may be showing multiple revisions | ||
114 | 6940 | print_revno = True | ||
115 | 6941 | |||
116 | 6942 | eol_marker = '\n' | ||
117 | 6943 | if null: | ||
118 | 6944 | eol_marker = '\0' | ||
119 | 6945 | |||
120 | 6946 | if not ignore_case and grep.is_fixed_string(pattern): | ||
121 | 6947 | # if the pattern isalnum, implicitly use to -F for faster grep | ||
122 | 6948 | fixed_string = True | ||
123 | 6949 | elif ignore_case and fixed_string: | ||
124 | 6950 | # GZ 2010-06-02: Fall back to regexp rather than lowercasing | ||
125 | 6951 | # pattern and text which will cause pain later | ||
126 | 6952 | fixed_string = False | ||
127 | 6953 | pattern = re.escape(pattern) | ||
128 | 6954 | |||
129 | 6955 | patternc = None | ||
130 | 6956 | re_flags = re.MULTILINE | ||
131 | 6957 | if ignore_case: | ||
132 | 6958 | re_flags |= re.IGNORECASE | ||
133 | 6959 | |||
134 | 6960 | if not fixed_string: | ||
135 | 6961 | patternc = grep.compile_pattern( | ||
136 | 6962 | pattern.encode(grep._user_encoding), re_flags) | ||
137 | 6963 | |||
138 | 6964 | if color == 'always': | ||
139 | 6965 | show_color = True | ||
140 | 6966 | elif color == 'never': | ||
141 | 6967 | show_color = False | ||
142 | 6968 | elif color == 'auto': | ||
143 | 6969 | show_color = _termcolor.allow_color() | ||
144 | 6970 | |||
145 | 6971 | opts = grep.GrepOptions() | ||
146 | 6972 | |||
147 | 6973 | opts.verbose = verbose | ||
148 | 6974 | opts.ignore_case = ignore_case | ||
149 | 6975 | opts.no_recursive = no_recursive | ||
150 | 6976 | opts.from_root = from_root | ||
151 | 6977 | opts.null = null | ||
152 | 6978 | opts.levels = levels | ||
153 | 6979 | opts.line_number = line_number | ||
154 | 6980 | opts.path_list = path_list | ||
155 | 6981 | opts.revision = revision | ||
156 | 6982 | opts.pattern = pattern | ||
157 | 6983 | opts.include = include | ||
158 | 6984 | opts.exclude = exclude | ||
159 | 6985 | opts.fixed_string = fixed_string | ||
160 | 6986 | opts.files_with_matches = files_with_matches | ||
161 | 6987 | opts.files_without_match = files_without_match | ||
162 | 6988 | opts.color = color | ||
163 | 6989 | opts.diff = False | ||
164 | 6990 | |||
165 | 6991 | opts.eol_marker = eol_marker | ||
166 | 6992 | opts.print_revno = print_revno | ||
167 | 6993 | opts.patternc = patternc | ||
168 | 6994 | opts.recursive = not no_recursive | ||
169 | 6995 | opts.fixed_string = fixed_string | ||
170 | 6996 | opts.outf = self.outf | ||
171 | 6997 | opts.show_color = show_color | ||
172 | 6998 | |||
173 | 6999 | if diff: | ||
174 | 7000 | # options not used: | ||
175 | 7001 | # files_with_matches, files_without_match | ||
176 | 7002 | # levels(?), line_number, from_root | ||
177 | 7003 | # include, exclude | ||
178 | 7004 | # These are silently ignored. | ||
179 | 7005 | grep.grep_diff(opts) | ||
180 | 7006 | elif revision is None: | ||
181 | 7007 | grep.workingtree_grep(opts) | ||
182 | 7008 | else: | ||
183 | 7009 | grep.versioned_grep(opts) | ||
184 | 7010 | |||
185 | 7011 | |||
186 | 6834 | def _register_lazy_builtins(): | 7012 | def _register_lazy_builtins(): |
187 | 6835 | # register lazy builtins from other modules; called at startup and should | 7013 | # register lazy builtins from other modules; called at startup and should |
188 | 6836 | # be only called once. | 7014 | # be only called once. |
189 | 6837 | 7015 | ||
190 | === renamed file 'breezy/plugins/grep/grep.py' => 'breezy/grep.py' | |||
191 | --- breezy/plugins/grep/grep.py 2018-11-21 03:20:30 +0000 | |||
192 | +++ breezy/grep.py 2019-02-04 01:01:36 +0000 | |||
193 | @@ -1,5 +1,5 @@ | |||
194 | 1 | # Copyright (C) 2010 Canonical Ltd | 1 | # Copyright (C) 2010 Canonical Ltd |
196 | 2 | # | 2 | |
197 | 3 | # This program is free software; you can redistribute it and/or modify | 3 | # This program is free software; you can redistribute it and/or modify |
198 | 4 | # it under the terms of the GNU General Public License as published by | 4 | # it under the terms of the GNU General Public License as published by |
199 | 5 | # the Free Software Foundation; either version 2 of the License, or | 5 | # the Free Software Foundation; either version 2 of the License, or |
200 | @@ -12,36 +12,35 @@ | |||
201 | 12 | # | 12 | # |
202 | 13 | # You should have received a copy of the GNU General Public License | 13 | # You should have received a copy of the GNU General Public License |
203 | 14 | # along with this program; if not, write to the Free Software | 14 | # along with this program; if not, write to the Free Software |
205 | 15 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 15 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
206 | 16 | 16 | ||
207 | 17 | from __future__ import absolute_import | 17 | from __future__ import absolute_import |
208 | 18 | 18 | ||
209 | 19 | import re | 19 | import re |
210 | 20 | 20 | ||
212 | 21 | from ...lazy_import import lazy_import | 21 | from .lazy_import import lazy_import |
213 | 22 | lazy_import(globals(), """ | 22 | lazy_import(globals(), """ |
214 | 23 | from fnmatch import fnmatch | 23 | from fnmatch import fnmatch |
215 | 24 | 24 | ||
216 | 25 | from breezy._termcolor import color_string, FG | 25 | from breezy._termcolor import color_string, FG |
217 | 26 | 26 | ||
218 | 27 | from breezy import ( | 27 | from breezy import ( |
219 | 28 | diff, | ||
220 | 29 | ) | ||
221 | 30 | """) | ||
222 | 31 | from . import ( | ||
223 | 28 | controldir, | 32 | controldir, |
224 | 29 | diff, | ||
225 | 30 | errors, | 33 | errors, |
227 | 31 | lazy_regex, | 34 | osutils, |
228 | 32 | revision as _mod_revision, | 35 | revision as _mod_revision, |
229 | 33 | ) | ||
230 | 34 | """) | ||
231 | 35 | from breezy import ( | ||
232 | 36 | osutils, | ||
233 | 37 | trace, | 36 | trace, |
234 | 38 | ) | 37 | ) |
236 | 39 | from breezy.revisionspec import ( | 38 | from .revisionspec import ( |
237 | 40 | RevisionSpec, | 39 | RevisionSpec, |
238 | 41 | RevisionSpec_revid, | 40 | RevisionSpec_revid, |
239 | 42 | RevisionSpec_revno, | 41 | RevisionSpec_revno, |
240 | 43 | ) | 42 | ) |
242 | 44 | from breezy.sixish import ( | 43 | from .sixish import ( |
243 | 45 | BytesIO, | 44 | BytesIO, |
244 | 46 | ) | 45 | ) |
245 | 47 | 46 | ||
246 | @@ -52,6 +51,42 @@ | |||
247 | 52 | """Raised when a revision is not on left-hand history.""" | 51 | """Raised when a revision is not on left-hand history.""" |
248 | 53 | 52 | ||
249 | 54 | 53 | ||
250 | 54 | class GrepOptions(object): | ||
251 | 55 | """Container to pass around grep options. | ||
252 | 56 | |||
253 | 57 | This class is used as a container to pass around user option and | ||
254 | 58 | some other params (like outf) to processing functions. This makes | ||
255 | 59 | it easier to add more options as grep evolves. | ||
256 | 60 | """ | ||
257 | 61 | verbose = False | ||
258 | 62 | ignore_case = False | ||
259 | 63 | no_recursive = False | ||
260 | 64 | from_root = False | ||
261 | 65 | null = False | ||
262 | 66 | levels = None | ||
263 | 67 | line_number = False | ||
264 | 68 | path_list = None | ||
265 | 69 | revision = None | ||
266 | 70 | pattern = None | ||
267 | 71 | include = None | ||
268 | 72 | exclude = None | ||
269 | 73 | fixed_string = False | ||
270 | 74 | files_with_matches = False | ||
271 | 75 | files_without_match = False | ||
272 | 76 | color = None | ||
273 | 77 | diff = False | ||
274 | 78 | |||
275 | 79 | # derived options | ||
276 | 80 | recursive = None | ||
277 | 81 | eol_marker = None | ||
278 | 82 | patternc = None | ||
279 | 83 | sub_patternc = None | ||
280 | 84 | print_revno = None | ||
281 | 85 | fixed_string = None | ||
282 | 86 | outf = None | ||
283 | 87 | show_color = False | ||
284 | 88 | |||
285 | 89 | |||
286 | 55 | def _rev_on_mainline(rev_tuple): | 90 | def _rev_on_mainline(rev_tuple): |
287 | 56 | """returns True is rev tuple is on mainline""" | 91 | """returns True is rev tuple is on mainline""" |
288 | 57 | if len(rev_tuple) == 1: | 92 | if len(rev_tuple) == 1: |
289 | 58 | 93 | ||
290 | === removed directory 'breezy/plugins/grep' | |||
291 | === removed file 'breezy/plugins/grep/.bzrignore' | |||
292 | --- breezy/plugins/grep/.bzrignore 2010-06-08 03:05:42 +0000 | |||
293 | +++ breezy/plugins/grep/.bzrignore 1970-01-01 00:00:00 +0000 | |||
294 | @@ -1,1 +0,0 @@ | |||
295 | 1 | ./build | ||
296 | 2 | 0 | ||
297 | === removed file 'breezy/plugins/grep/NEWS' | |||
298 | --- breezy/plugins/grep/NEWS 2017-07-30 16:59:50 +0000 | |||
299 | +++ breezy/plugins/grep/NEWS 1970-01-01 00:00:00 +0000 | |||
300 | @@ -1,73 +0,0 @@ | |||
301 | 1 | This is the NEWS file from bzr-grep from before it was merged into bzr core. | ||
302 | 2 | For changes before then, please refer to the main bzr log file. | ||
303 | 3 | |||
304 | 4 | bzr-grep 0.5.0-final - Unreleased | ||
305 | 5 | ================================== | ||
306 | 6 | * ``bzr grep`` now supports ``--diff|-p`` option to search through | ||
307 | 7 | changesets. (Parth Malwankar, #540705) | ||
308 | 8 | |||
309 | 9 | * Option ``grep_color`` can be set in ``breezy.conf`` instead of using | ||
310 | 10 | the option ``--color`` from the command line. (Johan Dahlin) | ||
311 | 11 | |||
312 | 12 | bzr-grep 0.4.0-final - 08-Jun-2010 | ||
313 | 13 | ================================== | ||
314 | 14 | * Add seperate output formatter to reduce duplication of search loops, | ||
315 | 15 | additionally make -Fi use regexp rather than lowercasing pattern and | ||
316 | 16 | entirety of text for the same reason. This also fixes bug #590589 | ||
317 | 17 | - UnicodeDecodeError with options -Fi. (Martin [gz]) | ||
318 | 18 | |||
319 | 19 | * Added fast path for no match that avoids splitting the file text into | ||
320 | 20 | seperate lines and testing each one, by checking the entire text for a | ||
321 | 21 | possible match initially. (Martin [gz]) | ||
322 | 22 | |||
323 | 23 | * Added Makefile. (Parth Malwankar) | ||
324 | 24 | |||
325 | 25 | * Fixed setup.py to work correctly. (Martin [gz]) | ||
326 | 26 | |||
327 | 27 | bzr-grep 0.3.0-final - 23-May-2010 | ||
328 | 28 | ================================== | ||
329 | 29 | * Support for --color option (POSIX only). (Parth Malwankar, #571694) | ||
330 | 30 | |||
331 | 31 | * Revisions in branches without trees can now be searched with | ||
332 | 32 | -r option. (Parth Malwankar, #584240) | ||
333 | 33 | |||
334 | 34 | * Trying to search working tree for a treeless branch no longer | ||
335 | 35 | produces a stack trace but gives an error message suggesting use of | ||
336 | 36 | -r option. (Parth Malwankar, #572658) | ||
337 | 37 | |||
338 | 38 | bzr-grep 0.2.0-final - 30-Mar-2010 | ||
339 | 39 | ================================== | ||
340 | 40 | * 'binary file skipped' warning is not shows without --verbose flag | ||
341 | 41 | (Parth Malwankar, #539031) | ||
342 | 42 | |||
343 | 43 | * Added support for -F/--fixed-string for faster search. | ||
344 | 44 | Simple patterns [a-zA-Z0-9 _] are now implicitly -F and searched faster. | ||
345 | 45 | (Parth Malwankar, #539263) | ||
346 | 46 | |||
347 | 47 | * Better unicode handling. bzr-grep no longer crashes with UnicodeDecode | ||
348 | 48 | error for some outputs. (Parth Malwankar, #539258) | ||
349 | 49 | |||
350 | 50 | * Faster grep for revision range. bzr-grep now caches results for | ||
351 | 51 | files that have not changed between revisions. | ||
352 | 52 | (Parth Malwankar, #542375) | ||
353 | 53 | |||
354 | 54 | * Faster grep for specific revision. (Parth Malwankar, #539429) | ||
355 | 55 | |||
356 | 56 | * Significant performance improvement. Working tree grep for bzr.dev | ||
357 | 57 | has gone from ~7.5s to ~1s. (Parth Malwankar, #539028) | ||
358 | 58 | |||
359 | 59 | * Support for -L/--files-without-match and -l/files-with-matches | ||
360 | 60 | (Parth Malwankar, #540097) | ||
361 | 61 | |||
362 | 62 | bzr-grep 0.1.0-final - 14-Mar-2010 | ||
363 | 63 | ================================== | ||
364 | 64 | * --recursive is now default. (Parth Malwankar, #536688) | ||
365 | 65 | |||
366 | 66 | * ``bzr grep`` searches working copy by default. (Parth Malwankar, #537072) | ||
367 | 67 | |||
368 | 68 | * --include/exclude=GLOB is now supported. (Parth Malwankar, #529889) | ||
369 | 69 | |||
370 | 70 | bzr-grep 0.0.1-final - 10-Mar-2010 | ||
371 | 71 | ================================== | ||
372 | 72 | * Initial release (Parth Malwankar) | ||
373 | 73 | |||
374 | 74 | 0 | ||
375 | === removed file 'breezy/plugins/grep/__init__.py' | |||
376 | --- breezy/plugins/grep/__init__.py 2018-11-11 04:08:32 +0000 | |||
377 | +++ breezy/plugins/grep/__init__.py 1970-01-01 00:00:00 +0000 | |||
378 | @@ -1,38 +0,0 @@ | |||
379 | 1 | # Copyright (C) 2010 Canonical Ltd | ||
380 | 2 | # | ||
381 | 3 | # This program is free software; you can redistribute it and/or modify | ||
382 | 4 | # it under the terms of the GNU General Public License as published by | ||
383 | 5 | # the Free Software Foundation; either version 2 of the License, or | ||
384 | 6 | # (at your option) any later version. | ||
385 | 7 | # | ||
386 | 8 | # This program is distributed in the hope that it will be useful, | ||
387 | 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
388 | 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
389 | 11 | # GNU General Public License for more details. | ||
390 | 12 | # | ||
391 | 13 | # You should have received a copy of the GNU General Public License | ||
392 | 14 | # along with this program; if not, write to the Free Software | ||
393 | 15 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
394 | 16 | |||
395 | 17 | """Print lines matching PATTERN for specified files and revisions.""" | ||
396 | 18 | |||
397 | 19 | from __future__ import absolute_import | ||
398 | 20 | |||
399 | 21 | from ... import version_info # noqa: F401 | ||
400 | 22 | from ...commands import plugin_cmds | ||
401 | 23 | |||
402 | 24 | plugin_cmds.register_lazy("cmd_grep", [], "breezy.plugins.grep.cmds") | ||
403 | 25 | |||
404 | 26 | |||
405 | 27 | def test_suite(): | ||
406 | 28 | from ...tests import TestUtil | ||
407 | 29 | |||
408 | 30 | suite = TestUtil.TestSuite() | ||
409 | 31 | loader = TestUtil.TestLoader() | ||
410 | 32 | testmod_names = [ | ||
411 | 33 | 'test_grep', | ||
412 | 34 | ] | ||
413 | 35 | |||
414 | 36 | suite.addTest(loader.loadTestsFromModuleNames( | ||
415 | 37 | ["%s.%s" % (__name__, tmn) for tmn in testmod_names])) | ||
416 | 38 | return suite | ||
417 | 39 | 0 | ||
418 | === removed file 'breezy/plugins/grep/cmds.py' | |||
419 | --- breezy/plugins/grep/cmds.py 2018-11-17 16:53:10 +0000 | |||
420 | +++ breezy/plugins/grep/cmds.py 1970-01-01 00:00:00 +0000 | |||
421 | @@ -1,254 +0,0 @@ | |||
422 | 1 | # Copyright (C) 2010 Canonical Ltd | ||
423 | 2 | # | ||
424 | 3 | # This program is free software; you can redistribute it and/or modify | ||
425 | 4 | # it under the terms of the GNU General Public License as published by | ||
426 | 5 | # the Free Software Foundation; either version 2 of the License, or | ||
427 | 6 | # (at your option) any later version. | ||
428 | 7 | # | ||
429 | 8 | # This program is distributed in the hope that it will be useful, | ||
430 | 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
431 | 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
432 | 11 | # GNU General Public License for more details. | ||
433 | 12 | # | ||
434 | 13 | # You should have received a copy of the GNU General Public License | ||
435 | 14 | # along with this program; if not, write to the Free Software | ||
436 | 15 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
437 | 16 | |||
438 | 17 | """Print lines matching PATTERN for specified files and revisions.""" | ||
439 | 18 | |||
440 | 19 | from __future__ import absolute_import | ||
441 | 20 | |||
442 | 21 | from ... import errors | ||
443 | 22 | from ...commands import Command, display_command | ||
444 | 23 | from ...option import Option, ListOption | ||
445 | 24 | from ...config import GlobalConfig | ||
446 | 25 | |||
447 | 26 | from ...sixish import ( | ||
448 | 27 | text_type, | ||
449 | 28 | ) | ||
450 | 29 | |||
451 | 30 | # FIXME: _parse_levels should be shared with breezy.builtins. this is a copy | ||
452 | 31 | # to avoid the error | ||
453 | 32 | # "IllegalUseOfScopeReplacer: ScopeReplacer object '_parse_levels' was used | ||
454 | 33 | # incorrectly: Object already cleaned up, did you assign it to another | ||
455 | 34 | # variable?: _factory | ||
456 | 35 | # with lazy import | ||
457 | 36 | |||
458 | 37 | |||
459 | 38 | def _parse_levels(s): | ||
460 | 39 | try: | ||
461 | 40 | return int(s) | ||
462 | 41 | except ValueError: | ||
463 | 42 | msg = "The levels argument must be an integer." | ||
464 | 43 | raise errors.BzrCommandError(msg) | ||
465 | 44 | |||
466 | 45 | |||
467 | 46 | class GrepOptions(object): | ||
468 | 47 | """Container to pass around grep options. | ||
469 | 48 | |||
470 | 49 | This class is used as a container to pass around user option and | ||
471 | 50 | some other params (like outf) to processing functions. This makes | ||
472 | 51 | it easier to add more options as grep evolves. | ||
473 | 52 | """ | ||
474 | 53 | verbose = False | ||
475 | 54 | ignore_case = False | ||
476 | 55 | no_recursive = False | ||
477 | 56 | from_root = False | ||
478 | 57 | null = False | ||
479 | 58 | levels = None | ||
480 | 59 | line_number = False | ||
481 | 60 | path_list = None | ||
482 | 61 | revision = None | ||
483 | 62 | pattern = None | ||
484 | 63 | include = None | ||
485 | 64 | exclude = None | ||
486 | 65 | fixed_string = False | ||
487 | 66 | files_with_matches = False | ||
488 | 67 | files_without_match = False | ||
489 | 68 | color = None | ||
490 | 69 | diff = False | ||
491 | 70 | |||
492 | 71 | # derived options | ||
493 | 72 | recursive = None | ||
494 | 73 | eol_marker = None | ||
495 | 74 | patternc = None | ||
496 | 75 | sub_patternc = None | ||
497 | 76 | print_revno = None | ||
498 | 77 | fixed_string = None | ||
499 | 78 | outf = None | ||
500 | 79 | show_color = False | ||
501 | 80 | |||
502 | 81 | |||
503 | 82 | class cmd_grep(Command): | ||
504 | 83 | """Print lines matching PATTERN for specified files and revisions. | ||
505 | 84 | |||
506 | 85 | This command searches the specified files and revisions for a given | ||
507 | 86 | pattern. The pattern is specified as a Python regular expressions[1]. | ||
508 | 87 | |||
509 | 88 | If the file name is not specified, the revisions starting with the | ||
510 | 89 | current directory are searched recursively. If the revision number is | ||
511 | 90 | not specified, the working copy is searched. To search the last committed | ||
512 | 91 | revision, use the '-r -1' or '-r last:1' option. | ||
513 | 92 | |||
514 | 93 | Unversioned files are not searched unless explicitly specified on the | ||
515 | 94 | command line. Unversioned directores are not searched. | ||
516 | 95 | |||
517 | 96 | When searching a pattern, the output is shown in the 'filepath:string' | ||
518 | 97 | format. If a revision is explicitly searched, the output is shown as | ||
519 | 98 | 'filepath~N:string', where N is the revision number. | ||
520 | 99 | |||
521 | 100 | --include and --exclude options can be used to search only (or exclude | ||
522 | 101 | from search) files with base name matches the specified Unix style GLOB | ||
523 | 102 | pattern. The GLOB pattern an use *, ?, and [...] as wildcards, and \\ | ||
524 | 103 | to quote wildcard or backslash character literally. Note that the glob | ||
525 | 104 | pattern is not a regular expression. | ||
526 | 105 | |||
527 | 106 | [1] http://docs.python.org/library/re.html#regular-expression-syntax | ||
528 | 107 | """ | ||
529 | 108 | |||
530 | 109 | encoding_type = 'replace' | ||
531 | 110 | takes_args = ['pattern', 'path*'] | ||
532 | 111 | takes_options = [ | ||
533 | 112 | 'verbose', | ||
534 | 113 | 'revision', | ||
535 | 114 | Option('color', type=text_type, argname='when', | ||
536 | 115 | help='Show match in color. WHEN is never, always or auto.'), | ||
537 | 116 | Option('diff', short_name='p', | ||
538 | 117 | help='Grep for pattern in changeset for each revision.'), | ||
539 | 118 | ListOption('exclude', type=text_type, argname='glob', short_name='X', | ||
540 | 119 | help="Skip files whose base name matches GLOB."), | ||
541 | 120 | ListOption('include', type=text_type, argname='glob', short_name='I', | ||
542 | 121 | help="Search only files whose base name matches GLOB."), | ||
543 | 122 | Option('files-with-matches', short_name='l', | ||
544 | 123 | help='Print only the name of each input file in ' | ||
545 | 124 | 'which PATTERN is found.'), | ||
546 | 125 | Option('files-without-match', short_name='L', | ||
547 | 126 | help='Print only the name of each input file in ' | ||
548 | 127 | 'which PATTERN is not found.'), | ||
549 | 128 | Option('fixed-string', short_name='F', | ||
550 | 129 | help='Interpret PATTERN is a single fixed string (not regex).'), | ||
551 | 130 | Option('from-root', | ||
552 | 131 | help='Search for pattern starting from the root of the branch. ' | ||
553 | 132 | '(implies --recursive)'), | ||
554 | 133 | Option('ignore-case', short_name='i', | ||
555 | 134 | help='ignore case distinctions while matching.'), | ||
556 | 135 | Option('levels', | ||
557 | 136 | help='Number of levels to display - 0 for all, 1 for collapsed ' | ||
558 | 137 | '(1 is default).', | ||
559 | 138 | argname='N', | ||
560 | 139 | type=_parse_levels), | ||
561 | 140 | Option('line-number', short_name='n', | ||
562 | 141 | help='show 1-based line number.'), | ||
563 | 142 | Option('no-recursive', | ||
564 | 143 | help="Don't recurse into subdirectories. (default is --recursive)"), | ||
565 | 144 | Option('null', short_name='Z', | ||
566 | 145 | help='Write an ASCII NUL (\\0) separator ' | ||
567 | 146 | 'between output lines rather than a newline.'), | ||
568 | 147 | ] | ||
569 | 148 | |||
570 | 149 | @display_command | ||
571 | 150 | def run(self, verbose=False, ignore_case=False, no_recursive=False, | ||
572 | 151 | from_root=False, null=False, levels=None, line_number=False, | ||
573 | 152 | path_list=None, revision=None, pattern=None, include=None, | ||
574 | 153 | exclude=None, fixed_string=False, files_with_matches=False, | ||
575 | 154 | files_without_match=False, color=None, diff=False): | ||
576 | 155 | from breezy import _termcolor | ||
577 | 156 | from . import grep | ||
578 | 157 | import re | ||
579 | 158 | if path_list is None: | ||
580 | 159 | path_list = ['.'] | ||
581 | 160 | else: | ||
582 | 161 | if from_root: | ||
583 | 162 | raise errors.BzrCommandError( | ||
584 | 163 | 'cannot specify both --from-root and PATH.') | ||
585 | 164 | |||
586 | 165 | if files_with_matches and files_without_match: | ||
587 | 166 | raise errors.BzrCommandError('cannot specify both ' | ||
588 | 167 | '-l/--files-with-matches and -L/--files-without-matches.') | ||
589 | 168 | |||
590 | 169 | global_config = GlobalConfig() | ||
591 | 170 | |||
592 | 171 | if color is None: | ||
593 | 172 | color = global_config.get_user_option('grep_color') | ||
594 | 173 | |||
595 | 174 | if color is None: | ||
596 | 175 | color = 'never' | ||
597 | 176 | |||
598 | 177 | if color not in ['always', 'never', 'auto']: | ||
599 | 178 | raise errors.BzrCommandError('Valid values for --color are ' | ||
600 | 179 | '"always", "never" or "auto".') | ||
601 | 180 | |||
602 | 181 | if levels is None: | ||
603 | 182 | levels = 1 | ||
604 | 183 | |||
605 | 184 | print_revno = False | ||
606 | 185 | if revision is not None or levels == 0: | ||
607 | 186 | # print revision numbers as we may be showing multiple revisions | ||
608 | 187 | print_revno = True | ||
609 | 188 | |||
610 | 189 | eol_marker = '\n' | ||
611 | 190 | if null: | ||
612 | 191 | eol_marker = '\0' | ||
613 | 192 | |||
614 | 193 | if not ignore_case and grep.is_fixed_string(pattern): | ||
615 | 194 | # if the pattern isalnum, implicitly use to -F for faster grep | ||
616 | 195 | fixed_string = True | ||
617 | 196 | elif ignore_case and fixed_string: | ||
618 | 197 | # GZ 2010-06-02: Fall back to regexp rather than lowercasing | ||
619 | 198 | # pattern and text which will cause pain later | ||
620 | 199 | fixed_string = False | ||
621 | 200 | pattern = re.escape(pattern) | ||
622 | 201 | |||
623 | 202 | patternc = None | ||
624 | 203 | re_flags = re.MULTILINE | ||
625 | 204 | if ignore_case: | ||
626 | 205 | re_flags |= re.IGNORECASE | ||
627 | 206 | |||
628 | 207 | if not fixed_string: | ||
629 | 208 | patternc = grep.compile_pattern( | ||
630 | 209 | pattern.encode(grep._user_encoding), re_flags) | ||
631 | 210 | |||
632 | 211 | if color == 'always': | ||
633 | 212 | show_color = True | ||
634 | 213 | elif color == 'never': | ||
635 | 214 | show_color = False | ||
636 | 215 | elif color == 'auto': | ||
637 | 216 | show_color = _termcolor.allow_color() | ||
638 | 217 | |||
639 | 218 | GrepOptions.verbose = verbose | ||
640 | 219 | GrepOptions.ignore_case = ignore_case | ||
641 | 220 | GrepOptions.no_recursive = no_recursive | ||
642 | 221 | GrepOptions.from_root = from_root | ||
643 | 222 | GrepOptions.null = null | ||
644 | 223 | GrepOptions.levels = levels | ||
645 | 224 | GrepOptions.line_number = line_number | ||
646 | 225 | GrepOptions.path_list = path_list | ||
647 | 226 | GrepOptions.revision = revision | ||
648 | 227 | GrepOptions.pattern = pattern | ||
649 | 228 | GrepOptions.include = include | ||
650 | 229 | GrepOptions.exclude = exclude | ||
651 | 230 | GrepOptions.fixed_string = fixed_string | ||
652 | 231 | GrepOptions.files_with_matches = files_with_matches | ||
653 | 232 | GrepOptions.files_without_match = files_without_match | ||
654 | 233 | GrepOptions.color = color | ||
655 | 234 | GrepOptions.diff = False | ||
656 | 235 | |||
657 | 236 | GrepOptions.eol_marker = eol_marker | ||
658 | 237 | GrepOptions.print_revno = print_revno | ||
659 | 238 | GrepOptions.patternc = patternc | ||
660 | 239 | GrepOptions.recursive = not no_recursive | ||
661 | 240 | GrepOptions.fixed_string = fixed_string | ||
662 | 241 | GrepOptions.outf = self.outf | ||
663 | 242 | GrepOptions.show_color = show_color | ||
664 | 243 | |||
665 | 244 | if diff: | ||
666 | 245 | # options not used: | ||
667 | 246 | # files_with_matches, files_without_match | ||
668 | 247 | # levels(?), line_number, from_root | ||
669 | 248 | # include, exclude | ||
670 | 249 | # These are silently ignored. | ||
671 | 250 | grep.grep_diff(GrepOptions) | ||
672 | 251 | elif revision is None: | ||
673 | 252 | grep.workingtree_grep(GrepOptions) | ||
674 | 253 | else: | ||
675 | 254 | grep.versioned_grep(GrepOptions) | ||
676 | 255 | 0 | ||
677 | === modified file 'breezy/tests/__init__.py' | |||
678 | --- breezy/tests/__init__.py 2018-11-23 23:51:34 +0000 | |||
679 | +++ breezy/tests/__init__.py 2019-02-04 01:01:36 +0000 | |||
680 | @@ -4107,6 +4107,7 @@ | |||
681 | 4107 | 'breezy.tests.test_globbing', | 4107 | 'breezy.tests.test_globbing', |
682 | 4108 | 'breezy.tests.test_gpg', | 4108 | 'breezy.tests.test_gpg', |
683 | 4109 | 'breezy.tests.test_graph', | 4109 | 'breezy.tests.test_graph', |
684 | 4110 | 'breezy.tests.test_grep', | ||
685 | 4110 | 'breezy.tests.test_groupcompress', | 4111 | 'breezy.tests.test_groupcompress', |
686 | 4111 | 'breezy.tests.test_hashcache', | 4112 | 'breezy.tests.test_hashcache', |
687 | 4112 | 'breezy.tests.test_help', | 4113 | 'breezy.tests.test_help', |
688 | 4113 | 4114 | ||
689 | === renamed file 'breezy/plugins/grep/test_grep.py' => 'breezy/tests/test_grep.py' | |||
690 | --- breezy/plugins/grep/test_grep.py 2018-11-12 01:41:38 +0000 | |||
691 | +++ breezy/tests/test_grep.py 2019-02-04 01:01:36 +0000 | |||
692 | @@ -12,7 +12,7 @@ | |||
693 | 12 | # | 12 | # |
694 | 13 | # You should have received a copy of the GNU General Public License | 13 | # You should have received a copy of the GNU General Public License |
695 | 14 | # along with this program; if not, write to the Free Software | 14 | # along with this program; if not, write to the Free Software |
697 | 15 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 15 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
698 | 16 | 16 | ||
699 | 17 | from __future__ import absolute_import | 17 | from __future__ import absolute_import |
700 | 18 | 18 | ||
701 | @@ -20,11 +20,11 @@ | |||
702 | 20 | import re | 20 | import re |
703 | 21 | import unicodedata as ud | 21 | import unicodedata as ud |
704 | 22 | 22 | ||
708 | 23 | from ... import tests, osutils | 23 | from .. import tests, osutils |
709 | 24 | from ...sixish import PY3 | 24 | from ..sixish import PY3 |
710 | 25 | from ..._termcolor import color_string, FG | 25 | from .._termcolor import color_string, FG |
711 | 26 | 26 | ||
713 | 27 | from ...tests.features import ( | 27 | from ..tests.features import ( |
714 | 28 | UnicodeFilenameFeature, | 28 | UnicodeFilenameFeature, |
715 | 29 | ) | 29 | ) |
716 | 30 | 30 | ||
717 | @@ -2429,13 +2429,13 @@ | |||
718 | 2429 | self.assertEqualDiff(subst_dates(out), '''\ | 2429 | self.assertEqualDiff(subst_dates(out), '''\ |
719 | 2430 | === revno:3 === | 2430 | === revno:3 === |
720 | 2431 | === modified file 'hello' | 2431 | === modified file 'hello' |
723 | 2432 | --- hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2432 | --- hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
724 | 2433 | +++ hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2433 | +++ hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
725 | 2434 | +hello world! | 2434 | +hello world! |
726 | 2435 | === revno:1 === | 2435 | === revno:1 === |
727 | 2436 | === added file 'hello' | 2436 | === added file 'hello' |
730 | 2437 | --- hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2437 | --- hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
731 | 2438 | +++ hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2438 | +++ hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
732 | 2439 | ''') | 2439 | ''') |
733 | 2440 | 2440 | ||
734 | 2441 | def test_grep_diff_revision(self): | 2441 | def test_grep_diff_revision(self): |
735 | @@ -2448,8 +2448,8 @@ | |||
736 | 2448 | self.assertEqualDiff(subst_dates(out), '''\ | 2448 | self.assertEqualDiff(subst_dates(out), '''\ |
737 | 2449 | === revno:3 === | 2449 | === revno:3 === |
738 | 2450 | === modified file 'hello' | 2450 | === modified file 'hello' |
741 | 2451 | --- hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2451 | --- hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
742 | 2452 | +++ hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2452 | +++ hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
743 | 2453 | +hello world! | 2453 | +hello world! |
744 | 2454 | ''') | 2454 | ''') |
745 | 2455 | 2455 | ||
746 | @@ -2470,16 +2470,16 @@ | |||
747 | 2470 | self.assertEqualDiff(subst_dates(out), '''\ | 2470 | self.assertEqualDiff(subst_dates(out), '''\ |
748 | 2471 | === revno:5 === | 2471 | === revno:5 === |
749 | 2472 | === modified file 'hello' | 2472 | === modified file 'hello' |
752 | 2473 | --- hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2473 | --- hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
753 | 2474 | +++ hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2474 | +++ hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
754 | 2475 | +hello world!3 | 2475 | +hello world!3 |
755 | 2476 | === revno:4 === | 2476 | === revno:4 === |
756 | 2477 | === added file 'blah' | 2477 | === added file 'blah' |
757 | 2478 | +hello world!2 | 2478 | +hello world!2 |
758 | 2479 | === revno:3 === | 2479 | === revno:3 === |
759 | 2480 | === modified file 'hello' | 2480 | === modified file 'hello' |
762 | 2481 | --- hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2481 | --- hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
763 | 2482 | +++ hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2482 | +++ hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
764 | 2483 | +hello world!1 | 2483 | +hello world!1 |
765 | 2484 | ''') | 2484 | ''') |
766 | 2485 | 2485 | ||
767 | @@ -2496,8 +2496,8 @@ | |||
768 | 2496 | " === modified file 'hello'", fg=FG.BOLD_MAGENTA) + '\n' | 2496 | " === modified file 'hello'", fg=FG.BOLD_MAGENTA) + '\n' |
769 | 2497 | redhello = color_string('hello', fg=FG.BOLD_RED) | 2497 | redhello = color_string('hello', fg=FG.BOLD_RED) |
770 | 2498 | diffstr = '''\ | 2498 | diffstr = '''\ |
773 | 2499 | --- hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2499 | --- hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
774 | 2500 | +++ hello YYYY-MM-DD HH:MM:SS +ZZZZ | 2500 | +++ hello\tYYYY-MM-DD HH:MM:SS +ZZZZ |
775 | 2501 | +hello world! | 2501 | +hello world! |
776 | 2502 | ''' | 2502 | ''' |
777 | 2503 | diffstr = diffstr.replace('hello', redhello) | 2503 | diffstr = diffstr.replace('hello', redhello) |
778 | 2504 | 2504 | ||
779 | === modified file 'doc/en/release-notes/brz-3.0.txt' | |||
780 | --- doc/en/release-notes/brz-3.0.txt 2019-02-02 22:23:40 +0000 | |||
781 | +++ doc/en/release-notes/brz-3.0.txt 2019-02-04 01:01:36 +0000 | |||
782 | @@ -93,6 +93,9 @@ | |||
783 | 93 | * The 'fastimport' plugin is now bundled with Breezy. | 93 | * The 'fastimport' plugin is now bundled with Breezy. |
784 | 94 | (Jelmer Vernooij) | 94 | (Jelmer Vernooij) |
785 | 95 | 95 | ||
786 | 96 | * The ``grep`` plugin has been merged into Breezy. | ||
787 | 97 | (Parth Malwankar, Martin Packman, Jelmer Vernooij) | ||
788 | 98 | |||
789 | 96 | * The 'stats' plugin is now bundled with Breezy. | 99 | * The 'stats' plugin is now bundled with Breezy. |
790 | 97 | (Jelmer Vernooij) | 100 | (Jelmer Vernooij) |
791 | 98 | 101 |
Thanks, I think is a good thing to do.