Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(350)

Side by Side Diff: tools/git/mffr.py

Issue 17527004: Augment mffr.py to be able to take arguments from a file. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Response to review Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Usage: mffr.py [-d] [-g *.h] [-g *.cc] REGEXP REPLACEMENT 6 """Usage: mffr.py [-d] [-g *.h] [-g *.cc] REGEXP REPLACEMENT
7 7
8 This tool performs a fast find-and-replace operation on files in 8 This tool performs a fast find-and-replace operation on files in
9 the current git repository. 9 the current git repository.
10 10
11 The -d flag selects a default set of globs (C++ and Objective-C/C++ 11 The -d flag selects a default set of globs (C++ and Objective-C/C++
12 source files). The -g flag adds a single glob to the list and may 12 source files). The -g flag adds a single glob to the list and may
13 be used multiple times. If neither -d nor -g is specified, the tool 13 be used multiple times. If neither -d nor -g is specified, the tool
14 searches all files (*.*). 14 searches all files (*.*).
15 15
16 REGEXP uses full Python regexp syntax. REPLACEMENT can use 16 REGEXP uses full Python regexp syntax. REPLACEMENT can use
17 back-references. 17 back-references.
18 """ 18 """
19 19
20 import optparse
20 import re 21 import re
21 import subprocess 22 import subprocess
22 import sys 23 import sys
23 24
24 25
25 # We need to use shell=True with subprocess on Windows so that it 26 # We need to use shell=True with subprocess on Windows so that it
26 # finds 'git' from the path, but can lead to undesired behavior on 27 # finds 'git' from the path, but can lead to undesired behavior on
27 # Linux. 28 # Linux.
28 _USE_SHELL = (sys.platform == 'win32') 29 _USE_SHELL = (sys.platform == 'win32')
29 30
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 if contents == original_contents: 67 if contents == original_contents:
67 raise Exception('No change in file %s although matched in grep' % 68 raise Exception('No change in file %s although matched in grep' %
68 referee) 69 referee)
69 with open(referee, 'wb') as f: 70 with open(referee, 'wb') as f:
70 f.write(contents) 71 f.write(contents)
71 72
72 return referees 73 return referees
73 74
74 75
75 def main(): 76 def main():
76 file_globs = [] 77 parser = optparse.OptionParser(usage='''
77 force_unsafe_run = False 78 (1) %prog <options> REGEXP REPLACEMENT
78 args = sys.argv[1:] 79 REGEXP uses full Python regexp syntax. REPLACEMENT can use back-references.
79 while args and args[0].startswith('-'): 80
80 if args[0] == '-d': 81 (2) %prog <options> -i <file>
81 file_globs = ['*.cc', '*.h', '*.m', '*.mm'] 82 <file> should contain a list (in Python syntax) of
82 args = args[1:] 83 [REGEXP, REPLACEMENT, [GLOBS]] lists, e.g.:
83 elif args[0] == '-g': 84 [
84 file_globs.append(args[1]) 85 [r"(foo|bar)", r"\1baz", ["*.cc", "*.h"]],
85 args = args[2:] 86 ["54", "42"],
86 elif args[0] == '-f': 87 ]
87 force_unsafe_run = True 88 As shown above, [GLOBS] can be omitted for a given search-replace list, in which
88 args = args[1:] 89 case the corresponding search-replace will use the globs specified on the
89 if not file_globs: 90 command line.''')
90 file_globs = ['*.*'] 91 parser.add_option('-d', action='store_true',
91 if not args: 92 dest='use_default_glob',
92 print globals()['__doc__'] 93 help='Perform the change on C++ and Objective-C(++) source '
94 'and header files.')
95 parser.add_option('-f', action='store_true',
96 dest='force_unsafe_run',
97 help='Perform the run even if there are uncommitted local '
98 'changes.')
99 parser.add_option('-g', action='append',
100 type='string',
101 default=[],
102 metavar="<glob>",
103 dest='user_supplied_globs',
104 help='Perform the change on the specified glob. Can be '
105 'specified multiple times, in which case the globs are '
106 'unioned.')
107 parser.add_option('-i', "--input_file",
108 type='string',
109 action='store',
110 default='',
111 metavar="<file>",
112 dest='input_filename',
113 help='Read arguments from <file> rather than the command '
114 'line. NOTE: To be sure of regular expressions being '
115 'interpreted correctly, use raw strings.')
116 opts, args = parser.parse_args()
117 if opts.use_default_glob and opts.user_supplied_globs:
118 print '"-d" and "-g" cannot be used together'
119 parser.print_help()
93 return 1 120 return 1
94 if not force_unsafe_run: 121
122 from_file = opts.input_filename != ""
123 if (from_file and len(args) != 0) or (not from_file and len(args) != 2):
124 parser.print_help()
125 return 1
126
127 if not opts.force_unsafe_run:
95 out, err = subprocess.Popen(['git', 'status', '--porcelain'], 128 out, err = subprocess.Popen(['git', 'status', '--porcelain'],
96 stdout=subprocess.PIPE, 129 stdout=subprocess.PIPE,
97 shell=_USE_SHELL).communicate() 130 shell=_USE_SHELL).communicate()
98 if out: 131 if out:
99 print 'ERROR: This tool does not print any confirmation prompts,' 132 print 'ERROR: This tool does not print any confirmation prompts,'
100 print 'so you should only run it with a clean staging area and cache' 133 print 'so you should only run it with a clean staging area and cache'
101 print 'so that reverting a bad find/replace is as easy as running' 134 print 'so that reverting a bad find/replace is as easy as running'
102 print ' git checkout -- .' 135 print ' git checkout -- .'
103 print '' 136 print ''
104 print 'To override this safeguard, pass the -f flag.' 137 print 'To override this safeguard, pass the -f flag.'
105 return 1 138 return 1
106 original = args[0] 139
107 replacement = args[1] 140 global_file_globs = ['*.*']
108 print 'File globs: %s' % file_globs 141 if opts.use_default_glob:
109 print 'Original: %s' % original 142 global_file_globs = ['*.cc', '*.h', '*.m', '*.mm']
110 print 'Replacement: %s' % replacement 143 elif opts.user_supplied_globs:
111 MultiFileFindReplace(original, replacement, file_globs) 144 global_file_globs = opts.user_supplied_globs
145
146 # Construct list of search-replace tasks.
147 search_replace_tasks = []
148 if opts.input_filename == '':
149 original = args[0]
150 replacement = args[1]
151 search_replace_tasks.append([original, replacement, global_file_globs])
152 else:
153 f = open(opts.input_filename)
154 search_replace_tasks = eval("".join(f.readlines()))
155 for task in search_replace_tasks:
156 if len(task) == 2:
157 task.append(global_file_globs)
158 f.close()
159
160 for (original, replacement, file_globs) in search_replace_tasks:
161 print 'File globs: %s' % file_globs
162 print 'Original: %s' % original
163 print 'Replacement: %s' % replacement
164 MultiFileFindReplace(original, replacement, file_globs)
112 return 0 165 return 0
113 166
114 167
115 if __name__ == '__main__': 168 if __name__ == '__main__':
116 sys.exit(main()) 169 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698