OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # Copyright (c) 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 optparse |
| 8 import os |
| 9 import re |
| 10 import shutil |
| 11 import sys |
| 12 |
| 13 _BASE_REGEX_STRING = '^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)' |
| 14 require_regex = re.compile(_BASE_REGEX_STRING % 'require') |
| 15 provide_regex = re.compile(_BASE_REGEX_STRING % 'provide') |
| 16 |
| 17 # Entry-points required to build a virtual keyboard. |
| 18 namespaces = [ |
| 19 'i18n.input.chrome.inputview.Controller', |
| 20 'i18n.input.chrome.inputview.content.compact.letter', |
| 21 'i18n.input.chrome.inputview.content.compact.util', |
| 22 'i18n.input.chrome.inputview.content.compact.symbol', |
| 23 'i18n.input.chrome.inputview.content.compact.more', |
| 24 'i18n.input.chrome.inputview.content.compact.numberpad', |
| 25 'i18n.input.chrome.inputview.content.ContextlayoutUtil', |
| 26 'i18n.input.chrome.inputview.content.util', |
| 27 'i18n.input.chrome.inputview.EmojiType', |
| 28 'i18n.input.chrome.inputview.layouts.CompactSpaceRow', |
| 29 'i18n.input.chrome.inputview.layouts.RowsOf101', |
| 30 'i18n.input.chrome.inputview.layouts.RowsOf102', |
| 31 'i18n.input.chrome.inputview.layouts.RowsOfCompact', |
| 32 'i18n.input.chrome.inputview.layouts.RowsOfJP', |
| 33 'i18n.input.chrome.inputview.layouts.SpaceRow', |
| 34 'i18n.input.chrome.inputview.layouts.util', |
| 35 'i18n.input.hwt.util'] |
| 36 |
| 37 |
| 38 def ProcessFile(filename): |
| 39 """Extracts provided and required namespaces. |
| 40 |
| 41 Description: |
| 42 Scans Javascript file for provied and required namespaces. |
| 43 |
| 44 Args: |
| 45 filename: name of the file to process. |
| 46 |
| 47 Returns: |
| 48 Pair of lists, where the first list contains namespaces provided by the file |
| 49 and the second contains a list of requirements. |
| 50 """ |
| 51 provides = [] |
| 52 requires = [] |
| 53 file_handle = open(filename, 'r') |
| 54 try: |
| 55 for line in file_handle: |
| 56 if re.match(require_regex, line): |
| 57 requires.append(re.search(require_regex, line).group(1)) |
| 58 if re.match(provide_regex, line): |
| 59 provides.append(re.search(provide_regex, line).group(1)) |
| 60 finally: |
| 61 file_handle.close() |
| 62 return provides, requires |
| 63 |
| 64 |
| 65 def ExpandDirectories(refs): |
| 66 """Expands any directory references into inputs. |
| 67 |
| 68 Description: |
| 69 Looks for any directories in the provided references. Found directories |
| 70 are recursively searched for .js files. |
| 71 |
| 72 Args: |
| 73 refs: a list of directories. |
| 74 |
| 75 Returns: |
| 76 Pair of maps, where the first maps each namepace to the filename that |
| 77 provides the namespace, and the second maps a filename to prerequisite |
| 78 namespaces. |
| 79 """ |
| 80 providers = {} |
| 81 requirements = {} |
| 82 for ref in refs: |
| 83 if os.path.isdir(ref): |
| 84 for (root, dirs, files) in os.walk(ref): |
| 85 for name in files: |
| 86 if name.endswith('js'): |
| 87 filename = os.path.join(root, name) |
| 88 provides, requires = ProcessFile(filename) |
| 89 for p in provides: |
| 90 providers[p] = filename |
| 91 requirements[filename] = [] |
| 92 for r in requires: |
| 93 requirements[filename].append(r) |
| 94 return providers, requirements |
| 95 |
| 96 |
| 97 def ExtractDependencies(namespace, providers, requirements, dependencies): |
| 98 """Recursively extracts all dependencies for a namespace. |
| 99 Description: |
| 100 Recursively extracts all dependencies for a namespace. |
| 101 |
| 102 Args: |
| 103 namespace: The namespace to process. |
| 104 providers: Mapping of namespace to filename that provides the namespace. |
| 105 requireemnts: Mapping of filename to a list of prerequisite namespaces. |
| 106 Returns: |
| 107 """ |
| 108 if namespace in providers: |
| 109 filename = providers[namespace] |
| 110 if not filename in dependencies: |
| 111 for ns in requirements[filename]: |
| 112 ExtractDependencies(ns, providers, requirements, dependencies) |
| 113 dependencies.add(filename) |
| 114 |
| 115 |
| 116 def HomeDir(): |
| 117 """Resolves the user's home directory.""" |
| 118 |
| 119 return os.path.expanduser('~') |
| 120 |
| 121 |
| 122 def ExpandPathRelativeToHome(path): |
| 123 """Resolves a path that is relative to the home directory. |
| 124 |
| 125 Args: |
| 126 path: Relative path. |
| 127 |
| 128 Returns: |
| 129 Resolved path. |
| 130 """ |
| 131 |
| 132 return os.path.join(os.path.expanduser('~'), path) |
| 133 |
| 134 |
| 135 def GetGoogleInputToolsSandboxFromOptions(options): |
| 136 """Generate the input-input-tools path from the --input flag. |
| 137 |
| 138 Args: |
| 139 options: Flags to update.py. |
| 140 Returns: |
| 141 Path to the google-input-tools sandbox. |
| 142 """ |
| 143 |
| 144 path = options.input |
| 145 if not path: |
| 146 path = ExpandPathRelativeToHome('google-input-tools') |
| 147 print 'Unspecified path for google-input-tools. Defaulting to %s' % path |
| 148 return path |
| 149 |
| 150 |
| 151 def GetClosureLibrarySandboxFromOptions(options): |
| 152 """Generate the closure-library path from the --input flag. |
| 153 |
| 154 Args: |
| 155 options: Flags to update.py. |
| 156 Returns: |
| 157 Path to the closure-library sandbox. |
| 158 """ |
| 159 |
| 160 path = options.lib |
| 161 if not path: |
| 162 path = ExpandPathRelativeToHome('closure-library') |
| 163 print 'Unspecified path for closure-library. Defaulting to %s' % path |
| 164 return path |
| 165 |
| 166 |
| 167 def CopyFile(source, target): |
| 168 """Copies a file from the source to the target location. |
| 169 |
| 170 Args: |
| 171 source: Path to the source file to copy. |
| 172 target: Path to the target location to copy the file. |
| 173 """ |
| 174 print '%s --> %s' % (source, target) |
| 175 if not os.path.exists(os.path.dirname(target)): |
| 176 os.makedirs(os.path.dirname(target)) |
| 177 shutil.copy(source, target) |
| 178 |
| 179 |
| 180 def UpdateFile(filename, input_source, closure_source): |
| 181 """Updates files in third_party/google_input_tools. |
| 182 Args: |
| 183 filename: The file to update. |
| 184 input_source: Root of the google_input_tools sandbox. |
| 185 closure_source: Root of the closure_library sandbox. |
| 186 """ |
| 187 target = '' |
| 188 if filename.startswith(input_source): |
| 189 target = os.path.join('src', filename[len(input_source)+1:]) |
| 190 elif filename.startswith(closure_source): |
| 191 target = os.path.join('third_party/closure_library', \ |
| 192 filename[len(closure_source)+1:]) |
| 193 if len(target) > 0: |
| 194 CopyFile(filename, target) |
| 195 |
| 196 |
| 197 def main(): |
| 198 """The entrypoint for this script.""" |
| 199 |
| 200 logging.basicConfig(format='update.py: %(message)s', level=logging.INFO) |
| 201 |
| 202 usage = 'usage: %prog [options] arg' |
| 203 parser = optparse.OptionParser(usage) |
| 204 parser.add_option('-i', |
| 205 '--input', |
| 206 dest='input', |
| 207 action='append', |
| 208 help='Path to the google-input-tools sandbox.') |
| 209 parser.add_option('-l', |
| 210 '--lib', |
| 211 dest='lib', |
| 212 action='store', |
| 213 help='Path to the closure-library sandbox.') |
| 214 |
| 215 (options, args) = parser.parse_args() |
| 216 |
| 217 input_path = GetGoogleInputToolsSandboxFromOptions(options) |
| 218 closure_library_path = GetClosureLibrarySandboxFromOptions(options) |
| 219 |
| 220 print 'iput_path = %s' % input_path |
| 221 print 'closure_library_path = %s' % closure_library_path |
| 222 |
| 223 if not os.path.isdir(input_path): |
| 224 print 'Could not find google-input-tools sandbox.' |
| 225 exit(1) |
| 226 if not os.path.isdir(closure_library_path): |
| 227 print 'Could not find closure-library sandbox.' |
| 228 exit(1) |
| 229 |
| 230 (providers, requirements) = \ |
| 231 ExpandDirectories([os.path.join(input_path, 'chrome'), |
| 232 closure_library_path]) |
| 233 |
| 234 dependencies = set() |
| 235 |
| 236 for name in namespaces: |
| 237 ExtractDependencies(name, providers, requirements, dependencies) |
| 238 |
| 239 for name in dependencies: |
| 240 UpdateFile(name, input_path, closure_library_path) |
| 241 |
| 242 if __name__ == '__main__': |
| 243 main() |
OLD | NEW |