Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / third_party / google_input_tools / update.py
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 json
7 import logging
8 import optparse
9 import os
10 import re
11 import shutil
12 import subprocess
13 import sys
14
15 _BASE_REGEX_STRING = '^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)'
16 require_regex = re.compile(_BASE_REGEX_STRING % 'require')
17 provide_regex = re.compile(_BASE_REGEX_STRING % 'provide')
18
19 preamble = [
20   '# Copyright 2014 The Chromium Authors. All rights reserved.',
21   '# Use of this source code is governed by a BSD-style license that can be',
22   '# found in the LICENSE file.',
23   '',
24   '# This file is auto-generated using update.py.',
25   '']
26
27 # Entry-points required to build a virtual keyboard.
28 namespaces = [
29   'i18n.input.chrome.inputview.Controller',
30   'i18n.input.chrome.inputview.content.compact.letter',
31   'i18n.input.chrome.inputview.content.compact.util',
32   'i18n.input.chrome.inputview.content.compact.symbol',
33   'i18n.input.chrome.inputview.content.compact.more',
34   'i18n.input.chrome.inputview.content.compact.numberpad',
35   'i18n.input.chrome.inputview.content.ContextlayoutUtil',
36   'i18n.input.chrome.inputview.content.util',
37   'i18n.input.chrome.inputview.EmojiType',
38   'i18n.input.chrome.inputview.layouts.CompactSpaceRow',
39   'i18n.input.chrome.inputview.layouts.RowsOf101',
40   'i18n.input.chrome.inputview.layouts.RowsOf102',
41   'i18n.input.chrome.inputview.layouts.RowsOfCompact',
42   'i18n.input.chrome.inputview.layouts.RowsOfJP',
43   'i18n.input.chrome.inputview.layouts.SpaceRow',
44   'i18n.input.chrome.inputview.layouts.util',
45   'i18n.input.hwt.util']
46
47 # Any additional required files.
48 extras = [
49   'common.css',
50   'emoji.css'
51 ]
52
53 def ProcessFile(filename):
54   """Extracts provided and required namespaces.
55
56   Description:
57     Scans Javascript file for provied and required namespaces.
58
59   Args:
60     filename: name of the file to process.
61
62   Returns:
63     Pair of lists, where the first list contains namespaces provided by the file
64     and the second contains a list of requirements.
65   """
66   provides = []
67   requires = []
68   file_handle = open(filename, 'r')
69   try:
70     for line in file_handle:
71       if re.match(require_regex, line):
72         requires.append(re.search(require_regex, line).group(1))
73       if re.match(provide_regex, line):
74         provides.append(re.search(provide_regex, line).group(1))
75   finally:
76     file_handle.close()
77   return provides, requires
78
79
80 def ExpandDirectories(refs):
81   """Expands any directory references into inputs.
82
83   Description:
84     Looks for any directories in the provided references.  Found directories
85     are recursively searched for .js files.
86
87   Args:
88     refs: a list of directories.
89
90   Returns:
91     Pair of maps, where the first maps each namepace to the filename that
92     provides the namespace, and the second maps a filename to prerequisite
93     namespaces.
94   """
95   providers = {}
96   requirements = {}
97   for ref in refs:
98     if os.path.isdir(ref):
99       for (root, dirs, files) in os.walk(ref):
100         for name in files:
101           if name.endswith('js'):
102             filename = os.path.join(root, name)
103             provides, requires = ProcessFile(filename)
104             for p in provides:
105               providers[p] = filename
106             requirements[filename] = []
107             for r in requires:
108               requirements[filename].append(r)
109   return providers, requirements
110
111
112 def ExtractDependencies(namespace, providers, requirements, dependencies):
113   """Recursively extracts all dependencies for a namespace.
114   Description:
115     Recursively extracts all dependencies for a namespace.
116
117   Args:
118     namespace: The namespace to process.
119     providers: Mapping of namespace to filename that provides the namespace.
120     requireemnts: Mapping of filename to a list of prerequisite namespaces.
121   Returns:
122   """
123   if namespace in providers:
124     filename = providers[namespace]
125     if not filename in dependencies:
126       for ns in requirements[filename]:
127         ExtractDependencies(ns, providers, requirements, dependencies)
128     dependencies.add(filename)
129
130
131 def HomeDir():
132   """Resolves the user's home directory."""
133
134   return os.path.expanduser('~')
135
136
137 def ExpandPathRelativeToHome(path):
138    """Resolves a path that is relative to the home directory.
139
140    Args: 
141      path: Relative path.
142
143    Returns:
144      Resolved path.
145    """
146
147    return os.path.join(os.path.expanduser('~'), path)
148
149
150 def GetGoogleInputToolsSandboxFromOptions(options):
151   """Generate the input-input-tools path from the --input flag.
152
153   Args:
154     options: Flags to update.py.
155   Returns:
156     Path to the google-input-tools sandbox.
157   """
158
159   path = options.input
160   if not path:
161     path = ExpandPathRelativeToHome('google-input-tools')
162     print 'Unspecified path for google-input-tools. Defaulting to %s' % path
163   return path
164
165
166 def GetClosureLibrarySandboxFromOptions(options):
167   """Generate the closure-library path from the --input flag.
168
169   Args:
170     options: Flags to update.py.
171   Returns:
172     Path to the closure-library sandbox.
173   """
174
175   path = options.lib
176   if not path:
177     path = ExpandPathRelativeToHome('closure-library')
178     print 'Unspecified path for closure-library. Defaulting to %s' % path
179   return path
180
181
182 def CopyFile(source, target):
183   """Copies a file from the source to the target location.
184
185   Args:
186     source: Path to the source file to copy.
187     target: Path to the target location to copy the file.
188   """
189
190   if not os.path.exists(os.path.dirname(target)):
191     os.makedirs(os.path.dirname(target))
192   shutil.copy(source, target)
193   # Ensure correct file permissions.
194   if target.endswith('py'):
195     subprocess.call(['chmod', '+x', target])
196   else:
197     subprocess.call(['chmod', '-x', target])
198
199
200 def UpdateFile(filename, input_source, closure_source, target_files):
201     """Updates files in third_party/google_input_tools.
202
203     Args:
204       filename: The file to update.
205       input_source: Root of the google_input_tools sandbox.
206       closure_source: Root of the closure_library sandbox.
207       target_files: List of relative paths to target files.
208     """
209
210     target = ''
211     if filename.startswith(input_source):
212       target = os.path.join('src', filename[len(input_source)+1:])
213     elif filename.startswith(closure_source):
214       target = os.path.join('third_party/closure_library', \
215                             filename[len(closure_source)+1:])
216     if len(target) > 0:
217       CopyFile(filename, target)
218       target_files.append(os.path.relpath(target, os.getcwd()))
219
220
221 def GenerateBuildFile(target_files):
222   """Updates inputview.gypi.
223
224   Args:
225     target_files: List of files required to build inputview.js.
226   """
227
228   sorted_files = sorted(target_files)
229   with open('inputview.gypi', 'w') as file_handle:
230     file_handle.write(os.linesep.join(preamble))
231     json_data = {'variables': {'inputview_sources': sorted_files}}
232     json_str = json.dumps(json_data, indent=2, separators=(',', ': '))
233     file_handle.write(json_str.replace('\"', '\''))
234
235
236 def CopyDir(input_path, sub_dir):
237   """Copies all files in a subdirectory of google-input-tools.
238
239   Description:
240     Recursive copy of a directory under google-input-tools.  Used to copy
241     localization and resource files.
242
243   Args:
244     input_path: Path to the google-input-tools-sandbox.
245   """
246   dir = os.path.join(input_path, "chrome", "os", "inputview", sub_dir)
247   for (root, dirs, files) in os.walk(dir):
248     for name in files:
249       filename = os.path.join(root, name)
250       relative_path = filename[len(dir) + 1:]
251       target = os.path.join('src', 'chrome', 'os', 'inputview', sub_dir,
252                        relative_path)
253       CopyFile(filename, target)
254
255
256 def main():
257   """The entrypoint for this script."""
258
259   logging.basicConfig(format='update.py: %(message)s', level=logging.INFO)
260
261   usage = 'usage: %prog [options] arg'
262   parser = optparse.OptionParser(usage)
263   parser.add_option('-i',
264                     '--input',
265                     dest='input',
266                     action='append',
267                     help='Path to the google-input-tools sandbox.')
268   parser.add_option('-l',
269                      '--lib',
270                      dest='lib',
271                      action='store',
272                      help='Path to the closure-library sandbox.')
273
274   (options, args) = parser.parse_args()
275
276   input_path = GetGoogleInputToolsSandboxFromOptions(options)
277   closure_library_path = GetClosureLibrarySandboxFromOptions(options)
278
279   if not os.path.isdir(input_path):
280     print 'Could not find google-input-tools sandbox.'
281     exit(1)
282   if not os.path.isdir(closure_library_path):
283     print 'Could not find closure-library sandbox.'
284     exit(1)
285
286   (providers, requirements) = \
287       ExpandDirectories([os.path.join(input_path, 'chrome'),
288                          closure_library_path])
289
290   dependencies = set()
291   for name in namespaces:
292     ExtractDependencies(name, providers, requirements, dependencies)
293
294   target_files = []
295   for name in dependencies:
296     UpdateFile(name, input_path, closure_library_path, target_files)
297
298   GenerateBuildFile(target_files)
299
300   # Copy resources
301   CopyDir(input_path, "_locales")
302   CopyDir(input_path, "images")
303   CopyDir(input_path, 'config')
304   CopyDir(input_path, 'layouts')
305   CopyDir(input_path, 'sounds')
306
307   # Copy extra support files.
308   for name in extras:
309     source = os.path.join(input_path, 'chrome', 'os', 'inputview', name)
310     target = os.path.join('src', 'chrome', 'os', 'inputview', name)
311     CopyFile(source ,target)
312
313
314 if __name__ == '__main__':
315   main()