Chromium Code Reviews| 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() |