Index: third_party/google_input_tools/builder.py |
diff --git a/third_party/google_input_tools/builder.py b/third_party/google_input_tools/builder.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..27ac64b239dd62ca39b732f653e9bb600f122bcf |
--- /dev/null |
+++ b/third_party/google_input_tools/builder.py |
@@ -0,0 +1,197 @@ |
+#!/usr/bin/python |
+# Copyright 2014 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+#import logging |
+import os |
+import re |
+import sys |
+ |
+_BASE_REGEX_STRING = '^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)' |
+require_regex = re.compile(_BASE_REGEX_STRING % 'require') |
+provide_regex = re.compile(_BASE_REGEX_STRING % 'provide') |
+ |
+ |
+def ProcessFile(filename): |
+ """Extracts provided and required namespaces. |
+ |
+ Description: |
+ 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.
|
+ |
+ Args: |
+ filename: name of the file to process. |
+ |
+ Returns: |
+ Pair of lists, where the first list contains namespaces provided by the file |
+ and the second contains a list of requirements. |
+ """ |
+ |
+ provides = [] |
+ requires = [] |
+ file_handle = open(filename, 'r') |
+ 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.
|
+ 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
|
+ if re.match(require_regex, line): |
+ 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
|
+ if re.match(provide_regex, line): |
+ provides.append(re.search(provide_regex, line).group(1)) |
+ finally: |
+ file_handle.close() |
+ return provides, requires |
+ |
+ |
+def ExtractDependencies(filename, providers, requirements): |
+ """Extracts provided and required namespaces for a file. |
+ |
+ Description: |
+ Updates maps for namespace providers and file prerequisites. |
+ |
+ Args: |
+ filename: Path of the file to process. |
+ providers: Mapping of namespace to filename that provides the namespace. |
+ requirements: Mapping of filename to a list of prerequisite namespaces. |
+ """ |
+ |
+ p, r = ProcessFile(filename) |
+ |
+ for name in p: |
+ providers[name] = filename |
+ for name in r: |
+ if not filename in requirements: |
+ requirements[filename] = [] |
+ requirements[filename].append(name) |
+ |
+ |
+def Export(target_file, source_filename, providers, requirements, processed): |
+ """Writes the contents of a file. |
+ |
+ Description: |
+ Appends the contents of the source file to the target file. In order to |
+ preserve proper dependencies, each file has its required namespaces |
+ processed before exporting the source file itself. The set of exported files |
+ is tracked to guard against multiple exports of the same file. Comments as |
+ 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.
|
+ reduce file size. |
+ |
+ Args: |
+ target_file: Handle to target file for export. |
+ source_filename: Name of the file to export. |
+ providers: Map of namespace to filename. |
+ requirements: Map of filename to required namespaces. |
+ processed: Set of processed files. |
+ Returns: |
+ """ |
+ |
+ # Filename may have already been processed if it was a requirement of a |
+ # previous exported file. |
+ if source_filename in processed: |
+ return |
+ |
+ # Export requirements before file. |
+ if source_filename in requirements: |
+ for namespace in requirements[source_filename]: |
+ if namespace in providers: |
+ dependency = providers[namespace] |
+ if dependency: |
+ Export(target_file, dependency, providers, requirements, processed) |
+ |
+ # Export file |
+ processed.add(source_filename) |
+ for name in providers: |
+ if providers[name] == source_filename: |
+ 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.
|
+ source_file = open(source_filename, 'r') |
+ try: |
+ comment_block = False |
+ for line in source_file: |
+ # Skip require and provide statements. |
+ if (not re.match(require_regex, line) and not |
+ re.match(provide_regex, line)): |
+ formatted = line.rstrip() |
+ if comment_block: |
+ # Scan for trailing */ in multi-line comment. |
+ index = formatted.find('*/') |
+ if index >= 0: |
+ formatted = formatted[index + 2:] |
+ comment_block = False |
+ else: |
+ formatted = '' |
+ # Remove // style comments. |
+ index = formatted.find('//') |
+ if index >= 0: |
+ formatted = formatted[:index] |
+ # Remove /* */ style comments. |
+ start_comment = formatted.find('/*') |
+ end_comment = formatted.find('*/') |
+ while start_comment >= 0: |
+ if end_comment > start_comment: |
+ formatted = (formatted[:start_comment] |
+ + formatted[end_comment + 2:]) |
+ start_comment = formatted.find('/*') |
+ 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
|
+ else: |
+ formatted = formatted[:start_comment] |
+ comment_block = True |
+ start_comment = -1 |
+ 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.
|
+ target_file.write('%s\n' % formatted) |
+ finally: |
+ source_file.close() |
+ target_file.write('\n') |
+ |
+ |
+def GetTargetFile(arguments): |
+ """Extracts target file from the argument list. |
+ |
+ Args: |
+ arguments: List of command line arguments. |
+ """ |
+ |
+ for i in range(len(arguments)): |
+ if arguments[i] == '--target': |
+ 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.
|
+ return None |
+ |
+ |
+def GetSourceFiles(arguments): |
+ """Extract list if source files from the argument list. |
+ |
+ Args: |
+ arguments: List of command line arguments. |
+ """ |
+ |
+ sources = [] |
+ start_index = -1 |
+ 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.
|
+ if arguments[i] == '--sources': |
+ start_index = i + 1 |
+ break |
+ if start_index < 0: |
+ return None |
+ for i in range(start_index, len(arguments)): |
+ sources.append(arguments[i]) |
+ return sources |
+ |
+ |
+def main(): |
+ """The entrypoint for this script.""" |
+ |
+ 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.
|
+ sources = GetSourceFiles(sys.argv) |
+ |
+ providers = {} |
+ requirements = {} |
+ for file in sources: |
+ ExtractDependencies(file, providers, requirements) |
+ |
+ target_file = open(target, 'w') |
+ try: |
+ processed = set() |
+ for source_filename in sources: |
+ Export(target_file, source_filename, providers, requirements, processed) |
+ finally: |
+ target_file.close(); |
+ |
+if __name__ == '__main__': |
+ main() |