Index: third_party/google_input_tools/update.py |
diff --git a/third_party/google_input_tools/update.py b/third_party/google_input_tools/update.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..ce0e79fdba8aaded71389da2bc582a61b62ffe4d |
--- /dev/null |
+++ b/third_party/google_input_tools/update.py |
@@ -0,0 +1,243 @@ |
+#!/usr/bin/python |
+# Copyright (c) 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 optparse |
+import os |
+import re |
+import shutil |
+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') |
+ |
+# Entry-points required to build a virtual keyboard. |
+namespaces = [ |
+ 'i18n.input.chrome.inputview.Controller', |
+ 'i18n.input.chrome.inputview.content.compact.letter', |
+ 'i18n.input.chrome.inputview.content.compact.util', |
+ 'i18n.input.chrome.inputview.content.compact.symbol', |
+ 'i18n.input.chrome.inputview.content.compact.more', |
+ 'i18n.input.chrome.inputview.content.compact.numberpad', |
+ 'i18n.input.chrome.inputview.content.ContextlayoutUtil', |
+ 'i18n.input.chrome.inputview.content.util', |
+ 'i18n.input.chrome.inputview.EmojiType', |
+ 'i18n.input.chrome.inputview.layouts.CompactSpaceRow', |
+ 'i18n.input.chrome.inputview.layouts.RowsOf101', |
+ 'i18n.input.chrome.inputview.layouts.RowsOf102', |
+ 'i18n.input.chrome.inputview.layouts.RowsOfCompact', |
+ 'i18n.input.chrome.inputview.layouts.RowsOfJP', |
+ 'i18n.input.chrome.inputview.layouts.SpaceRow', |
+ 'i18n.input.chrome.inputview.layouts.util', |
+ 'i18n.input.hwt.util'] |
+ |
+ |
+def ProcessFile(filename): |
+ """Extracts provided and required namespaces. |
+ |
+ Description: |
+ Scans Javascript file for provied and required namespaces. |
+ |
+ 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: |
+ for line in file_handle: |
+ if re.match(require_regex, line): |
+ requires.append(re.search(require_regex, line).group(1)) |
+ if re.match(provide_regex, line): |
+ provides.append(re.search(provide_regex, line).group(1)) |
+ finally: |
+ file_handle.close() |
+ return provides, requires |
+ |
+ |
+def ExpandDirectories(refs): |
+ """Expands any directory references into inputs. |
+ |
+ Description: |
+ Looks for any directories in the provided references. Found directories |
+ are recursively searched for .js files. |
+ |
+ Args: |
+ refs: a list of directories. |
+ |
+ Returns: |
+ Pair of maps, where the first maps each namepace to the filename that |
+ provides the namespace, and the second maps a filename to prerequisite |
+ namespaces. |
+ """ |
+ providers = {} |
+ requirements = {} |
+ for ref in refs: |
+ if os.path.isdir(ref): |
+ for (root, dirs, files) in os.walk(ref): |
+ for name in files: |
+ if name.endswith('js'): |
+ filename = os.path.join(root, name) |
+ provides, requires = ProcessFile(filename) |
+ for p in provides: |
+ providers[p] = filename |
+ requirements[filename] = [] |
+ for r in requires: |
+ requirements[filename].append(r) |
+ return providers, requirements |
+ |
+ |
+def ExtractDependencies(namespace, providers, requirements, dependencies): |
+ """Recursively extracts all dependencies for a namespace. |
+ Description: |
+ Recursively extracts all dependencies for a namespace. |
+ |
+ Args: |
+ namespace: The namespace to process. |
+ providers: Mapping of namespace to filename that provides the namespace. |
+ requireemnts: Mapping of filename to a list of prerequisite namespaces. |
+ Returns: |
+ """ |
+ if namespace in providers: |
+ filename = providers[namespace] |
+ if not filename in dependencies: |
+ for ns in requirements[filename]: |
+ ExtractDependencies(ns, providers, requirements, dependencies) |
+ dependencies.add(filename) |
+ |
+ |
+def HomeDir(): |
+ """Resolves the user's home directory.""" |
+ |
+ return os.path.expanduser('~') |
+ |
+ |
+def ExpandPathRelativeToHome(path): |
+ """Resolves a path that is relative to the home directory. |
+ |
+ Args: |
+ path: Relative path. |
+ |
+ Returns: |
+ Resolved path. |
+ """ |
+ |
+ return os.path.join(os.path.expanduser('~'), path) |
+ |
+ |
+def GetGoogleInputToolsSandboxFromOptions(options): |
+ """Generate the input-input-tools path from the --input flag. |
+ |
+ Args: |
+ options: Flags to update.py. |
+ Returns: |
+ Path to the google-input-tools sandbox. |
+ """ |
+ |
+ path = options.input |
+ if not path: |
+ path = ExpandPathRelativeToHome('google-input-tools') |
+ print 'Unspecified path for google-input-tools. Defaulting to %s' % path |
+ return path |
+ |
+ |
+def GetClosureLibrarySandboxFromOptions(options): |
+ """Generate the closure-library path from the --input flag. |
+ |
+ Args: |
+ options: Flags to update.py. |
+ Returns: |
+ Path to the closure-library sandbox. |
+ """ |
+ |
+ path = options.lib |
+ if not path: |
+ path = ExpandPathRelativeToHome('closure-library') |
+ print 'Unspecified path for closure-library. Defaulting to %s' % path |
+ return path |
+ |
+ |
+def CopyFile(source, target): |
+ """Copies a file from the source to the target location. |
+ |
+ Args: |
+ source: Path to the source file to copy. |
+ target: Path to the target location to copy the file. |
+ """ |
+ print '%s --> %s' % (source, target) |
+ if not os.path.exists(os.path.dirname(target)): |
+ os.makedirs(os.path.dirname(target)) |
+ shutil.copy(source, target) |
+ |
+ |
+def UpdateFile(filename, input_source, closure_source): |
+ """Updates files in third_party/google_input_tools. |
+ Args: |
+ filename: The file to update. |
+ input_source: Root of the google_input_tools sandbox. |
+ closure_source: Root of the closure_library sandbox. |
+ """ |
+ target = '' |
+ if filename.startswith(input_source): |
+ target = os.path.join('src', filename[len(input_source)+1:]) |
+ elif filename.startswith(closure_source): |
+ target = os.path.join('third_party/closure_library', \ |
+ filename[len(closure_source)+1:]) |
+ if len(target) > 0: |
+ CopyFile(filename, target) |
+ |
+ |
+def main(): |
+ """The entrypoint for this script.""" |
+ |
+ logging.basicConfig(format='update.py: %(message)s', level=logging.INFO) |
+ |
+ usage = 'usage: %prog [options] arg' |
+ parser = optparse.OptionParser(usage) |
+ parser.add_option('-i', |
+ '--input', |
+ dest='input', |
+ action='append', |
+ help='Path to the google-input-tools sandbox.') |
+ parser.add_option('-l', |
+ '--lib', |
+ dest='lib', |
+ action='store', |
+ help='Path to the closure-library sandbox.') |
+ |
+ (options, args) = parser.parse_args() |
+ |
+ input_path = GetGoogleInputToolsSandboxFromOptions(options) |
+ closure_library_path = GetClosureLibrarySandboxFromOptions(options) |
+ |
+ print 'iput_path = %s' % input_path |
+ print 'closure_library_path = %s' % closure_library_path |
+ |
+ if not os.path.isdir(input_path): |
+ print 'Could not find google-input-tools sandbox.' |
+ exit(1) |
+ if not os.path.isdir(closure_library_path): |
+ print 'Could not find closure-library sandbox.' |
+ exit(1) |
+ |
+ (providers, requirements) = \ |
+ ExpandDirectories([os.path.join(input_path, 'chrome'), |
+ closure_library_path]) |
+ |
+ dependencies = set() |
+ |
+ for name in namespaces: |
+ ExtractDependencies(name, providers, requirements, dependencies) |
+ |
+ for name in dependencies: |
+ UpdateFile(name, input_path, closure_library_path) |
+ |
+if __name__ == '__main__': |
+ main() |