OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2017 The Chromium Authors. All rights reserved. | 2 # Copyright 2017 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 """Fix header files missing in GN. | 6 """Fix header files missing in GN. |
7 | 7 |
8 This script takes the missing header files from check_gn_headers.py, and | 8 This script takes the missing header files from check_gn_headers.py, and |
9 try to fix them by adding them to the GN files. | 9 try to fix them by adding them to the GN files. |
10 Manual cleaning up is likely required afterwards. | 10 Manual cleaning up is likely required afterwards. |
11 """ | 11 """ |
12 | 12 |
13 import argparse | 13 import argparse |
14 import os | 14 import os |
15 import re | 15 import re |
16 import subprocess | 16 import subprocess |
17 import sys | 17 import sys |
18 | 18 |
19 | 19 |
| 20 def GitGrep(pattern): |
| 21 p = subprocess.Popen( |
| 22 ['git', 'grep', '-En', pattern, '--', '*.gn', '*.gni'], |
| 23 stdout=subprocess.PIPE) |
| 24 out, _ = p.communicate() |
| 25 return out, p.returncode |
| 26 |
| 27 |
| 28 def ValidMatches(basename, cc, grep_lines): |
| 29 """Filter out 'git grep' matches with header files already.""" |
| 30 matches = [] |
| 31 for line in grep_lines: |
| 32 gnfile, linenr, contents = line.split(':') |
| 33 linenr = int(linenr) |
| 34 new = re.sub(cc, basename, contents) |
| 35 lines = open(gnfile).read().splitlines() |
| 36 assert contents in lines[linenr - 1] |
| 37 # Skip if it's already there. It could be before or after the match. |
| 38 if lines[linenr] == new: |
| 39 continue |
| 40 if lines[linenr - 2] == new: |
| 41 continue |
| 42 print ' ', gnfile, linenr, new |
| 43 matches.append((gnfile, linenr, new)) |
| 44 return matches |
| 45 |
| 46 |
20 def AddHeadersNextToCC(headers, skip_ambiguous=True): | 47 def AddHeadersNextToCC(headers, skip_ambiguous=True): |
21 """Add header files next to the corresponding .cc files in GN files. | 48 """Add header files next to the corresponding .cc files in GN files. |
22 | 49 |
23 When skip_ambiguous is True, skip if multiple .cc files are found. | 50 When skip_ambiguous is True, skip if multiple .cc files are found. |
24 Returns unhandled headers. | 51 Returns unhandled headers. |
25 | 52 |
26 Manual cleaning up is likely required, especially if not skip_ambiguous. | 53 Manual cleaning up is likely required, especially if not skip_ambiguous. |
27 """ | 54 """ |
28 edits = {} | 55 edits = {} |
29 unhandled = [] | 56 unhandled = [] |
30 for filename in headers: | 57 for filename in headers: |
31 filename = filename.strip() | 58 filename = filename.strip() |
32 if not (filename.endswith('.h') or filename.endswith('.hh')): | 59 if not (filename.endswith('.h') or filename.endswith('.hh')): |
33 continue | 60 continue |
34 basename = os.path.basename(filename) | 61 basename = os.path.basename(filename) |
35 print filename | 62 print filename |
36 cc = r'\b' + os.path.splitext(basename)[0] + r'\.(cc|cpp|mm)\b' | 63 cc = r'\b' + os.path.splitext(basename)[0] + r'\.(cc|cpp|mm)\b' |
37 p = subprocess.Popen( | 64 out, returncode = GitGrep('(/|")' + cc + '"') |
38 ['git', 'grep', '-En', cc + '"', '--', '*.gn', '*.gni'], | 65 if returncode != 0 or not out: |
39 stdout=subprocess.PIPE) | |
40 out, _ = p.communicate() | |
41 if p.returncode != 0 or not out: | |
42 unhandled.append(filename) | 66 unhandled.append(filename) |
43 continue | 67 continue |
44 | 68 |
45 if skip_ambiguous and len(out.splitlines()) > 1: | 69 matches = ValidMatches(basename, cc, out.splitlines()) |
| 70 |
| 71 if len(matches) == 0: |
| 72 continue |
| 73 if len(matches) > 1: |
46 print '\n[WARNING] Ambiguous matching for', filename | 74 print '\n[WARNING] Ambiguous matching for', filename |
47 print out | 75 for i in enumerate(matches, 1): |
48 continue | 76 print '%d: %s' % (i[0], i[1]) |
| 77 print |
| 78 if skip_ambiguous: |
| 79 continue |
49 | 80 |
50 for gnline in out.splitlines(): | 81 picked = raw_input('Pick the matches ("2,3" for multiple): ') |
51 gnfile, linenr, contents = gnline.split(':') | 82 try: |
52 linenr = int(linenr) | 83 matches = [matches[int(i) - 1] for i in picked.split(',')] |
53 new = re.sub(cc, basename, contents) | 84 except (ValueError, IndexError): |
54 lines = open(gnfile).read().splitlines() | |
55 # Skip if it's already there. It could be before or after the match. | |
56 if lines[linenr] == new: | |
57 continue | 85 continue |
58 if lines[linenr - 2] == new: | 86 |
59 continue | 87 for match in matches: |
| 88 gnfile, linenr, new = match |
60 print ' ', gnfile, linenr, new | 89 print ' ', gnfile, linenr, new |
61 edits.setdefault(gnfile, {})[linenr] = new | 90 edits.setdefault(gnfile, {})[linenr] = new |
62 | 91 |
63 for gnfile in edits: | 92 for gnfile in edits: |
64 lines = open(gnfile).read().splitlines() | 93 lines = open(gnfile).read().splitlines() |
65 for l in sorted(edits[gnfile].keys(), reverse=True): | 94 for l in sorted(edits[gnfile].keys(), reverse=True): |
66 lines.insert(l, edits[gnfile][l]) | 95 lines.insert(l, edits[gnfile][l]) |
67 open(gnfile, 'w').write('\n'.join(lines) + '\n') | 96 open(gnfile, 'w').write('\n'.join(lines) + '\n') |
68 | 97 |
69 return unhandled | 98 return unhandled |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 | 145 |
117 if args.prefix: | 146 if args.prefix: |
118 headers = [i for i in headers if i.startswith(args.prefix)] | 147 headers = [i for i in headers if i.startswith(args.prefix)] |
119 | 148 |
120 unhandled = AddHeadersNextToCC(headers) | 149 unhandled = AddHeadersNextToCC(headers) |
121 AddHeadersToSources(unhandled) | 150 AddHeadersToSources(unhandled) |
122 | 151 |
123 | 152 |
124 if __name__ == '__main__': | 153 if __name__ == '__main__': |
125 sys.exit(main()) | 154 sys.exit(main()) |
OLD | NEW |