Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2015 The Chromium Authors. All rights reserved. | 2 # Copyright 2015 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 GYP/GN filename, sort C-ish source files in that file. | 6 """Given a GYP/GN filename, sort C-ish source files 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 | |
| 11 Limitations: | |
| 12 | |
| 13 1) Comments used as section headers | |
| 14 | |
| 15 If a comment (1+ lines starting with #) appears in a source list without a | |
| 16 preceding blank line, the tool assumes that the comment is about the next | |
| 17 line. For example, given the following source list, | |
| 18 | |
| 19 sources = [ | |
| 20 "b.cc", | |
| 21 # Comment. | |
| 22 "a.cc", | |
| 23 "c.cc", | |
| 24 ] | |
| 25 | |
| 26 the tool will produce the following output: | |
| 27 | |
| 28 sources = [ | |
| 29 # Comment. | |
| 30 "a.cc", | |
| 31 "b.cc", | |
| 32 "c.cc", | |
| 33 ] | |
| 34 | |
| 35 This is not correct if the comment is for starting a new section like: | |
| 36 | |
| 37 sources = [ | |
| 38 "b.cc", | |
| 39 # These are for Linux. | |
| 40 "a.cc", | |
| 41 "c.cc", | |
| 42 ] | |
| 43 | |
| 44 The tool cannot disambiguate the two types of comments. The problem can be | |
| 45 worked around by inserting a blank line before the comment because the tool | |
| 46 interprets a blank line as the end of a source list. | |
|
Daniel Erat
2015/02/19 14:05:17
hmm, it may not be possible to always do this. i t
satorux1
2015/02/20 00:14:29
It should be OK. Here's from ash/BUILD.gn:
#
| |
| 47 | |
| 48 2) Sources commented out | |
| 49 | |
| 50 Sometimes sources are commented out with their positions kept in the | |
| 51 alphabetical order, but what if the list is not sorted correctly? For | |
| 52 example, given the following source list, | |
| 53 | |
| 54 sources = [ | |
| 55 "a.cc", | |
| 56 # "b.cc", | |
| 57 "d.cc", | |
| 58 "c.cc", | |
| 59 ] | |
| 60 | |
| 61 the tool will produce the following output: | |
| 62 | |
| 63 sources = [ | |
| 64 "a.cc", | |
| 65 "c.cc", | |
| 66 # "b.cc", | |
| 67 "d.cc", | |
| 68 ] | |
| 69 | |
| 70 This is because the tool assumes that the comment (# "b.cc",) is about the | |
| 71 next line ("d.cc",). This kind of errors should be fixed manually. | |
|
Daniel Erat
2015/02/19 14:05:17
maybe you should say that the fix is to not check
satorux1
2015/02/20 00:14:29
good point. added.
| |
| 72 | |
| 73 3) " and ' are used both used in the same source list (GYP only problem) | |
| 74 | |
| 75 If both " and ' are used in the same source list, sources quoted with " will | |
| 76 appear first in the output. The problem is rare enough so the tool does not | |
| 77 attempt to normalize them. Hence this kind of errors should be fixed | |
| 78 manually. | |
| 79 | |
| 80 4) Spaces and tabs used in the same source list | |
| 81 | |
| 82 Similarly, if spaces and tabs are both used in the same source list, sources | |
| 83 indented with tabs will appear first in the output. This kind of errors | |
| 84 should be fixed manually. | |
| 10 """ | 85 """ |
| 11 | 86 |
| 12 import difflib | 87 import difflib |
| 13 import optparse | 88 import optparse |
| 14 import re | 89 import re |
| 15 import sys | 90 import sys |
| 16 | 91 |
| 17 from yes_no import YesNo | 92 from yes_no import YesNo |
| 18 | 93 |
| 19 SUFFIXES = ['c', 'cc', 'cpp', 'h', 'mm', 'rc', 'rc.version', 'ico', 'def', | 94 SUFFIXES = ['c', 'cc', 'cpp', 'h', 'mm', 'rc', 'rc.version', 'ico', 'def', |
| 20 'release'] | 95 'release'] |
| 21 SOURCE_PATTERN = re.compile('^\s+[\'"].*\.(%s)[\'"],$' % | 96 SOURCE_PATTERN = re.compile(r'^\s+[\'"].*\.(%s)[\'"],$' % |
| 22 '|'.join([re.escape(x) for x in SUFFIXES])) | 97 '|'.join([re.escape(x) for x in SUFFIXES])) |
| 23 COMMENT_PATTERN = re.compile('^\s+#') | 98 COMMENT_PATTERN = re.compile(r'^\s+#') |
| 99 | |
| 24 | 100 |
| 25 def SortSources(original_lines): | 101 def SortSources(original_lines): |
| 26 """Sort source file names in |original_lines|. | 102 """Sort source file names in |original_lines|. |
| 27 | 103 |
| 28 Args: | 104 Args: |
| 29 original_lines: Lines of the original content as a list of strings. | 105 original_lines: Lines of the original content as a list of strings. |
| 30 | 106 |
| 31 Returns: | 107 Returns: |
| 32 Lines of the sorted content as a list of strings. | 108 Lines of the sorted content as a list of strings. |
| 33 | 109 |
| 34 The algorithm is fairly naive. The code tries to find a list of C-ish | 110 The algorithm is fairly naive. The code tries to find a list of C-ish |
| 35 source file names by a simple regex, then sort them. The code does not try | 111 source file names by a simple regex, then sort them. The code does not try |
| 36 to understand the syntax of the build files, hence there are some cases | 112 to understand the syntax of the build files. See the file comment above for |
| 37 that the code cannot handle correctly (ex. blank lines within a list of | 113 details. |
| 38 source file names). | |
| 39 """ | 114 """ |
| 40 | 115 |
| 41 output_lines = [] | 116 output_lines = [] |
| 42 comments = [] | 117 comments = [] |
| 43 sources = [] | 118 sources = [] |
| 44 for line in original_lines: | 119 for line in original_lines: |
| 45 if re.search(COMMENT_PATTERN, line): | 120 if re.search(COMMENT_PATTERN, line): |
| 46 comments.append(line) | 121 comments.append(line) |
| 47 elif re.search(SOURCE_PATTERN, line): | 122 elif re.search(SOURCE_PATTERN, line): |
| 48 # Associate the line with the preceeding comments. | 123 # Associate the line with the preceding comments. |
| 49 sources.append([line, comments]) | 124 sources.append([line, comments]) |
| 50 comments = [] | 125 comments = [] |
| 51 else: | 126 else: |
| 52 # |sources| should be flushed first, to handle comments at the end of a | 127 # |sources| should be flushed first, to handle comments at the end of a |
| 53 # source list correctly. | 128 # source list correctly. |
| 54 if sources: | 129 if sources: |
| 55 for source_line, source_comments in sorted(sources): | 130 for source_line, source_comments in sorted(sources): |
| 56 output_lines.extend(source_comments) | 131 output_lines.extend(source_comments) |
| 57 output_lines.append(source_line) | 132 output_lines.append(source_line) |
| 58 sources = [] | 133 sources = [] |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 101 if len(filenames) < 1: | 176 if len(filenames) < 1: |
| 102 parser.print_help() | 177 parser.print_help() |
| 103 return 1 | 178 return 1 |
| 104 | 179 |
| 105 for filename in filenames: | 180 for filename in filenames: |
| 106 ProcessFile(filename, opts.should_confirm) | 181 ProcessFile(filename, opts.should_confirm) |
| 107 | 182 |
| 108 | 183 |
| 109 if __name__ == '__main__': | 184 if __name__ == '__main__': |
| 110 sys.exit(main()) | 185 sys.exit(main()) |
| OLD | NEW |