blob: dd391cfa4f96489e28f1a390a7cc42c817b20b06 [file] [log] [blame]
Shawn O. Pearceb812a362009-04-10 20:37:47 -07001#
2# Copyright (C) 2009 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
Sarah Owenscecd1d82012-11-01 22:59:27 -070016from __future__ import print_function
Shawn O. Pearceb812a362009-04-10 20:37:47 -070017import sys
Shawn O. Pearceb812a362009-04-10 20:37:47 -070018from color import Coloring
19from command import PagedCommand
Shawn O. Pearcef0d4c362009-06-12 09:33:48 -070020from git_command import git_require, GitCommand
Shawn O. Pearceb812a362009-04-10 20:37:47 -070021
22class GrepColoring(Coloring):
23 def __init__(self, config):
24 Coloring.__init__(self, config, 'grep')
25 self.project = self.printer('project', attr='bold')
26
27class Grep(PagedCommand):
28 common = True
29 helpSummary = "Print lines matching a pattern"
30 helpUsage = """
31%prog {pattern | -e pattern} [<project>...]
32"""
33 helpDescription = """
34Search for the specified patterns in all project files.
35
Shawn O. Pearce50fa1ac2009-04-18 11:44:33 -070036Boolean Options
37---------------
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
50Examples
51-------
52
53Look for a line that has '#define' and either 'MAX_PATH or 'PATH_MAX':
54
David Pursehouse1d947b32012-10-25 12:23:11 +090055 repo grep -e '#define' --and -\\( -e MAX_PATH -e PATH_MAX \\)
Shawn O. Pearceb812a362009-04-10 20:37:47 -070056
57Look for a line that has 'NODE' or 'Unexpected' in files that
58contain a line that matches both expressions:
59
60 repo grep --all-match -e NODE -e Unexpected
61
62"""
63
64 def _Options(self, p):
65 def carry(option,
66 opt_str,
67 value,
68 parser):
69 pt = getattr(parser.values, 'cmd_argv', None)
70 if pt is None:
71 pt = []
72 setattr(parser.values, 'cmd_argv', pt)
73
74 if opt_str == '-(':
75 pt.append('(')
76 elif opt_str == '-)':
77 pt.append(')')
78 else:
79 pt.append(opt_str)
80
81 if value is not None:
82 pt.append(value)
83
84 g = p.add_option_group('Sources')
85 g.add_option('--cached',
86 action='callback', callback=carry,
87 help='Search the index, instead of the work tree')
David Pursehouse8f62fb72012-11-14 12:09:38 +090088 g.add_option('-r', '--revision',
Shawn O. Pearceb812a362009-04-10 20:37:47 -070089 dest='revision', action='append', metavar='TREEish',
90 help='Search TREEish, instead of the work tree')
91
92 g = p.add_option_group('Pattern')
93 g.add_option('-e',
94 action='callback', callback=carry,
95 metavar='PATTERN', type='str',
96 help='Pattern to search for')
97 g.add_option('-i', '--ignore-case',
98 action='callback', callback=carry,
99 help='Ignore case differences')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900100 g.add_option('-a', '--text',
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700101 action='callback', callback=carry,
102 help="Process binary files as if they were text")
103 g.add_option('-I',
104 action='callback', callback=carry,
105 help="Don't match the pattern in binary files")
106 g.add_option('-w', '--word-regexp',
107 action='callback', callback=carry,
108 help='Match the pattern only at word boundaries')
109 g.add_option('-v', '--invert-match',
110 action='callback', callback=carry,
111 help='Select non-matching lines')
112 g.add_option('-G', '--basic-regexp',
113 action='callback', callback=carry,
114 help='Use POSIX basic regexp for patterns (default)')
115 g.add_option('-E', '--extended-regexp',
116 action='callback', callback=carry,
117 help='Use POSIX extended regexp for patterns')
118 g.add_option('-F', '--fixed-strings',
119 action='callback', callback=carry,
120 help='Use fixed strings (not regexp) for pattern')
121
122 g = p.add_option_group('Pattern Grouping')
123 g.add_option('--all-match',
124 action='callback', callback=carry,
125 help='Limit match to lines that have all patterns')
126 g.add_option('--and', '--or', '--not',
127 action='callback', callback=carry,
128 help='Boolean operators to combine patterns')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900129 g.add_option('-(', '-)',
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700130 action='callback', callback=carry,
131 help='Boolean operator grouping')
132
133 g = p.add_option_group('Output')
134 g.add_option('-n',
135 action='callback', callback=carry,
136 help='Prefix the line number to matching lines')
137 g.add_option('-C',
138 action='callback', callback=carry,
139 metavar='CONTEXT', type='str',
140 help='Show CONTEXT lines around match')
141 g.add_option('-B',
142 action='callback', callback=carry,
143 metavar='CONTEXT', type='str',
144 help='Show CONTEXT lines before match')
145 g.add_option('-A',
146 action='callback', callback=carry,
147 metavar='CONTEXT', type='str',
148 help='Show CONTEXT lines after match')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900149 g.add_option('-l', '--name-only', '--files-with-matches',
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700150 action='callback', callback=carry,
151 help='Show only file names containing matching lines')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900152 g.add_option('-L', '--files-without-match',
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700153 action='callback', callback=carry,
154 help='Show only file names not containing matching lines')
155
156
157 def Execute(self, opt, args):
158 out = GrepColoring(self.manifest.manifestProject.config)
159
160 cmd_argv = ['grep']
David Pursehouse8f62fb72012-11-14 12:09:38 +0900161 if out.is_on and git_require((1, 6, 3)):
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700162 cmd_argv.append('--color')
David Pursehouse8f62fb72012-11-14 12:09:38 +0900163 cmd_argv.extend(getattr(opt, 'cmd_argv', []))
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700164
165 if '-e' not in cmd_argv:
166 if not args:
167 self.Usage()
168 cmd_argv.append('-e')
169 cmd_argv.append(args[0])
170 args = args[1:]
171
172 projects = self.GetProjects(args)
173
174 full_name = False
175 if len(projects) > 1:
176 cmd_argv.append('--full-name')
177 full_name = True
178
179 have_rev = False
180 if opt.revision:
181 if '--cached' in cmd_argv:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700182 print('fatal: cannot combine --cached and --revision', file=sys.stderr)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700183 sys.exit(1)
184 have_rev = True
185 cmd_argv.extend(opt.revision)
186 cmd_argv.append('--')
187
188 bad_rev = False
189 have_match = False
190
191 for project in projects:
192 p = GitCommand(project,
193 cmd_argv,
194 bare = False,
195 capture_stdout = True,
196 capture_stderr = True)
197 if p.Wait() != 0:
198 # no results
199 #
200 if p.stderr:
201 if have_rev and 'fatal: ambiguous argument' in p.stderr:
202 bad_rev = True
203 else:
204 out.project('--- project %s ---' % project.relpath)
205 out.nl()
Sebastian Schmidtfeb39d62010-06-02 17:18:13 +0200206 out.write("%s", p.stderr)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700207 out.nl()
208 continue
209 have_match = True
210
211 # We cut the last element, to avoid a blank line.
212 #
213 r = p.stdout.split('\n')
214 r = r[0:-1]
215
216 if have_rev and full_name:
217 for line in r:
218 rev, line = line.split(':', 1)
Sebastian Schmidtfeb39d62010-06-02 17:18:13 +0200219 out.write("%s", rev)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700220 out.write(':')
221 out.project(project.relpath)
222 out.write('/')
Sebastian Schmidtfeb39d62010-06-02 17:18:13 +0200223 out.write("%s", line)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700224 out.nl()
225 elif full_name:
226 for line in r:
227 out.project(project.relpath)
228 out.write('/')
Sebastian Schmidtfeb39d62010-06-02 17:18:13 +0200229 out.write("%s", line)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700230 out.nl()
231 else:
232 for line in r:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700233 print(line)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700234
235 if have_match:
236 sys.exit(0)
237 elif have_rev and bad_rev:
238 for r in opt.revision:
Sarah Owenscecd1d82012-11-01 22:59:27 -0700239 print("error: can't search revision %s" % r, file=sys.stderr)
Shawn O. Pearceb812a362009-04-10 20:37:47 -0700240 sys.exit(1)
241 else:
242 sys.exit(1)