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

Side by Side Diff: tools/sort-headers.py

Issue 1213613011: Allow move_source_file.py and sort-headers.py to work on blink. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 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
« tools/git/move_source_file.py ('K') | « tools/git/move_source_file.py ('k') | 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) 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 """Given a filename as an argument, sort the #include/#imports in that file. 6 """Given a filename as an argument, sort the #include/#imports in that file.
7 7
8 Shows a diff and prompts for confirmation before doing the deed. 8 Shows a diff and prompts for confirmation before doing the deed.
9 Works great with tools/git/for-all-touched-files.py. 9 Works great with tools/git/for-all-touched-files.py.
10 """ 10 """
11 11
12 import optparse 12 import optparse
13 import os 13 import os
14 import sys 14 import sys
15 15
16 from yes_no import YesNo 16 from yes_no import YesNo
17 17
18 18
19 def IncludeCompareKey(line):
20 """Sorting comparator key used for comparing two #include lines.
21 Returns the filename without the #include/#import/import prefix.
22 """
23 for prefix in ('#include ', '#import ', 'import '):
24 if line.startswith(prefix):
25 line = line[len(prefix):]
26 break
27
28 # The win32 api has all sorts of implicit include order dependencies :-/
29 # Give a few headers special sort keys that make sure they appear before all
30 # other headers.
31 if line.startswith('<windows.h>'): # Must be before e.g. shellapi.h
32 return '0'
33 if line.startswith('<atlbase.h>'): # Must be before atlapp.h.
34 return '1' + line
35 if line.startswith('<ole2.h>'): # Must be before e.g. intshcut.h
36 return '1' + line
37 if line.startswith('<unknwn.h>'): # Must be before e.g. intshcut.h
38 return '1' + line
39
40 # C++ system headers should come after C system headers.
41 if line.startswith('<'):
42 if line.find('.h>') != -1:
43 return '2' + line.lower()
44 else:
45 return '3' + line.lower()
46
47 return '4' + line
48
49
50 def IsInclude(line): 19 def IsInclude(line):
51 """Returns True if the line is an #include/#import/import line.""" 20 """Returns True if the line is an #include/#import/import line."""
52 return any([line.startswith('#include '), line.startswith('#import '), 21 return any([line.startswith('#include '), line.startswith('#import '),
53 line.startswith('import ')]) 22 line.startswith('import ')])
54 23
55 24
56 def SortHeader(infile, outfile): 25 def SortHeader(infile, outfile, for_blink):
26 def IncludeCompareKey(line):
Matt Giuca 2015/07/07 05:20:53 Hmm, not really a fan of nesting this whole functi
benwells 2015/07/13 05:46:31 Done the latter way as it seems more obvious.
27 """Sorting comparator key used for comparing two #include lines.
28 Returns the filename without the #include/#import/import prefix.
29 """
30 for prefix in ('#include ', '#import ', 'import '):
31 if line.startswith(prefix):
32 line = line[len(prefix):]
33 break
34
35 # The win32 api has all sorts of implicit include order dependencies :-/
36 # Give a few headers special sort keys that make sure they appear before all
37 # other headers.
38 if line.startswith('<windows.h>'): # Must be before e.g. shellapi.h
39 return '0'
40 if line.startswith('<atlbase.h>'): # Must be before atlapp.h.
41 return '1' + line
42 if line.startswith('<ole2.h>'): # Must be before e.g. intshcut.h
43 return '1' + line
44 if line.startswith('<unknwn.h>'): # Must be before e.g. intshcut.h
45 return '1' + line
46
47 if for_blink:
48 # Blink likes to have its "config.h" include first.
49 if line.startswith('"config.h"'):
50 return '0'
Matt Giuca 2015/07/07 05:20:53 Won't this conflict with <windows.h>?
benwells 2015/07/13 05:46:31 Yes. From looking at blink code they don't seem to
51
52 # Blink sorts system headers after others. This is handled by sorting
53 # alphabetically so no need to do anything tricky.
54 return '1' + line
55
56 # C++ system headers should come after C system headers.
57 if line.startswith('<'):
58 if line.find('.h>') != -1:
59 return '2' + line.lower()
60 else:
61 return '3' + line.lower()
62
63 return '4' + line
64
57 """Sorts the headers in infile, writing the sorted file to outfile.""" 65 """Sorts the headers in infile, writing the sorted file to outfile."""
58 for line in infile: 66 for line in infile:
59 if IsInclude(line): 67 if IsInclude(line):
60 headerblock = [] 68 headerblock = []
61 while IsInclude(line): 69 while IsInclude(line):
62 infile_ended_on_include_line = False 70 infile_ended_on_include_line = False
63 headerblock.append(line) 71 headerblock.append(line)
64 # Ensure we don't die due to trying to read beyond the end of the file. 72 # Ensure we don't die due to trying to read beyond the end of the file.
65 try: 73 try:
66 line = infile.next() 74 line = infile.next()
67 except StopIteration: 75 except StopIteration:
68 infile_ended_on_include_line = True 76 infile_ended_on_include_line = True
69 break 77 break
70 for header in sorted(headerblock, key=IncludeCompareKey): 78 for header in sorted(headerblock, key=IncludeCompareKey):
71 outfile.write(header) 79 outfile.write(header)
72 if infile_ended_on_include_line: 80 if infile_ended_on_include_line:
73 # We already wrote the last line above; exit to ensure it isn't written 81 # We already wrote the last line above; exit to ensure it isn't written
74 # again. 82 # again.
75 return 83 return
76 # Intentionally fall through, to write the line that caused 84 # Intentionally fall through, to write the line that caused
77 # the above while loop to exit. 85 # the above while loop to exit.
78 outfile.write(line) 86 outfile.write(line)
79 87
80 88
81 def FixFileWithConfirmFunction(filename, confirm_function, 89 def FixFileWithConfirmFunction(filename, confirm_function,
82 perform_safety_checks): 90 perform_safety_checks, for_blink = False):
Matt Giuca 2015/07/07 05:20:52 No spaces around =. "for_blink=False"
benwells 2015/07/13 05:46:31 Done.
83 """Creates a fixed version of the file, invokes |confirm_function| 91 """Creates a fixed version of the file, invokes |confirm_function|
84 to decide whether to use the new file, and cleans up. 92 to decide whether to use the new file, and cleans up.
85 93
86 |confirm_function| takes two parameters, the original filename and 94 |confirm_function| takes two parameters, the original filename and
87 the fixed-up filename, and returns True to use the fixed-up file, 95 the fixed-up filename, and returns True to use the fixed-up file,
88 false to not use it. 96 false to not use it.
89 97
90 If |perform_safety_checks| is True, then the function checks whether it is 98 If |perform_safety_checks| is True, then the function checks whether it is
91 unsafe to reorder headers in this file and skips the reorder with a warning 99 unsafe to reorder headers in this file and skips the reorder with a warning
92 message in that case. 100 message in that case.
93 """ 101 """
94 if perform_safety_checks and IsUnsafeToReorderHeaders(filename): 102 if perform_safety_checks and IsUnsafeToReorderHeaders(filename):
95 print ('Not reordering headers in %s as the script thinks that the ' 103 print ('Not reordering headers in %s as the script thinks that the '
96 'order of headers in this file is semantically significant.' 104 'order of headers in this file is semantically significant.'
97 % (filename)) 105 % (filename))
98 return 106 return
99 fixfilename = filename + '.new' 107 fixfilename = filename + '.new'
100 infile = open(filename, 'rb') 108 infile = open(filename, 'rb')
101 outfile = open(fixfilename, 'wb') 109 outfile = open(fixfilename, 'wb')
102 SortHeader(infile, outfile) 110 SortHeader(infile, outfile, for_blink)
103 infile.close() 111 infile.close()
104 outfile.close() # Important so the below diff gets the updated contents. 112 outfile.close() # Important so the below diff gets the updated contents.
105 113
106 try: 114 try:
107 if confirm_function(filename, fixfilename): 115 if confirm_function(filename, fixfilename):
108 if sys.platform == 'win32': 116 if sys.platform == 'win32':
109 os.unlink(filename) 117 os.unlink(filename)
110 os.rename(fixfilename, filename) 118 os.rename(fixfilename, filename)
111 finally: 119 finally:
112 try: 120 try:
113 os.remove(fixfilename) 121 os.remove(fixfilename)
114 except OSError: 122 except OSError:
115 # If the file isn't there, we don't care. 123 # If the file isn't there, we don't care.
116 pass 124 pass
117 125
118 126
119 def DiffAndConfirm(filename, should_confirm, perform_safety_checks): 127 def DiffAndConfirm(filename, should_confirm, perform_safety_checks, for_blink):
120 """Shows a diff of what the tool would change the file named 128 """Shows a diff of what the tool would change the file named
121 filename to. Shows a confirmation prompt if should_confirm is true. 129 filename to. Shows a confirmation prompt if should_confirm is true.
122 Saves the resulting file if should_confirm is false or the user 130 Saves the resulting file if should_confirm is false or the user
123 answers Y to the confirmation prompt. 131 answers Y to the confirmation prompt.
124 """ 132 """
125 def ConfirmFunction(filename, fixfilename): 133 def ConfirmFunction(filename, fixfilename):
126 diff = os.system('diff -u %s %s' % (filename, fixfilename)) 134 diff = os.system('diff -u %s %s' % (filename, fixfilename))
127 if sys.platform != 'win32': 135 if sys.platform != 'win32':
128 diff >>= 8 136 diff >>= 8
129 if diff == 0: # Check exit code. 137 if diff == 0: # Check exit code.
130 print '%s: no change' % filename 138 print '%s: no change' % filename
131 return False 139 return False
132 140
133 return (not should_confirm or YesNo('Use new file (y/N)?')) 141 return (not should_confirm or YesNo('Use new file (y/N)?'))
134 142
135 FixFileWithConfirmFunction(filename, ConfirmFunction, perform_safety_checks) 143 FixFileWithConfirmFunction(filename, ConfirmFunction, perform_safety_checks,
144 for_blink)
136 145
137 def IsUnsafeToReorderHeaders(filename): 146 def IsUnsafeToReorderHeaders(filename):
138 # *_message_generator.cc is almost certainly a file that generates IPC 147 # *_message_generator.cc is almost certainly a file that generates IPC
139 # definitions. Changes in include order in these files can result in them not 148 # definitions. Changes in include order in these files can result in them not
140 # building correctly. 149 # building correctly.
141 if filename.find("message_generator.cc") != -1: 150 if filename.find("message_generator.cc") != -1:
142 return True 151 return True
143 return False 152 return False
144 153
145 def main(): 154 def main():
146 parser = optparse.OptionParser(usage='%prog filename1 filename2 ...') 155 parser = optparse.OptionParser(usage='%prog filename1 filename2 ...')
147 parser.add_option('-f', '--force', action='store_false', default=True, 156 parser.add_option('-f', '--force', action='store_false', default=True,
148 dest='should_confirm', 157 dest='should_confirm',
149 help='Turn off confirmation prompt.') 158 help='Turn off confirmation prompt.')
150 parser.add_option('--no_safety_checks', 159 parser.add_option('--no_safety_checks',
151 action='store_false', default=True, 160 action='store_false', default=True,
152 dest='perform_safety_checks', 161 dest='perform_safety_checks',
153 help='Do not perform the safety checks via which this ' 162 help='Do not perform the safety checks via which this '
154 'script refuses to operate on files for which it thinks ' 163 'script refuses to operate on files for which it thinks '
155 'the include ordering is semantically significant.') 164 'the include ordering is semantically significant.')
165 parser.add_option('--for_blink', action='store_true', default=False,
166 dest='for_blink', help='Whether the blink header sorting '
167 'rules should be applied.')
156 opts, filenames = parser.parse_args() 168 opts, filenames = parser.parse_args()
157 169
158 if len(filenames) < 1: 170 if len(filenames) < 1:
159 parser.print_help() 171 parser.print_help()
160 return 1 172 return 1
161 173
162 for filename in filenames: 174 for filename in filenames:
163 DiffAndConfirm(filename, opts.should_confirm, opts.perform_safety_checks) 175 DiffAndConfirm(filename, opts.should_confirm, opts.perform_safety_checks,
176 opts.for_blink)
164 177
165 178
166 if __name__ == '__main__': 179 if __name__ == '__main__':
167 sys.exit(main()) 180 sys.exit(main())
OLDNEW
« tools/git/move_source_file.py ('K') | « tools/git/move_source_file.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698