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

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

Issue 2106353005: Make mffr.py work on Windows for tools/git/mass-rename.py (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 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 optparse
21 import os
21 import re 22 import re
22 import subprocess 23 import subprocess
23 import sys 24 import sys
24 25
25 26
26 # We need to use shell=True with subprocess on Windows so that it 27 # We can't use shell=True because of the vast and sundry crazy characters we
27 # finds 'git' from the path, but can lead to undesired behavior on 28 # try to pass through to git grep. depot_tools packages a git .bat around
28 # Linux. 29 # a git.cmd around git.exe, which makes it impossible to escape the characters
29 _USE_SHELL = (sys.platform == 'win32') 30 # properly. Instead, locate the git .exe up front here. We use cd / && pwd -W,
31 # which first changes to the git install root. Inside git bash this "/" is where
32 # it hosts a fake /usr, /bin, /etc, ..., but then we use -W to pwd to print the
33 # Windows version of the path. Once we have the .exe directly, then we no longer
34 # need to use shell=True to subprocess calls, so escaping becomes simply for
35 # quotes for CreateProcess(), rather than |, <, >, etc. through multiple layers
36 # of cmd.
37 if sys.platform == 'win32':
38 _git = os.path.normpath(os.path.join(subprocess.check_output(
39 'git bash -c "cd / && pwd -W"', shell=True).strip(), 'bin\\git.exe'))
40 else:
41 _git = 'git'
30 42
31 43
32 def MultiFileFindReplace(original, replacement, file_globs): 44 def MultiFileFindReplace(original, replacement, file_globs):
33 """Implements fast multi-file find and replace. 45 """Implements fast multi-file find and replace.
34 46
35 Given an |original| string and a |replacement| string, find matching 47 Given an |original| string and a |replacement| string, find matching
36 files by running git grep on |original| in files matching any 48 files by running git grep on |original| in files matching any
37 pattern in |file_globs|. 49 pattern in |file_globs|.
38 50
39 Once files are found, |re.sub| is run to replace |original| with 51 Once files are found, |re.sub| is run to replace |original| with
40 |replacement|. |replacement| may use capture group back-references. 52 |replacement|. |replacement| may use capture group back-references.
41 53
42 Args: 54 Args:
43 original: '(#(include|import)\s*["<])chrome/browser/ui/browser.h([>"])' 55 original: '(#(include|import)\s*["<])chrome/browser/ui/browser.h([>"])'
44 replacement: '\1chrome/browser/ui/browser/browser.h\3' 56 replacement: '\1chrome/browser/ui/browser/browser.h\3'
45 file_globs: ['*.cc', '*.h', '*.m', '*.mm'] 57 file_globs: ['*.cc', '*.h', '*.m', '*.mm']
46 58
47 Returns the list of files modified. 59 Returns the list of files modified.
48 60
49 Raises an exception on error. 61 Raises an exception on error.
50 """ 62 """
51 # Posix extended regular expressions do not reliably support the "\s" 63 # Posix extended regular expressions do not reliably support the "\s"
52 # shorthand. 64 # shorthand.
53 posix_ere_original = re.sub(r"\\s", "[[:space:]]", original) 65 posix_ere_original = re.sub(r"\\s", "[[:space:]]", original)
54 if sys.platform == 'win32': 66 if sys.platform == 'win32':
55 posix_ere_original = posix_ere_original.replace('"', '""') 67 posix_ere_original = posix_ere_original.replace('"', '""')
56 out, err = subprocess.Popen( 68 out, err = subprocess.Popen(
57 ['git', 'grep', '-E', '--name-only', posix_ere_original, 69 [_git, 'grep', '-E', '--name-only', posix_ere_original,
58 '--'] + file_globs, 70 '--'] + file_globs,
59 stdout=subprocess.PIPE, 71 stdout=subprocess.PIPE).communicate()
60 shell=_USE_SHELL).communicate()
61 referees = out.splitlines() 72 referees = out.splitlines()
62 73
63 for referee in referees: 74 for referee in referees:
64 with open(referee) as f: 75 with open(referee) as f:
65 original_contents = f.read() 76 original_contents = f.read()
66 contents = re.sub(original, replacement, original_contents) 77 contents = re.sub(original, replacement, original_contents)
67 if contents == original_contents: 78 if contents == original_contents:
68 raise Exception('No change in file %s although matched in grep' % 79 raise Exception('No change in file %s although matched in grep' %
69 referee) 80 referee)
70 with open(referee, 'wb') as f: 81 with open(referee, 'wb') as f:
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
118 print '"-d" and "-g" cannot be used together' 129 print '"-d" and "-g" cannot be used together'
119 parser.print_help() 130 parser.print_help()
120 return 1 131 return 1
121 132
122 from_file = opts.input_filename != "" 133 from_file = opts.input_filename != ""
123 if (from_file and len(args) != 0) or (not from_file and len(args) != 2): 134 if (from_file and len(args) != 0) or (not from_file and len(args) != 2):
124 parser.print_help() 135 parser.print_help()
125 return 1 136 return 1
126 137
127 if not opts.force_unsafe_run: 138 if not opts.force_unsafe_run:
128 out, err = subprocess.Popen(['git', 'status', '--porcelain'], 139 out, err = subprocess.Popen([_git, 'status', '--porcelain'],
129 stdout=subprocess.PIPE, 140 stdout=subprocess.PIPE).communicate()
130 shell=_USE_SHELL).communicate()
131 if out: 141 if out:
132 print 'ERROR: This tool does not print any confirmation prompts,' 142 print 'ERROR: This tool does not print any confirmation prompts,'
133 print 'so you should only run it with a clean staging area and cache' 143 print 'so you should only run it with a clean staging area and cache'
134 print 'so that reverting a bad find/replace is as easy as running' 144 print 'so that reverting a bad find/replace is as easy as running'
135 print ' git checkout -- .' 145 print ' git checkout -- .'
136 print '' 146 print ''
137 print 'To override this safeguard, pass the -f flag.' 147 print 'To override this safeguard, pass the -f flag.'
138 return 1 148 return 1
139 149
140 global_file_globs = ['*.*'] 150 global_file_globs = ['*.*']
(...skipping 19 matching lines...) Expand all
160 for (original, replacement, file_globs) in search_replace_tasks: 170 for (original, replacement, file_globs) in search_replace_tasks:
161 print 'File globs: %s' % file_globs 171 print 'File globs: %s' % file_globs
162 print 'Original: %s' % original 172 print 'Original: %s' % original
163 print 'Replacement: %s' % replacement 173 print 'Replacement: %s' % replacement
164 MultiFileFindReplace(original, replacement, file_globs) 174 MultiFileFindReplace(original, replacement, file_globs)
165 return 0 175 return 0
166 176
167 177
168 if __name__ == '__main__': 178 if __name__ == '__main__':
169 sys.exit(main()) 179 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