Commit 10278398 authored by kevers's avatar kevers Committed by Commit bot

Add build target for inputview.

BUG=401729

Review URL: https://codereview.chromium.org/676423003

Cr-Commit-Position: refs/heads/master@{#302275}
parent 6352b1f7
...@@ -19,4 +19,12 @@ update.py --input=_path_to_google_input_tools_ --lib=_path_to_closure_lib_ ...@@ -19,4 +19,12 @@ update.py --input=_path_to_google_input_tools_ --lib=_path_to_closure_lib_
Local Modifications: Local Modifications:
Only includes the portion of google-input-tools required to build an inputview- Only includes the portion of google-input-tools required to build an inputview-
based virtual keyboard. based virtual keyboard.
\ No newline at end of file
builder.py: Python script for building inputview.js.
closure.gni: GN template for calling the closure builder.
inputview.gni: Convert build dependencies from gyp to gn format.
inputview.gyp: Build file for generating inputview.js.
inputview.gypi: Autogenerated by update script to define sources for inputview.
update.py: Python script for updating revision of google-input-tools.
#!/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 argparse
import json
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 provided 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 = []
with open(filename, 'r') as file_handle:
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))
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 'provide' and 'require' statements are removed during to export to
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%s' % (name, os.linesep))
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('*/')
else:
formatted = formatted[:start_comment]
comment_block = True
start_comment = -1
if formatted.strip():
target_file.write('%s%s' % (formatted, os.linesep))
finally:
source_file.close()
target_file.write('\n')
def ExtractSources(options):
"""Extracts list of sources based on command line options.
Args:
options: Parsed command line options.
Returns:
List of source files. If the path option is specified then file paths are
absolute. Otherwise, relative paths may be used.
"""
sources = None
if options.json_file:
# Optionally load list of source files from a json file. Useful when the
# list of files to process is too long for the command line.
with open(options.json_file, 'r') as json_file:
data = []
# Strip leading comments.
for line in json_file:
if not line.startswith('#'):
data.append(line)
json_object = json.loads(os.linesep.join(data).replace('\'', '\"'))
path = options.json_sources.split('.')
sources = json_object
for key in path:
sources = sources[key]
if options.path:
sources = [os.path.join(options.path, source) for source in sources]
else:
sources = options.sources
return sources
def main():
"""The entrypoint for this script."""
parser = argparse.ArgumentParser()
parser.add_argument('--sources', nargs='*')
parser.add_argument('--target', nargs=1)
parser.add_argument('--json_file', nargs='?')
parser.add_argument('--json_sources', nargs='?')
parser.add_argument('--path', nargs='?')
options = parser.parse_args()
sources = ExtractSources(options)
assert sources, 'Missing source files.'
providers = {}
requirements = {}
for file in sources:
ExtractDependencies(file, providers, requirements)
with open(options.target[0], 'w') as target_file:
processed = set()
for source_filename in sources:
Export(target_file, source_filename, providers, requirements, processed)
if __name__ == '__main__':
main()
# 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.
template("build_closure") {
assert(defined(invoker.sources))
assert(defined(invoker.target))
action_name = target_name + "_js_gen"
action(action_name) {
script = "//third_party/google_input_tools/builder.py"
sources = invoker.sources
outputs = [invoker.target]
args = ["--target",
rebase_path(invoker.target, root_build_dir)]
if(defined(invoker.json_file)) {
# Optionally parse list of sources from a json file. Useful when the list
# is sufficiently long to create problems with length restrictions on the
# command line.
assert(defined(invoker.json_sources))
args += ["--json_file",
rebase_path(invoker.json_file, root_build_dir),
"--json_sources",
invoker.json_sources]
} else {
# If the number of source files is short, they can be directly extracted
# from the command line.
args += ["--sources"] + sources
}
if(defined(invoker.path)) {
args += ["--path", invoker.path]
}
}
group(target_name) {
deps = [ ":$action_name" ]
}
}
# 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.
inputview_gypi_values = exec_script(
"//build/gypi_to_gn.py",
[ rebase_path("inputview.gypi") ],
"scope",
[ "inputview.gypi" ])
inputview_sources = rebase_path(inputview_gypi_values.inputview_sources)
\ No newline at end of file
# 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.
{
'targets': [
{
'target_name': 'inputview',
'type': 'none',
'includes': [ 'inputview.gypi' ],
'actions': [
{
'action_name': 'inputview',
'inputs': [
'builder.py',
'<@(inputview_sources)',
],
'outputs': [
'<(SHARED_INTERMEDIATE_DIR)/ui/keyboard/resources/inputview.js',
],
'action': [
'python',
'builder.py',
'--target',
'<@(_outputs)',
'--json_file',
'inputview.gypi',
'--json_sources',
'variables.inputview_sources'
],
'message': 'Generating <@(_outputs)'
},
],
},
],
}
\ No newline at end of file
This diff is collapsed.
#!/usr/bin/python #!/usr/bin/python
# Copyright (c) 2014 The Chromium Authors. All rights reserved. # Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be # Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file. # found in the LICENSE file.
import json
import logging import logging
import optparse import optparse
import os import os
...@@ -14,6 +15,14 @@ _BASE_REGEX_STRING = '^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)' ...@@ -14,6 +15,14 @@ _BASE_REGEX_STRING = '^\s*goog\.%s\(\s*[\'"](.+)[\'"]\s*\)'
require_regex = re.compile(_BASE_REGEX_STRING % 'require') require_regex = re.compile(_BASE_REGEX_STRING % 'require')
provide_regex = re.compile(_BASE_REGEX_STRING % 'provide') provide_regex = re.compile(_BASE_REGEX_STRING % 'provide')
preamble = [
'# 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.',
'',
'# This file is auto-generated using update.py.',
'']
# Entry-points required to build a virtual keyboard. # Entry-points required to build a virtual keyboard.
namespaces = [ namespaces = [
'i18n.input.chrome.inputview.Controller', 'i18n.input.chrome.inputview.Controller',
...@@ -171,19 +180,22 @@ def CopyFile(source, target): ...@@ -171,19 +180,22 @@ def CopyFile(source, target):
source: Path to the source file to copy. source: Path to the source file to copy.
target: Path to the target location to copy the file. target: Path to the target location to copy the file.
""" """
print '%s --> %s' % (source, target)
if not os.path.exists(os.path.dirname(target)): if not os.path.exists(os.path.dirname(target)):
os.makedirs(os.path.dirname(target)) os.makedirs(os.path.dirname(target))
shutil.copy(source, target) shutil.copy(source, target)
def UpdateFile(filename, input_source, closure_source): def UpdateFile(filename, input_source, closure_source, target_files):
"""Updates files in third_party/google_input_tools. """Updates files in third_party/google_input_tools.
Args: Args:
filename: The file to update. filename: The file to update.
input_source: Root of the google_input_tools sandbox. input_source: Root of the google_input_tools sandbox.
closure_source: Root of the closure_library sandbox. closure_source: Root of the closure_library sandbox.
target_files: List of relative paths to target files.
""" """
target = '' target = ''
if filename.startswith(input_source): if filename.startswith(input_source):
target = os.path.join('src', filename[len(input_source)+1:]) target = os.path.join('src', filename[len(input_source)+1:])
...@@ -192,6 +204,22 @@ def UpdateFile(filename, input_source, closure_source): ...@@ -192,6 +204,22 @@ def UpdateFile(filename, input_source, closure_source):
filename[len(closure_source)+1:]) filename[len(closure_source)+1:])
if len(target) > 0: if len(target) > 0:
CopyFile(filename, target) CopyFile(filename, target)
target_files.append(os.path.relpath(target, os.getcwd()))
def GenerateBuildFile(target_files):
"""Updates inputview.gypi.
Args:
target_files: List of files required to build inputview.js.
"""
sorted_files = sorted(target_files)
with open('inputview.gypi', 'w') as file_handle:
file_handle.write(os.linesep.join(preamble))
json_data = {'variables': {'inputview_sources': sorted_files}}
json_str = json.dumps(json_data, indent=2, separators=(',', ': '))
file_handle.write(json_str.replace('\"', '\''))
def main(): def main():
...@@ -217,9 +245,6 @@ def main(): ...@@ -217,9 +245,6 @@ def main():
input_path = GetGoogleInputToolsSandboxFromOptions(options) input_path = GetGoogleInputToolsSandboxFromOptions(options)
closure_library_path = GetClosureLibrarySandboxFromOptions(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): if not os.path.isdir(input_path):
print 'Could not find google-input-tools sandbox.' print 'Could not find google-input-tools sandbox.'
exit(1) exit(1)
...@@ -232,12 +257,14 @@ def main(): ...@@ -232,12 +257,14 @@ def main():
closure_library_path]) closure_library_path])
dependencies = set() dependencies = set()
for name in namespaces: for name in namespaces:
ExtractDependencies(name, providers, requirements, dependencies) ExtractDependencies(name, providers, requirements, dependencies)
target_files = []
for name in dependencies: for name in dependencies:
UpdateFile(name, input_path, closure_library_path) UpdateFile(name, input_path, closure_library_path, target_files)
GenerateBuildFile(target_files)
if __name__ == '__main__': if __name__ == '__main__':
main() main()
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
# found in the LICENSE file. # found in the LICENSE file.
import("//mojo/public/tools/bindings/mojom.gni") import("//mojo/public/tools/bindings/mojom.gni")
import("//third_party/google_input_tools/closure.gni")
import("//third_party/google_input_tools/inputview.gni")
import("//tools/grit/grit_rule.gni") import("//tools/grit/grit_rule.gni")
component("keyboard") { component("keyboard") {
...@@ -78,6 +80,7 @@ grit("resources_grit") { ...@@ -78,6 +80,7 @@ grit("resources_grit") {
deps = [ deps = [
":keyboard_mojom_bindings", ":keyboard_mojom_bindings",
":inputview"
] ]
} }
...@@ -87,6 +90,14 @@ copy("resources") { ...@@ -87,6 +90,14 @@ copy("resources") {
public_deps = [ ":resources_grit" ] public_deps = [ ":resources_grit" ]
} }
build_closure("inputview") {
sources = inputview_sources
target = "$target_gen_dir/resources/inputview.js"
json_file = "//third_party/google_input_tools/inputview.gypi"
json_sources = "variables.inputview_sources"
path = rebase_path("//third_party/google_input_tools")
}
test("keyboard_unittests") { test("keyboard_unittests") {
sources = [ sources = [
"test/run_all_unittests.cc", "test/run_all_unittests.cc",
......
...@@ -19,7 +19,10 @@ ...@@ -19,7 +19,10 @@
{ {
# GN version: //ui/keyboard:resources # GN version: //ui/keyboard:resources
'target_name': 'keyboard_resources', 'target_name': 'keyboard_resources',
'dependencies': [ 'keyboard_mojom_bindings', ], 'dependencies': [
'keyboard_mojom_bindings',
'../../third_party/google_input_tools/inputview.gyp:inputview',
],
'type': 'none', 'type': 'none',
'variables': { 'variables': {
'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/ui/keyboard', 'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/ui/keyboard',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment