diff options
author | lfg <lfg@chromium.org> | 2014-08-28 20:56:28 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-08-29 03:58:01 +0000 |
commit | 8a1bee36d9f609ab9a98ecf89bf1dfc0bb4762dc (patch) | |
tree | 98801b1699e47204b60186ec5619e1ba9a492157 | |
parent | 792dcd9ba6050f1dce72f9a7e1961e0f0ceabc2c (diff) | |
download | chromium_src-8a1bee36d9f609ab9a98ecf89bf1dfc0bb4762dc.zip chromium_src-8a1bee36d9f609ab9a98ecf89bf1dfc0bb4762dc.tar.gz chromium_src-8a1bee36d9f609ab9a98ecf89bf1dfc0bb4762dc.tar.bz2 |
- Add support for references in different paths in apis.
- Move ImageDetails from chrome to extensions.
BUG=352290
Review URL: https://codereview.chromium.org/487533005
Cr-Commit-Position: refs/heads/master@{#292567}
23 files changed, 246 insertions, 111 deletions
diff --git a/build/json_schema_bundle_compile.gypi b/build/json_schema_bundle_compile.gypi index 7560bdc..a302013 100644 --- a/build/json_schema_bundle_compile.gypi +++ b/build/json_schema_bundle_compile.gypi @@ -7,6 +7,11 @@ # When including this gypi, the following variables must be set: # schema_files: # An array of json or idl files that comprise the api model. + # schema_include_rules (optional): + # An array of paths to include when searching for referenced objects, + # with the namespace separated by a :. + # Example: + # [ '/foo/bar:Foo::Bar::%(namespace)s' ] # cc_dir: # The directory to put the generated code in. # root_namespace: @@ -32,6 +37,7 @@ '<(api_gen_dir)/model.py', '<(api_gen_dir)/util_cc_helper.py', ], + 'schema_include_rules': [], }, 'actions': [ { @@ -52,6 +58,7 @@ '--destdir=<(SHARED_INTERMEDIATE_DIR)', '--namespace=<(root_namespace)', '--generator=cpp-bundle-schema', + '--include-rules=<(schema_include_rules)', '<@(schema_files)', '<@(non_compiled_schema_files)', ], diff --git a/build/json_schema_compile.gypi b/build/json_schema_compile.gypi index 9672f79..9952e20 100644 --- a/build/json_schema_compile.gypi +++ b/build/json_schema_compile.gypi @@ -7,6 +7,11 @@ # When including this gypi, the following variables must be set: # schema_files: # An array of json or idl files that comprise the api model. + # schema_include_rules (optional): + # An array of paths to include when searching for referenced objects, + # with the namespace separated by a :. + # Example: + # [ '/foo/bar:Foo::Bar::%(namespace)s' ] # cc_dir: # The directory to put the generated code in. # root_namespace: @@ -17,6 +22,7 @@ # Functions and namespaces can be excluded by setting "nocompile" to true. 'api_gen_dir': '<(DEPTH)/tools/json_schema_compiler', 'api_gen': '<(api_gen_dir)/compiler.py', + 'schema_include_rules': [], }, 'rules': [ { @@ -54,6 +60,7 @@ '--destdir=<(SHARED_INTERMEDIATE_DIR)', '--namespace=<(root_namespace)', '--generator=cpp', + '--include-rules=<(schema_include_rules)' ], 'message': 'Generating C++ code from <(RULE_INPUT_PATH) json files', 'process_outputs_as_sources': 1, @@ -92,6 +99,7 @@ '--destdir=<(SHARED_INTERMEDIATE_DIR)', '--namespace=<(root_namespace)', '--generator=cpp', + '--include-rules=<(schema_include_rules)' ], 'message': 'Generating C++ code from <(RULE_INPUT_PATH) IDL files', 'process_outputs_as_sources': 1, diff --git a/chrome/browser/extensions/api/capture_web_contents_function.h b/chrome/browser/extensions/api/capture_web_contents_function.h index 0a1c741..0f3b9db 100644 --- a/chrome/browser/extensions/api/capture_web_contents_function.h +++ b/chrome/browser/extensions/api/capture_web_contents_function.h @@ -6,7 +6,7 @@ #define CHROME_BROWSER_EXTENSIONS_API_CAPTURE_WEB_CONTENTS_FUNCTION_H_ #include "chrome/browser/extensions/chrome_extension_function.h" -#include "chrome/common/extensions/api/types.h" +#include "extensions/common/api/extension_types.h" class SkBitmap; @@ -40,7 +40,7 @@ class CaptureWebContentsFunction : public ChromeAsyncExtensionFunction { virtual void OnCaptureFailure(FailureReason reason) = 0; private: - typedef api::types::ImageDetails ImageDetails; + typedef core_api::extension_types::ImageDetails ImageDetails; void CopyFromBackingStoreComplete(bool succeed, const SkBitmap& bitmap); void OnCaptureSuccess(const SkBitmap& bitmap); diff --git a/chrome/common/extensions/api/BUILD.gn b/chrome/common/extensions/api/BUILD.gn index 469227d..c74335f 100644 --- a/chrome/common/extensions/api/BUILD.gn +++ b/chrome/common/extensions/api/BUILD.gn @@ -9,6 +9,8 @@ import("schemas.gni") generated_extensions_api("api") { schemas = true bundle = true + + deps = schema_dependencies } # GYP version: chrome/browser/extensions/api/api.gyp:chrome_api_registration @@ -32,4 +34,5 @@ generated_extensions_api("api_registration") { if (is_chromeos) { # deps += [ "<(DEPTH)/chrome/chrome.gyp:drive_proto" ] TODO(GYP) } + deps += schema_dependencies } diff --git a/chrome/common/extensions/api/api.gyp b/chrome/common/extensions/api/api.gyp index 19b28fa..da226f7 100644 --- a/chrome/common/extensions/api/api.gyp +++ b/chrome/common/extensions/api/api.gyp @@ -18,6 +18,9 @@ '../../../../build/json_schema_compile.gypi', 'schemas.gypi', ], + 'dependencies': [ + '<@(schema_dependencies)', + ], }, ], } diff --git a/chrome/common/extensions/api/schemas.gni b/chrome/common/extensions/api/schemas.gni index a8a8b41..9a43246 100644 --- a/chrome/common/extensions/api/schemas.gni +++ b/chrome/common/extensions/api/schemas.gni @@ -29,3 +29,6 @@ if (!is_android) { } root_namespace = "extensions::api::%(namespace)s" +schema_include_rules = + "extensions/common/api:extensions::core_api::%(namespace)s" +schema_dependencies = [ "//extensions/common/api" ] diff --git a/chrome/common/extensions/api/schemas.gypi b/chrome/common/extensions/api/schemas.gypi index b7b9d17..4e7b234 100644 --- a/chrome/common/extensions/api/schemas.gypi +++ b/chrome/common/extensions/api/schemas.gypi @@ -116,6 +116,9 @@ 'web_view_internal.json', 'windows.json', ], + 'main_schema_include_rules': [ + 'extensions/common/api:extensions::core_api::%(namespace)s', + ], 'main_non_compiled_schema_files': [ 'browsing_data.json', 'chromeos_info_private.json', @@ -157,12 +160,20 @@ 'non_compiled_schema_files': [ '<@(main_non_compiled_schema_files)', ], + 'schema_dependencies': [ + '<(DEPTH)/extensions/common/api/api.gyp:extensions_api', + ], 'schema_files': [ '<@(main_schema_files)', ], + 'schema_include_rules': [ + '<@(main_schema_include_rules)', + ], }, { # enable_extensions==0 'non_compiled_schema_files': [ ], + 'schema_dependencies': [ + ], 'schema_files': [ # These should be eliminated. See crbug.com/305852. '<@(android_schema_files)', diff --git a/chrome/common/extensions/api/tabs.json b/chrome/common/extensions/api/tabs.json index 931a293..f3c9348 100644 --- a/chrome/common/extensions/api/tabs.json +++ b/chrome/common/extensions/api/tabs.json @@ -654,7 +654,7 @@ "description": "The target window. Defaults to the <a href='windows#current-window'>current window</a>." }, { - "$ref": "types.ImageDetails", + "$ref": "extensionTypes.ImageDetails", "name": "options", "optional": true }, diff --git a/chrome/common/extensions/api/types.json b/chrome/common/extensions/api/types.json index 80f8c6a..1a7c306 100644 --- a/chrome/common/extensions/api/types.json +++ b/chrome/common/extensions/api/types.json @@ -150,26 +150,6 @@ ] } ] - }, - { - "id": "ImageDetails", - "type": "object", - "description": "Details about the format and quality of an image.", - "properties": { - "format": { - "type": "string", - "optional": true, - "enum": ["jpeg", "png"], - "description": "The format of the resulting image. Default is <code>\"jpeg\"</code>." - }, - "quality": { - "type": "integer", - "optional": true, - "minimum": 0, - "maximum": 100, - "description": "When format is <code>\"jpeg\"</code>, controls the quality of the resulting image. This value is ignored for PNG images. As quality is decreased, the resulting image will have more visual artifacts, and the number of bytes needed to store it will decrease." - } - } } ] } diff --git a/chrome/common/extensions/api/web_view_internal.json b/chrome/common/extensions/api/web_view_internal.json index c09c126..a05e860 100644 --- a/chrome/common/extensions/api/web_view_internal.json +++ b/chrome/common/extensions/api/web_view_internal.json @@ -412,7 +412,7 @@ "description": "The instance ID of the guest <webview> process." }, { - "$ref": "types.ImageDetails", + "$ref": "extensionTypes.ImageDetails", "name": "options", "optional": true }, diff --git a/extensions/common/api/extension_types.json b/extensions/common/api/extension_types.json new file mode 100644 index 0000000..f3d8782 --- /dev/null +++ b/extensions/common/api/extension_types.json @@ -0,0 +1,32 @@ +// 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. + +[ + { + "namespace": "extensionTypes", + "description": "The <code>chrome.extension_types</code> API contains type declarations for Chrome extensions.", + "types": [ + { + "id": "ImageDetails", + "type": "object", + "description": "Details about the format and quality of an image.", + "properties": { + "format": { + "type": "string", + "optional": true, + "enum": ["jpeg", "png"], + "description": "The format of the resulting image. Default is <code>\"jpeg\"</code>." + }, + "quality": { + "type": "integer", + "optional": true, + "minimum": 0, + "maximum": 100, + "description": "When format is <code>\"jpeg\"</code>, controls the quality of the resulting image. This value is ignored for PNG images. As quality is decreased, the resulting image will have more visual artifacts, and the number of bytes needed to store it will decrease." + } + } + } + ] + } +] diff --git a/extensions/common/api/schemas.gypi b/extensions/common/api/schemas.gypi index e595e5d..b7fd1de 100644 --- a/extensions/common/api/schemas.gypi +++ b/extensions/common/api/schemas.gypi @@ -18,6 +18,7 @@ 'cast_channel.idl', 'dns.idl', 'extensions_manifest_types.json', + 'extension_types.json', 'hid.idl', 'power.idl', 'runtime.json', diff --git a/extensions/generated_extensions_api.gni b/extensions/generated_extensions_api.gni index 98ddc77..0926d94 100644 --- a/extensions/generated_extensions_api.gni +++ b/extensions/generated_extensions_api.gni @@ -16,6 +16,12 @@ # namespace for each API. Use %(namespace)s to replace with the API # namespace, like "toplevel::%(namespace)s_api". # +# schema_include_rules [optional] +# A list of paths to include when searching for referenced objects, +# with the namespace separated by a :. +# Example: +# [ '/foo/bar:Foo::Bar::%(namespace)s' ] +# # schemas [optional, default = false] # Boolean indicating if the schema files should be generated. # @@ -54,6 +60,11 @@ template("generated_extensions_api") { bundle_registration = defined(invoker.bundle_registration) && invoker.bundle_registration + schema_include_rules = "" + if (defined(invoker.schema_include_rules)) { + schema_include_rules = invoker.schema_include_rules + } + # Keep a copy of the target_name here since it will be trampled # in nested targets. target_visibility = ":$target_name" @@ -96,7 +107,8 @@ template("generated_extensions_api") { "--root=" + rebase_path("//", root_build_dir), "--destdir=" + rebase_path(root_gen_dir, root_build_dir), "--namespace=$root_namespace", - "--generator=cpp" ] + "--generator=cpp", + "--include-rules=$schema_include_rules" ] visibility = target_visibility } } @@ -120,9 +132,9 @@ template("generated_extensions_api") { "--destdir=" + rebase_path(root_gen_dir, root_build_dir), "--namespace=$root_namespace", "--generator=cpp-bundle-schema", - ] + - rebase_path(sources, root_build_dir) + - rebase_path(uncompiled_sources, root_build_dir) + "--include-rules=$schema_include_rules" ] + + rebase_path(sources, root_build_dir) + + rebase_path(uncompiled_sources, root_build_dir) } } @@ -151,9 +163,9 @@ template("generated_extensions_api") { "--namespace=$root_namespace", "--generator=cpp-bundle-registration", "--impl-dir=" + rebase_path(impl_dir, "//"), - ] + - rebase_path(sources, root_build_dir) + - rebase_path(uncompiled_sources, root_build_dir) + "--include-rules=$schema_include_rules" ] + + rebase_path(sources, root_build_dir) + + rebase_path(uncompiled_sources, root_build_dir) } } diff --git a/tools/json_schema_compiler/cc_generator.py b/tools/json_schema_compiler/cc_generator.py index 43434b8..1d243f0 100644 --- a/tools/json_schema_compiler/cc_generator.py +++ b/tools/json_schema_compiler/cc_generator.py @@ -7,25 +7,23 @@ from model import PropertyType import cpp_util import schema_util import util_cc_helper +from cpp_namespace_environment import CppNamespaceEnvironment class CCGenerator(object): - def __init__(self, type_generator, cpp_namespace_pattern): + def __init__(self, type_generator): self._type_generator = type_generator - self._cpp_namespace_pattern = cpp_namespace_pattern def Generate(self, namespace): - return _Generator(namespace, - self._type_generator, - self._cpp_namespace_pattern).Generate() + return _Generator(namespace, self._type_generator).Generate() class _Generator(object): """A .cc generator for a namespace. """ - def __init__(self, namespace, cpp_type_generator, cpp_namespace_pattern): + def __init__(self, namespace, cpp_type_generator): + assert type(namespace.environment) is CppNamespaceEnvironment self._namespace = namespace self._type_helper = cpp_type_generator - self._cpp_namespace_pattern = cpp_namespace_pattern self._util_cc_helper = ( util_cc_helper.UtilCCHelper(self._type_helper)) self._generate_error_messages = namespace.compiler_options.get( @@ -34,8 +32,9 @@ class _Generator(object): def Generate(self): """Generates a Code object with the .cc for a single namespace. """ - cpp_namespace = cpp_util.GetCppNamespace(self._cpp_namespace_pattern, - self._namespace.unix_name) + cpp_namespace = cpp_util.GetCppNamespace( + self._namespace.environment.namespace_pattern, + self._namespace.unix_name) c = Code() (c.Append(cpp_util.CHROMIUM_LICENSE) diff --git a/tools/json_schema_compiler/compiler.py b/tools/json_schema_compiler/compiler.py index 38899286..7a2e4dd 100755 --- a/tools/json_schema_compiler/compiler.py +++ b/tools/json_schema_compiler/compiler.py @@ -18,6 +18,7 @@ Usage example: import optparse import os +import shlex import sys from cpp_bundle_generator import CppBundleGenerator @@ -25,6 +26,7 @@ from cpp_generator import CppGenerator from cpp_type_generator import CppTypeGenerator from dart_generator import DartGenerator import json_schema +from cpp_namespace_environment import CppNamespaceEnvironment from model import Model from schema_loader import SchemaLoader @@ -38,15 +40,18 @@ def GenerateSchema(generator_name, destdir, cpp_namespace_pattern, dart_overrides_dir, - impl_dir): + impl_dir, + include_rules): # Merge the source files into a single list of schemas. api_defs = [] for file_path in file_paths: - schema = os.path.normpath(file_path) + schema = os.path.relpath(file_path, root) schema_loader = SchemaLoader( - os.path.dirname(os.path.relpath(schema, root)), - os.path.dirname(file_path)) - api_def = schema_loader.LoadSchema(os.path.split(schema)[1]) + root, + os.path.dirname(schema), + include_rules, + cpp_namespace_pattern) + api_def = schema_loader.LoadSchema(schema) # If compiling the C++ model code, delete 'nocompile' nodes. if generator_name == 'cpp': @@ -68,7 +73,9 @@ def GenerateSchema(generator_name, relpath = os.path.relpath(os.path.normpath(file_path), root) namespace = api_model.AddNamespace(target_namespace, relpath, - include_compiler_options=True) + include_compiler_options=True, + environment=CppNamespaceEnvironment( + cpp_namespace_pattern)) if default_namespace is None: default_namespace = namespace @@ -105,7 +112,7 @@ def GenerateSchema(generator_name, ('generated_schemas.h', cpp_bundle_generator.schemas_h_generator) ] elif generator_name == 'cpp': - cpp_generator = CppGenerator(type_generator, cpp_namespace_pattern) + cpp_generator = CppGenerator(type_generator) generators = [ ('%s.h' % filename_base, cpp_generator.h_generator), ('%s.cc' % filename_base, cpp_generator.cc_generator) @@ -156,6 +163,10 @@ if __name__ == '__main__': help='Adds custom dart from files in the given directory (Dart only).') parser.add_option('-i', '--impl-dir', dest='impl_dir', help='The root path of all API implementations') + parser.add_option('-I', '--include-rules', + help='A list of paths to include when searching for referenced objects,' + ' with the namespace separated by a \':\'. Example: ' + '/foo/bar:Foo::Bar::%(namespace)s') (opts, file_paths) = parser.parse_args() @@ -169,8 +180,19 @@ if __name__ == '__main__': raise Exception( "Unless in bundle mode, only one file can be specified at a time.") + def split_path_and_namespace(path_and_namespace): + if ':' not in path_and_namespace: + raise ValueError('Invalid include rule "%s". Rules must be of ' + 'the form path:namespace' % path_and_namespace) + return path_and_namespace.split(':', 1) + + include_rules = [] + if opts.include_rules: + include_rules = map(split_path_and_namespace, + shlex.split(opts.include_rules)) + result = GenerateSchema(opts.generator, file_paths, opts.root, opts.destdir, opts.namespace, opts.dart_overrides_dir, - opts.impl_dir) + opts.impl_dir, include_rules) if not opts.destdir: print result diff --git a/tools/json_schema_compiler/cpp_generator.py b/tools/json_schema_compiler/cpp_generator.py index 7441ac5..5521ea9 100644 --- a/tools/json_schema_compiler/cpp_generator.py +++ b/tools/json_schema_compiler/cpp_generator.py @@ -6,6 +6,6 @@ from cc_generator import CCGenerator from h_generator import HGenerator class CppGenerator(object): - def __init__(self, type_generator, cpp_namespace_pattern): - self.h_generator = HGenerator(type_generator, cpp_namespace_pattern) - self.cc_generator = CCGenerator(type_generator, cpp_namespace_pattern) + def __init__(self, type_generator): + self.h_generator = HGenerator(type_generator) + self.cc_generator = CCGenerator(type_generator) diff --git a/tools/json_schema_compiler/cpp_namespace_environment.py b/tools/json_schema_compiler/cpp_namespace_environment.py new file mode 100644 index 0000000..20e77bb --- /dev/null +++ b/tools/json_schema_compiler/cpp_namespace_environment.py @@ -0,0 +1,7 @@ +# 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. + +class CppNamespaceEnvironment(object): + def __init__(self, namespace_pattern): + self.namespace_pattern = namespace_pattern diff --git a/tools/json_schema_compiler/cpp_type_generator.py b/tools/json_schema_compiler/cpp_type_generator.py index de6d130..6bec67e4 100644 --- a/tools/json_schema_compiler/cpp_type_generator.py +++ b/tools/json_schema_compiler/cpp_type_generator.py @@ -96,7 +96,10 @@ class CppTypeGenerator(object): if self._default_namespace is type_.namespace: cpp_type = cpp_util.Classname(type_.name) else: - cpp_type = '%s::%s' % (type_.namespace.unix_name, + cpp_namespace = cpp_util.GetCppNamespace( + type_.namespace.environment.namespace_pattern, + type_.namespace.unix_name) + cpp_type = '%s::%s' % (cpp_namespace, cpp_util.Classname(type_.name)) elif type_.property_type == PropertyType.ANY: cpp_type = 'base::Value' @@ -130,7 +133,7 @@ class CppTypeGenerator(object): PropertyType.OBJECT, PropertyType.CHOICES)) - def GenerateForwardDeclarations(self, cpp_namespace_pattern): + def GenerateForwardDeclarations(self): """Returns the forward declarations for self._default_namespace. """ c = Code() @@ -144,8 +147,9 @@ class CppTypeGenerator(object): if not filtered_deps: continue - cpp_namespace = cpp_util.GetCppNamespace(cpp_namespace_pattern, - namespace.unix_name) + cpp_namespace = cpp_util.GetCppNamespace( + namespace.environment.namespace_pattern, + namespace.unix_name) c.Concat(cpp_util.OpenNamespace(cpp_namespace)) for dep in filtered_deps: c.Append('struct %s;' % dep.type_.name) diff --git a/tools/json_schema_compiler/cpp_type_generator_test.py b/tools/json_schema_compiler/cpp_type_generator_test.py index f3a760a..51fcfe9 100755 --- a/tools/json_schema_compiler/cpp_type_generator_test.py +++ b/tools/json_schema_compiler/cpp_type_generator_test.py @@ -3,6 +3,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from cpp_namespace_environment import CppNamespaceEnvironment from cpp_type_generator import CppTypeGenerator from json_schema import CachedLoad import model @@ -51,8 +52,12 @@ class CppTypeGeneratorTest(unittest.TestCase): def testGenerateIncludesAndForwardDeclarations(self): m = model.Model() - m.AddNamespace(self.windows_json[0], 'path/to/windows.json') - m.AddNamespace(self.tabs_json[0], 'path/to/tabs.json') + m.AddNamespace(self.windows_json[0], + 'path/to/windows.json', + environment=CppNamespaceEnvironment('%(namespace)s')) + m.AddNamespace(self.tabs_json[0], + 'path/to/tabs.json', + environment=CppNamespaceEnvironment('%(namespace)s')) manager = CppTypeGenerator(m, _FakeSchemaLoader(m)) self.assertEquals('', manager.GenerateIncludes().Render()) @@ -62,7 +67,18 @@ class CppTypeGeneratorTest(unittest.TestCase): 'namespace tabs {\n' 'struct Tab;\n' '} // namespace tabs', - manager.GenerateForwardDeclarations('%(namespace)s').Render()) + manager.GenerateForwardDeclarations().Render()) + + m = model.Model() + m.AddNamespace(self.windows_json[0], + 'path/to/windows.json', + environment=CppNamespaceEnvironment( + 'foo::bar::%(namespace)s')) + m.AddNamespace(self.tabs_json[0], + 'path/to/tabs.json', + environment=CppNamespaceEnvironment( + 'foo::bar::%(namespace)s')) + manager = CppTypeGenerator(m, _FakeSchemaLoader(m)) self.assertEquals( 'namespace foo {\n' 'namespace bar {\n' @@ -71,13 +87,12 @@ class CppTypeGeneratorTest(unittest.TestCase): '} // namespace tabs\n' '} // namespace bar\n' '} // namespace foo', - manager.GenerateForwardDeclarations('foo::bar::%(namespace)s').Render()) + manager.GenerateForwardDeclarations().Render()) manager = CppTypeGenerator(self.models.get('permissions'), _FakeSchemaLoader(m)) self.assertEquals('', manager.GenerateIncludes().Render()) self.assertEquals('', manager.GenerateIncludes().Render()) - self.assertEquals( - '', manager.GenerateForwardDeclarations('%(namespace)s').Render()) + self.assertEquals('', manager.GenerateForwardDeclarations().Render()) manager = CppTypeGenerator(self.models.get('content_settings'), _FakeSchemaLoader(m)) self.assertEquals('', manager.GenerateIncludes().Render()) @@ -96,8 +111,7 @@ class CppTypeGeneratorTest(unittest.TestCase): self.assertEquals('#include "path/to/browser_action.h"\n' '#include "path/to/font_settings.h"', manager.GenerateIncludes().Render()) - self.assertEquals( - '', manager.GenerateForwardDeclarations('%(namespace)s').Render()) + self.assertEquals('', manager.GenerateForwardDeclarations().Render()) def testGetCppTypeSimple(self): manager = CppTypeGenerator(self.models.get('tabs'), _FakeSchemaLoader(None)) @@ -147,8 +161,12 @@ class CppTypeGeneratorTest(unittest.TestCase): def testGetCppTypeIncludedRef(self): m = model.Model() - m.AddNamespace(self.windows_json[0], 'path/to/windows.json') - m.AddNamespace(self.tabs_json[0], 'path/to/tabs.json') + m.AddNamespace(self.windows_json[0], + 'path/to/windows.json', + environment=CppNamespaceEnvironment('%(namespace)s')) + m.AddNamespace(self.tabs_json[0], + 'path/to/tabs.json', + environment=CppNamespaceEnvironment('%(namespace)s')) manager = CppTypeGenerator(m, _FakeSchemaLoader(m)) self.assertEquals( 'std::vector<linked_ptr<tabs::Tab> >', diff --git a/tools/json_schema_compiler/dart_generator_test.py b/tools/json_schema_compiler/dart_generator_test.py index b01d467..2005e7e 100755 --- a/tools/json_schema_compiler/dart_generator_test.py +++ b/tools/json_schema_compiler/dart_generator_test.py @@ -32,7 +32,7 @@ class DartTest(unittest.TestCase): if REBASE_MODE: output_dir = TESTS_DIR output_code = GenerateSchema('dart', ['%s.idl' % file_rel], TESTS_DIR, - output_dir, None, None, None) + output_dir, '', None, None, []) if not REBASE_MODE: with open('%s.dart' % file_rel) as f: diff --git a/tools/json_schema_compiler/h_generator.py b/tools/json_schema_compiler/h_generator.py index 95c8056..a6d67db 100644 --- a/tools/json_schema_compiler/h_generator.py +++ b/tools/json_schema_compiler/h_generator.py @@ -10,23 +10,19 @@ import cpp_util import schema_util class HGenerator(object): - def __init__(self, type_generator, cpp_namespace_pattern): + def __init__(self, type_generator): self._type_generator = type_generator - self._cpp_namespace_pattern = cpp_namespace_pattern def Generate(self, namespace): - return _Generator(namespace, - self._type_generator, - self._cpp_namespace_pattern).Generate() + return _Generator(namespace, self._type_generator).Generate() class _Generator(object): """A .h generator for a namespace. """ - def __init__(self, namespace, cpp_type_generator, cpp_namespace_pattern): + def __init__(self, namespace, cpp_type_generator): self._namespace = namespace self._type_helper = cpp_type_generator - self._cpp_namespace_pattern = cpp_namespace_pattern self._generate_error_messages = namespace.compiler_options.get( 'generate_error_messages', False) @@ -65,11 +61,11 @@ class _Generator(object): # $ref types from other files to be used as required params. This requires # some detangling of windows and tabs which will currently lead to circular # #includes. - c.Cblock(self._type_helper.GenerateForwardDeclarations( - self._cpp_namespace_pattern)) + c.Cblock(self._type_helper.GenerateForwardDeclarations()) - cpp_namespace = cpp_util.GetCppNamespace(self._cpp_namespace_pattern, - self._namespace.unix_name) + cpp_namespace = cpp_util.GetCppNamespace( + self._namespace.environment.namespace_pattern, + self._namespace.unix_name) c.Concat(cpp_util.OpenNamespace(cpp_namespace)) c.Append() if self._namespace.properties: diff --git a/tools/json_schema_compiler/model.py b/tools/json_schema_compiler/model.py index ed8a2ec..16530e7 100644 --- a/tools/json_schema_compiler/model.py +++ b/tools/json_schema_compiler/model.py @@ -27,12 +27,17 @@ class Model(object): def __init__(self): self.namespaces = {} - def AddNamespace(self, json, source_file, include_compiler_options=False): + def AddNamespace(self, + json, + source_file, + include_compiler_options=False, + environment=None): """Add a namespace's json to the model and returns the namespace. """ namespace = Namespace(json, source_file, - include_compiler_options=include_compiler_options) + include_compiler_options=include_compiler_options, + environment=environment) self.namespaces[namespace.name] = namespace return namespace @@ -95,7 +100,11 @@ class Namespace(object): - |compiler_options| the compiler_options dict, only not empty if |include_compiler_options| is True """ - def __init__(self, json, source_file, include_compiler_options=False): + def __init__(self, + json, + source_file, + include_compiler_options=False, + environment=None): self.name = json['namespace'] if 'description' not in json: # TODO(kalman): Go back to throwing an error here. @@ -119,6 +128,7 @@ class Namespace(object): self.compiler_options = json.get('compiler_options', {}) else: self.compiler_options = {} + self.environment = environment self.documentation_options = json.get('documentation_options', {}) diff --git a/tools/json_schema_compiler/schema_loader.py b/tools/json_schema_compiler/schema_loader.py index 358381f..261e8d0 100644 --- a/tools/json_schema_compiler/schema_loader.py +++ b/tools/json_schema_compiler/schema_loader.py @@ -8,20 +8,48 @@ import sys import idl_schema import json_schema +from cpp_namespace_environment import CppNamespaceEnvironment from model import Model, UnixName +def GenerateFilenames(full_namespace): + # Try to find the file defining the namespace. Eg. for + # nameSpace.sub_name_space.Type' the following heuristics looks for: + # 1. name_space_sub_name_space.json, + # 2. name_space_sub_name_space.idl, + # 3. sub_name_space.json, + # 4. sub_name_space.idl, + # 5. etc. + sub_namespaces = full_namespace.split('.') + filenames = [ ] + basename = None + for namespace in reversed(sub_namespaces): + if basename is not None: + basename = UnixName(namespace + '.' + basename) + else: + basename = UnixName(namespace) + for ext in ['json', 'idl']: + filenames.append('%s.%s' % (basename, ext)) + return filenames + class SchemaLoader(object): '''Resolves a type name into the namespace the type belongs to. Properties: - - |display_path| path to the directory with the API header files, intended for - use with the Model. - - |real_path| path to the directory with the API header files, used for file - access. + - |root| path to the root directory. + - |path| path to the directory with the API header files, relative to the + root. + - |include_rules| List containing tuples with (path, cpp_namespace_pattern) + used when searching for types. + - |cpp_namespace_pattern| Default namespace pattern ''' - def __init__(self, display_path, real_path): - self._display_path = display_path - self._real_path = real_path + def __init__(self, + root, + path, + include_rules, + cpp_namespace_pattern): + self._root = root + self._include_rules = [(path, cpp_namespace_pattern)] + self._include_rules.extend(include_rules) def ResolveType(self, full_name, default_namespace): name_parts = full_name.rsplit('.', 1) @@ -29,35 +57,26 @@ class SchemaLoader(object): if full_name not in default_namespace.types: return None return default_namespace - namespace_name, type_name = name_parts - real_name = None - # Try to find the file defining the namespace. Eg. for - # nameSpace.sub_name_space.Type' the following heuristics looks for: - # 1. name_space_sub_name_space.json, - # 2. name_space_sub_name_space.idl. - for ext in ['json', 'idl']: - basename = UnixName(namespace_name) - filename = '%s.%s' % (basename, ext) - filepath = os.path.join(self._real_path, filename); - if os.path.exists(filepath): - real_name = filename - break - if real_name is None: - return None - namespace = Model().AddNamespace( - self.LoadSchema(real_name)[0], - os.path.join(self._display_path, real_name)) - if type_name not in namespace.types: - return None - return namespace + full_namespace, type_name = full_name.rsplit('.', 1) + filenames = GenerateFilenames(full_namespace) + for path, namespace in self._include_rules: + for filename in reversed(filenames): + filepath = os.path.join(path, filename); + if os.path.exists(os.path.join(self._root, filepath)): + namespace = Model().AddNamespace( + self.LoadSchema(filepath)[0], + filepath, + environment=CppNamespaceEnvironment(namespace)) + if type_name in namespace.types: + return namespace + return None def LoadSchema(self, schema): '''Load a schema definition. The schema parameter must be a file name - without any path component - the file is loaded from the path defined by - the real_path argument passed to the constructor.''' + with the full path relative to the root.''' schema_filename, schema_extension = os.path.splitext(schema) - schema_path = os.path.join(self._real_path, schema); + schema_path = os.path.join(self._root, schema) if schema_extension == '.json': api_defs = json_schema.Load(schema_path) elif schema_extension == '.idl': |