OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
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 | |
4 # found in the LICENSE file. | |
5 | |
6 """Fix header files missing in GN. | |
7 | |
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. | |
10 Manual cleaning up is likely required afterwards. | |
11 """ | |
12 | |
13 import argparse | |
14 import os | |
15 import re | |
16 import subprocess | |
17 import sys | |
18 | |
19 | |
20 def AddHeadersNextToCC(headers, skip_ambiguous=True): | |
21 """Add header files next to the corresponding .cc files in GN files. | |
22 | |
23 When skip_ambiguous is True, skip if multiple .cc files are found. | |
24 Returns unhandled headers. | |
25 | |
26 Manual cleaning up is likely required, especially if not skip_ambiguous. | |
27 """ | |
28 edits = {} | |
29 unhandled = [] | |
30 for filename in headers: | |
31 filename = filename.strip() | |
32 if not (filename.endswith('.h') or filename.endswith('.hh')): | |
Nico
2017/03/28 14:37:55
Do we have any headers ending in .hh?
wychen
2017/03/28 17:52:05
Yes, we do, and some of them are part of the GN mi
| |
33 continue | |
34 basename = os.path.basename(filename) | |
35 print filename | |
36 cc = r'\b' + os.path.splitext(basename)[0] + r'\.(cc|cpp|mm)\b' | |
37 p = subprocess.Popen( | |
38 ['git', 'grep', '-En', cc + '"', '--', '*.gn', '*.gni'], | |
39 stdout=subprocess.PIPE) | |
40 out, _ = p.communicate() | |
41 if p.returncode != 0 or not out: | |
42 unhandled.append(filename) | |
43 continue | |
44 | |
45 if skip_ambiguous and len(out.splitlines()) > 1: | |
46 print '\n[WARNING] Ambiguous matching for', filename | |
47 print out | |
48 continue | |
49 | |
50 for gnline in out.splitlines(): | |
51 gnfile, linenr, contents = gnline.split(':') | |
52 linenr = int(linenr) | |
53 new = re.sub(cc, basename, contents) | |
54 lines = open(gnfile).read().splitlines() | |
55 if lines[linenr] == new: | |
56 continue | |
57 if lines[linenr - 2] == new: | |
Nico
2017/03/28 14:37:55
why this?
wychen
2017/03/28 17:52:05
This and the line above is for deduplication.
line
| |
58 continue | |
59 print ' ', gnfile, linenr, new | |
60 edits.setdefault(gnfile, {})[linenr] = new | |
61 | |
62 for gnfile in edits: | |
63 lines = open(gnfile).read().splitlines() | |
64 for l in reversed(sorted(edits[gnfile].keys())): | |
Nico
2017/03/28 14:37:55
Ah, that was the bug! I had assumed the keys were
wychen
2017/03/28 17:52:05
Done.
| |
65 lines.insert(l, edits[gnfile][l]) | |
66 open(gnfile, 'w').write('\n'.join(lines) + '\n') | |
67 | |
68 return unhandled | |
69 | |
70 | |
71 def AddHeadersToSources(headers, skip_ambiguous=True): | |
72 """Add header files to the sources list in the closest GN file. | |
Nico
2017/03/28 14:37:55
"to the _first_ sources list"
Mention somehow tha
wychen
2017/03/28 17:52:05
Done.
| |
73 | |
74 When skip_ambiguous is True, skip if multiple sources arrays are found. | |
75 | |
76 "git cl format" afterwards is required. Manually cleaning up duplicated items | |
77 is likely required. | |
78 """ | |
79 for filename in headers: | |
80 filename = filename.strip() | |
81 print filename | |
82 dirname = os.path.dirname(filename) | |
83 while not os.path.exists(os.path.join(dirname, 'BUILD.gn')): | |
84 dirname = os.path.dirname(dirname) | |
85 rel = filename[len(dirname) + 1:] | |
86 gnfile = os.path.join(dirname, 'BUILD.gn') | |
87 | |
88 lines = open(gnfile).read().splitlines() | |
89 matched = [i for i, l in enumerate(lines) if ' sources = [' in l] | |
90 if skip_ambiguous and len(matched) > 1: | |
91 print '[WARNING] Multiple sources in', gnfile | |
92 continue | |
93 | |
94 if len(matched) < 1: | |
95 continue | |
96 print ' ', gnfile, rel | |
97 index = matched[0] | |
98 lines.insert(index + 1, '"%s",' % rel) | |
99 open(gnfile, 'w').write('\n'.join(lines) + '\n') | |
100 | |
101 | |
102 def main(): | |
103 parser = argparse.ArgumentParser() | |
104 parser.add_argument('--input', required=True, | |
105 help="missing headers, output of check_gn_headers.py") | |
Nico
2017/03/28 14:37:55
nit: I'd make this one a positional argument
wychen
2017/03/28 17:52:05
Done.
| |
106 parser.add_argument('--prefix', | |
107 help="only handle path name with this prefix") | |
108 parser.add_argument('args', nargs=argparse.REMAINDER) | |
109 | |
110 args, _extras = parser.parse_known_args() | |
111 | |
112 headers = open(args.input).readlines() | |
113 | |
114 if args.prefix: | |
115 headers = [i for i in headers if i.startswith(args.prefix)] | |
116 | |
117 unhandled = AddHeadersNextToCC(headers) | |
118 AddHeadersToSources(unhandled) | |
119 | |
120 | |
121 if __name__ == '__main__': | |
122 sys.exit(main()) | |
OLD | NEW |