blob: a588a78e6c5b3a4c15d3fa7b1fed24b91728f140 [file] [log] [blame]
Mike Frysingerf6013762019-06-13 02:30:51 -04001# -*- coding:utf-8 -*-
Shawn O. Pearceb812a362009-04-10 20:37:47 -07002#
3# Copyright (C) 2009 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
Sarah Owenscecd1d82012-11-01 22:59:27 -070017from __future__ import print_function
Shawn O. Pearceb812a362009-04-10 20:37:47 -070018import sys
Shawn O. Pearceb812a362009-04-10 20:37:47 -070019from color import Coloring
20from command import PagedCommand
Shawn O. Pearcef0d4c362009-06-12 09:33:48 -070021from git_command import git_require, GitCommand
Shawn O. Pearceb812a362009-04-10 20:37:47 -070022
23class GrepColoring(Coloring):
24 def __init__(self, config):
25 Coloring.__init__(self, config, 'grep')
26 self.project = self.printer('project', attr='bold')
27
28class Grep(PagedCommand):
29 common = True
30 helpSummary = "Print lines matching a pattern"
31 helpUsage = """
32%prog {pattern | -e pattern} [<project>...]
33"""
34 helpDescription = """
35Search for the specified patterns in all project files.
36
Mike Frysingerb8f7bb02018-10-10 01:05:11 -040037# Boolean Options
Shawn O. Pearceb812a362009-04-10 20:37:47 -070038
39The following options can appear as often as necessary to express
40the pattern to locate:
41
42 -e PATTERN
43 --and, --or, --not, -(, -)
44
45Further, the -r/--revision option may be specified multiple times
46in order to scan multiple trees. If the same file matches in more
47than one tree, only the first result is reported, prefixed by the
48revision name it was found under.
49
Mike Frysingerb8f7bb02018-10-10 01:05:11 -040050# Examples
Shawn O. Pearceb812a362009-04-10 20:37:47 -070051
52Look for a line that has '#define' and either 'MAX_PATH or 'PATH_MAX':
53
David Pursehouse1d947b32012-10-25 12:23:11 +090054 repo grep -e '#define' --and -\\( -e MAX_PATH -e PATH_MAX \\)
Shawn O. Pearceb812a362009-04-10 20:37:47 -070055
56Look for a line that has 'NODE' or 'Unexpected' in files that
57contain a line that matches both expressions:
58
59 repo grep --all-match -e NODE -e Unexpected
60
61"""
62
63 def _Options(self, p):
64 def carry(option,
65 opt_str,
66 value,
67 parser):
68 pt = getattr(parser.values, 'cmd_argv', None)
69 if pt is None:
70 pt = []
71 setattr(parser.values, 'cmd_argv', pt)
72
73 if opt_str == '-(':
74 pt.append('(')
75 elif opt_str == '-)':
76 pt.append(')')
77 else:
78 pt.append(opt_str)
79
80 if value is not None:
81 pt.append(value)
82
83 g = p.add_option_group('Sources')
84 g.add_option('--cached',
85 action='callback', callback=carry,
86 help='Search the index, instead of the work tree')
David Pursehouse8f62fb72012-11-14 12:09:38 +090087 g.add_option('-r', '--revision',
Shawn O. Pearceb812a362009-04-10 20:37:47 -070088 dest='revision', action='append', metavar='TREEish',
89 help='Search TREEish, instead of the work tree')
90
91 g = p.add_option_group('Pattern')
92 g.add_option('-e',
93 action='callback', callback=carry,
94 metavar='PATTERN', type='str',
95 help='Pattern to search for')
96 g.add_option('-i', '--ignore-case',
97 action='callback', callback=carry,
98 help='Ignore case differences')
David Pursehouse8f62fb72012-11-14 12:09:38 +090099 g.add_option('-a', '--text',
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700100 action='callback', callback=carry,
101 help="Process binary files as if they were text")
102 g.add_option('-I',
103 action='callback', callback=carry,
104 help="Don't match the pattern in binary files")
105 g.add_option('-w', '--word-regexp',
106 action='callback', callback=carry,
107 help='Match the pattern only at word boundaries')
108 g.add_option('-v', '--invert-match',
109 action='callback', callback=carry,
110 help='Select non-matching lines')
111 g.add_option('-G', '--basic-regexp',
112 action='callback', callback=carry,
113 help='Use POSIX basic regexp for patterns (default)')
114 g.add_option('-E', '--extended-regexp',
115 action='callback', callback=carry,
116 help='Use POSIX extended regexp for patterns')
117 g.add_option('-F', '--fixed-strings',
118 action='callback', callback=carry,
119 help='Use fixed strings (not regexp) for pattern')
120
121 g = p.add_option_group('Pattern Grouping')
122 g.add_option('--all-match',
123 action='callback', callback=carry,
124 help='Limit match to lines that have all patterns')
125 g.add_option('--and', '--or', '--not',
126 action='callback', callback=carry,
127 help='Boolean operators to combine patterns')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900128 g.add_option('-(', '-)',
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700129 action='callback', callback=carry,
130 help='Boolean operator grouping')
131
132 g = p.add_option_group('Output')
133 g.add_option('-n',
134 action='callback', callback=carry,
135 help='Prefix the line number to matching lines')
136 g.add_option('-C',
137 action='callback', callback=carry,
138 metavar='CONTEXT', type='str',
139 help='Show CONTEXT lines around match')
140 g.add_option('-B',
141 action='callback', callback=carry,
142 metavar='CONTEXT', type='str',
143 help='Show CONTEXT lines before match')
144 g.add_option('-A',
145 action='callback', callback=carry,
146 metavar='CONTEXT', type='str',
147 help='Show CONTEXT lines after match')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900148 g.add_option('-l', '--name-only', '--files-with-matches',
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700149 action='callback', callback=carry,
150 help='Show only file names containing matching lines')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900151 g.add_option('-L', '--files-without-match',
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700152 action='callback', callback=carry,
153 help='Show only file names not containing matching lines')
154
155
156 def Execute(self, opt, args):
157 out = GrepColoring(self.manifest.manifestProject.config)
158
159 cmd_argv = ['grep']
David Pursehouse8f62fb72012-11-14 12:09:38 +0900160 if out.is_on and git_require((1, 6, 3)):
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700161 cmd_argv.append('--color')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900162 cmd_argv.extend(getattr(opt, 'cmd_argv', []))
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700163
164 if '-e' not in cmd_argv:
165 if not args:
166 self.Usage()
167 cmd_argv.append('-e')
168 cmd_argv.append(args[0])
169 args = args[1:]
170
171 projects = self.GetProjects(args)
172
173 full_name = False
174 if len(projects) > 1:
175 cmd_argv.append('--full-name')
176 full_name = True
177
178 have_rev = False
179 if opt.revision:
180 if '--cached' in cmd_argv:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700181 print('fatal: cannot combine --cached and --revision', file=sys.stderr)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700182 sys.exit(1)
183 have_rev = True
184 cmd_argv.extend(opt.revision)
185 cmd_argv.append('--')
186
187 bad_rev = False
188 have_match = False
189
190 for project in projects:
191 p = GitCommand(project,
192 cmd_argv,
193 bare = False,
194 capture_stdout = True,
195 capture_stderr = True)
196 if p.Wait() != 0:
197 # no results
198 #
199 if p.stderr:
200 if have_rev and 'fatal: ambiguous argument' in p.stderr:
201 bad_rev = True
202 else:
203 out.project('--- project %s ---' % project.relpath)
204 out.nl()
Sebastian Schmidtfeb39d62010-06-02 17:18:13 +0200205 out.write("%s", p.stderr)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700206 out.nl()
207 continue
208 have_match = True
209
210 # We cut the last element, to avoid a blank line.
211 #
212 r = p.stdout.split('\n')
213 r = r[0:-1]
214
215 if have_rev and full_name:
216 for line in r:
217 rev, line = line.split(':', 1)
Sebastian Schmidtfeb39d62010-06-02 17:18:13 +0200218 out.write("%s", rev)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700219 out.write(':')
220 out.project(project.relpath)
221 out.write('/')
Sebastian Schmidtfeb39d62010-06-02 17:18:13 +0200222 out.write("%s", line)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700223 out.nl()
224 elif full_name:
225 for line in r:
226 out.project(project.relpath)
227 out.write('/')
Sebastian Schmidtfeb39d62010-06-02 17:18:13 +0200228 out.write("%s", line)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700229 out.nl()
230 else:
231 for line in r:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700232 print(line)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700233
234 if have_match:
235 sys.exit(0)
236 elif have_rev and bad_rev:
237 for r in opt.revision:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700238 print("error: can't search revision %s" % r, file=sys.stderr)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700239 sys.exit(1)
240 else:
241 sys.exit(1)