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

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

Issue 11358216: Consolidate mass-rename.sh and move_source_file.py (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Reupload with similarity=30 to see the move diff. Created 8 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « tools/git/mass-rename.sh ('k') | tools/refactor/move_file.py » ('j') | 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) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 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 """Moves a C++ file to a new location, updating any include paths that 6 """Moves a C++ file to a new location, updating any include paths that
7 point to it. Updates include guards in moved header files. Assumes 7 point to it. Updates include guards in moved header files. Assumes
8 Chromium coding style. 8 Chromium coding style.
9 9
10 Does not reorder headers (you can use tools/sort-headers.py), and does 10 Does not reorder headers; instead, use this after committing all of
11 not update .gypi files. 11 your moves:
12 ./tools/git/for-all-touched-files.py -c "tools/sort-headers.py [[FILENAME]]"
12 13
13 Relies on git for a fast way to find files that include the moved file. 14 Updates paths used in .gyp(i) files, but does not reorder or
15 restructure .gyp(i) files in any way.
16
17 Must run in a git checkout, as it relies on git for a fast way to find
18 files that reference the moved file.
14 """ 19 """
15 20
16 21
17 import os 22 import os
23 import re
18 import subprocess 24 import subprocess
19 import sys 25 import sys
20 26
21 27
22 HANDLED_EXTENSIONS = ['.cc', '.mm', '.h', '.hh'] 28 HANDLED_EXTENSIONS = ['.cc', '.mm', '.h', '.hh']
23 29
24 30
25 def MoveFile(from_path, to_path): 31 def MoveFile(from_path, to_path, already_moved):
Nico 2012/11/14 19:51:36 It's a bit confusing that this is called MoveFile
Jói 2012/11/15 15:13:10 Done.
26 """Moves a file from |from_path| to |to_path|, updating its include 32 """Moves a file from |from_path| to |to_path| (unless
27 guard to match the new path and updating all #includes and #imports 33 |already_moved|), then updates the moved file's include guard to
28 of the file in other files in the same git repository, with the 34 match the new path and updates all references to the file in other
35 source files and .gyp(i) files in the same git repository, with the
29 assumption that they include it using the Chromium style 36 assumption that they include it using the Chromium style
30 guide-standard full path from root. 37 guide-standard full path from root, or the .gyp(i) standard full
38 path from root minus first path component.
31 """ 39 """
32 extension = os.path.splitext(from_path)[1] 40 extension = os.path.splitext(from_path)[1]
33 if extension not in HANDLED_EXTENSIONS:
34 raise Exception('Only intended to move individual source files.')
35 41
36 dest_extension = os.path.splitext(to_path)[1] 42 if not already_moved:
37 if dest_extension not in HANDLED_EXTENSIONS: 43 if extension not in HANDLED_EXTENSIONS:
38 if to_path.endswith('/') or to_path.endswith('\\'): 44 raise Exception('Only intended to move individual source files.')
39 to_path += os.path.basename(from_path) 45 dest_extension = os.path.splitext(to_path)[1]
40 else: 46 if dest_extension not in HANDLED_EXTENSIONS:
41 raise Exception('Destination must be either full path or end with /.') 47 if to_path.endswith('/') or to_path.endswith('\\'):
48 to_path += os.path.basename(from_path)
49 else:
50 raise Exception('Destination must be either full path or end with /.')
42 51
43 if not os.system('git mv %s %s' % (from_path, to_path)) == 0: 52 if not os.system('git mv %s %s' % (from_path, to_path)) == 0:
44 raise Exception('Fatal: Failed to run git mv command.') 53 raise Exception('Fatal: Failed to run git mv command.')
45 54
46 if extension in ['.h', '.hh']: 55 if extension in ['.h', '.hh']:
47 UpdateIncludeGuard(from_path, to_path) 56 UpdateIncludeGuard(from_path, to_path)
48 UpdateIncludes(from_path, to_path) 57 UpdateUsages(from_path, to_path, includes=True)
58
59 UpdateUsages(from_path, to_path, includes=False)
49 60
50 61
51 def MakeIncludeGuardName(path_from_root): 62 def MakeIncludeGuardName(path_from_root):
52 """Returns an include guard name given a path from root.""" 63 """Returns an include guard name given a path from root."""
53 guard = path_from_root.replace('/', '_') 64 guard = path_from_root.replace('/', '_')
54 guard = guard.replace('\\', '_') 65 guard = guard.replace('\\', '_')
55 guard = guard.replace('.', '_') 66 guard = guard.replace('.', '_')
56 guard += '_' 67 guard += '_'
57 return guard.upper() 68 return guard.upper()
58 69
(...skipping 13 matching lines...) Expand all
72 83
73 new_contents = contents.replace(old_guard, new_guard) 84 new_contents = contents.replace(old_guard, new_guard)
74 if new_contents == contents: 85 if new_contents == contents:
75 raise Exception( 86 raise Exception(
76 'Error updating include guard; perhaps old guard is not per style guide?') 87 'Error updating include guard; perhaps old guard is not per style guide?')
77 88
78 with open(new_path, 'w') as f: 89 with open(new_path, 'w') as f:
79 f.write(new_contents) 90 f.write(new_contents)
80 91
81 92
82 def UpdateIncludes(old_path, new_path): 93 def UpdateUsages(old_path, new_path, includes):
83 """Given the |old_path| and |new_path| of a file being moved, update 94 """Given the |old_path| and |new_path| of a file being moved, update
84 #include and #import statements in all files in the same git 95 usages (#include, #import, or reference in a .gyp(i) file) in all files
85 repository referring to the moved file. 96 in the same git repository referring to the moved file.
97
98 Updates includes when |includes| is True, .gyp(i) files when
99 |includes| is False.
86 """ 100 """
87 # Include paths always use forward slashes. 101 # Include paths always use forward slashes.
88 old_path = old_path.replace('\\', '/') 102 old_path = old_path.replace('\\', '/')
89 new_path = new_path.replace('\\', '/') 103 new_path = new_path.replace('\\', '/')
90 104
91 out, err = subprocess.Popen( 105 if includes:
92 ['git', 'grep', '--name-only', 106 out, err = subprocess.Popen(
93 r'#\(include\|import\)\s*["<]%s[>"]' % old_path], 107 ['git', 'grep', '--name-only',
94 stdout=subprocess.PIPE).communicate() 108 r'#\(include\|import\)\s*["<]%s[>"]' % old_path,
95 includees = out.splitlines() 109 '--', '*.cc', '*.h', '*.m', '*.mm'],
110 stdout=subprocess.PIPE).communicate()
111 includees = out.splitlines()
112 else:
113 def PathMinusFirstComponent(path):
114 parts = re.split(r"[/\\]", path, 1)
115 if len(parts) == 2:
116 return parts[1]
117 else:
118 return parts[0]
119 old_path = PathMinusFirstComponent(old_path)
120 new_path = PathMinusFirstComponent(new_path)
121 out, err = subprocess.Popen(
122 ['git', 'grep', '--name-only',
123 r'[\'"]%s[\'"]' % old_path, '--', '*.gyp*'],
124 stdout=subprocess.PIPE).communicate()
125 includees = out.splitlines()
96 126
97 for includee in includees: 127 for includee in includees:
98 with open(includee) as f: 128 with open(includee) as f:
99 contents = f.read() 129 contents = f.read()
100 new_contents = contents.replace('"%s"' % old_path, '"%s"' % new_path) 130 new_contents = contents.replace('"%s"' % old_path, '"%s"' % new_path)
101 new_contents = new_contents.replace('<%s>' % old_path, '<%s>' % new_path) 131 if includes:
132 new_contents = new_contents.replace('<%s>' % old_path, '<%s>' % new_path)
133 else:
134 new_contents = new_contents.replace("'%s'" % old_path, "'%s'" % new_path)
102 if new_contents == contents: 135 if new_contents == contents:
103 raise Exception('Error updating include in file %s' % includee) 136 raise Exception('Error updating usage in file %s' % includee)
104 with open(includee, 'w') as f: 137 with open(includee, 'w') as f:
105 f.write(new_contents) 138 f.write(new_contents)
106 139
107 140
108 def main(): 141 def main():
109 if not os.path.isdir('.git'): 142 if not os.path.isdir('.git'):
110 print 'Fatal: You must run from the root of a git checkout.' 143 print 'Fatal: You must run from the root of a git checkout.'
111 return 1 144 return 1
112 args = sys.argv[1:] 145 args = sys.argv[1:]
113 if len(args) != 2: 146 if not len(args) in [2, 3]:
114 print 'Usage: move_file.py FROM_PATH TO_PATH\n\n%s' % __doc__ 147 print ('Usage: move_source_file.py [--already-moved] FROM_PATH TO_PATH'
148 '\n\n%s' % __doc__)
115 return 1 149 return 1
116 MoveFile(args[0], args[1]) 150 already_moved = False
151 if args[0] == '--already-moved':
152 args = args[1:]
153 already_moved = True
154
155 MoveFile(args[0], args[1], already_moved)
117 return 0 156 return 0
118 157
119 158
120 if __name__ == '__main__': 159 if __name__ == '__main__':
121 sys.exit(main()) 160 sys.exit(main())
OLDNEW
« no previous file with comments | « tools/git/mass-rename.sh ('k') | tools/refactor/move_file.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698