OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/python | |
2 # Copyright 2014 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 #import logging | |
7 import os | |
8 import re | |
9 import sys | |
10 | |
11 _BASE_REGEX_STRING = '^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)' | |
12 require_regex = re.compile(_BASE_REGEX_STRING % 'require') | |
13 provide_regex = re.compile(_BASE_REGEX_STRING % 'provide') | |
14 | |
15 | |
16 def ProcessFile(filename): | |
17 """Extracts provided and required namespaces. | |
18 | |
19 Description: | |
20 Scans Javascript file for provied and required namespaces. | |
bruthig
2014/10/28 19:20:44
sp provied/provided
kevers
2014/10/29 14:27:19
Done.
| |
21 | |
22 Args: | |
23 filename: name of the file to process. | |
24 | |
25 Returns: | |
26 Pair of lists, where the first list contains namespaces provided by the file | |
27 and the second contains a list of requirements. | |
28 """ | |
29 | |
30 provides = [] | |
31 requires = [] | |
32 file_handle = open(filename, 'r') | |
33 try: | |
bruthig
2014/10/28 19:20:44
An alternative (and more pythonic) way to the try/
kevers
2014/10/29 14:27:19
Done.
| |
34 for line in file_handle: | |
bruthig
2014/10/28 19:20:44
Is it correct to assume that all matches will be c
kevers
2014/10/29 14:27:19
A linebreak is not allowed within a require or pro
| |
35 if re.match(require_regex, line): | |
36 requires.append(re.search(require_regex, line).group(1)) | |
bruthig
2014/10/28 19:20:44
You could replace the for loop and if statements w
kevers
2014/10/29 14:27:19
As this solution would loop over the file twice, I
| |
37 if re.match(provide_regex, line): | |
38 provides.append(re.search(provide_regex, line).group(1)) | |
39 finally: | |
40 file_handle.close() | |
41 return provides, requires | |
42 | |
43 | |
44 def ExtractDependencies(filename, providers, requirements): | |
45 """Extracts provided and required namespaces for a file. | |
46 | |
47 Description: | |
48 Updates maps for namespace providers and file prerequisites. | |
49 | |
50 Args: | |
51 filename: Path of the file to process. | |
52 providers: Mapping of namespace to filename that provides the namespace. | |
53 requirements: Mapping of filename to a list of prerequisite namespaces. | |
54 """ | |
55 | |
56 p, r = ProcessFile(filename) | |
57 | |
58 for name in p: | |
59 providers[name] = filename | |
60 for name in r: | |
61 if not filename in requirements: | |
62 requirements[filename] = [] | |
63 requirements[filename].append(name) | |
64 | |
65 | |
66 def Export(target_file, source_filename, providers, requirements, processed): | |
67 """Writes the contents of a file. | |
68 | |
69 Description: | |
70 Appends the contents of the source file to the target file. In order to | |
71 preserve proper dependencies, each file has its required namespaces | |
72 processed before exporting the source file itself. The set of exported files | |
73 is tracked to guard against multiple exports of the same file. Comments as | |
74 well as 'proivde' and 'require' statements are removed during to export to | |
bruthig
2014/10/28 19:20:44
sp proivde/provide
sp removed during to/the export
kevers
2014/10/29 14:27:19
Done.
| |
75 reduce file size. | |
76 | |
77 Args: | |
78 target_file: Handle to target file for export. | |
79 source_filename: Name of the file to export. | |
80 providers: Map of namespace to filename. | |
81 requirements: Map of filename to required namespaces. | |
82 processed: Set of processed files. | |
83 Returns: | |
84 """ | |
85 | |
86 # Filename may have already been processed if it was a requirement of a | |
87 # previous exported file. | |
88 if source_filename in processed: | |
89 return | |
90 | |
91 # Export requirements before file. | |
92 if source_filename in requirements: | |
93 for namespace in requirements[source_filename]: | |
94 if namespace in providers: | |
95 dependency = providers[namespace] | |
96 if dependency: | |
97 Export(target_file, dependency, providers, requirements, processed) | |
98 | |
99 # Export file | |
100 processed.add(source_filename) | |
101 for name in providers: | |
102 if providers[name] == source_filename: | |
103 target_file.write('// %s\n' % name) | |
bruthig
2014/10/28 19:20:44
If you care to make this platform agnostic you cou
kevers
2014/10/29 14:27:19
Done.
| |
104 source_file = open(source_filename, 'r') | |
105 try: | |
106 comment_block = False | |
107 for line in source_file: | |
108 # Skip require and provide statements. | |
109 if (not re.match(require_regex, line) and not | |
110 re.match(provide_regex, line)): | |
111 formatted = line.rstrip() | |
112 if comment_block: | |
113 # Scan for trailing */ in multi-line comment. | |
114 index = formatted.find('*/') | |
115 if index >= 0: | |
116 formatted = formatted[index + 2:] | |
117 comment_block = False | |
118 else: | |
119 formatted = '' | |
120 # Remove // style comments. | |
121 index = formatted.find('//') | |
122 if index >= 0: | |
123 formatted = formatted[:index] | |
124 # Remove /* */ style comments. | |
125 start_comment = formatted.find('/*') | |
126 end_comment = formatted.find('*/') | |
127 while start_comment >= 0: | |
128 if end_comment > start_comment: | |
129 formatted = (formatted[:start_comment] | |
130 + formatted[end_comment + 2:]) | |
131 start_comment = formatted.find('/*') | |
132 end_comment = formatted.find('*/') | |
bruthig
2014/10/28 19:20:44
It might be more readable/maintainable if there wa
kevers
2014/10/29 14:27:19
This spot is looking for potentially multiple inst
| |
133 else: | |
134 formatted = formatted[:start_comment] | |
135 comment_block = True | |
136 start_comment = -1 | |
137 if len(formatted.strip()) > 0: | |
bruthig
2014/10/28 19:20:44
The if statement below would be equivalent (assumi
kevers
2014/10/29 14:27:19
Done.
| |
138 target_file.write('%s\n' % formatted) | |
139 finally: | |
140 source_file.close() | |
141 target_file.write('\n') | |
142 | |
143 | |
144 def GetTargetFile(arguments): | |
145 """Extracts target file from the argument list. | |
146 | |
147 Args: | |
148 arguments: List of command line arguments. | |
149 """ | |
150 | |
151 for i in range(len(arguments)): | |
152 if arguments[i] == '--target': | |
153 return arguments[i + 1] | |
bruthig
2014/10/28 19:20:44
Is it intentional/ok that this will raise an out o
kevers
2014/10/29 14:27:19
Removed in favor of options parser.
| |
154 return None | |
155 | |
156 | |
157 def GetSourceFiles(arguments): | |
158 """Extract list if source files from the argument list. | |
159 | |
160 Args: | |
161 arguments: List of command line arguments. | |
162 """ | |
163 | |
164 sources = [] | |
165 start_index = -1 | |
166 for i in range(len(arguments)): | |
bruthig
2014/10/28 19:20:44
[applies to Python2.6 only] If arguments is going
kevers
2014/10/29 14:27:19
Removed in favor of options parser.
| |
167 if arguments[i] == '--sources': | |
168 start_index = i + 1 | |
169 break | |
170 if start_index < 0: | |
171 return None | |
172 for i in range(start_index, len(arguments)): | |
173 sources.append(arguments[i]) | |
174 return sources | |
175 | |
176 | |
177 def main(): | |
178 """The entrypoint for this script.""" | |
179 | |
180 target = GetTargetFile(sys.argv) | |
bruthig
2014/10/28 19:20:44
You may want to consider using pythons built in ar
kevers
2014/10/29 14:27:19
Done.
| |
181 sources = GetSourceFiles(sys.argv) | |
182 | |
183 providers = {} | |
184 requirements = {} | |
185 for file in sources: | |
186 ExtractDependencies(file, providers, requirements) | |
187 | |
188 target_file = open(target, 'w') | |
189 try: | |
190 processed = set() | |
191 for source_filename in sources: | |
192 Export(target_file, source_filename, providers, requirements, processed) | |
193 finally: | |
194 target_file.close(); | |
195 | |
196 if __name__ == '__main__': | |
197 main() | |
OLD | NEW |