| Index: services/catalog/public/tools/sourcify_manifest.py
|
| diff --git a/services/catalog/public/tools/sourcify_manifest.py b/services/catalog/public/tools/sourcify_manifest.py
|
| index 81c219dd843a7dd14f7141caee08b3000f7d6387..6744b7f70a42c6c3309265f67d087cab6df4a796 100755
|
| --- a/services/catalog/public/tools/sourcify_manifest.py
|
| +++ b/services/catalog/public/tools/sourcify_manifest.py
|
| @@ -3,56 +3,109 @@
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| -"""Generates a C++ source file which defines a string constant containing the
|
| -contents of a catalog manifest file. Useful for baking catalogs into binaries
|
| -which don't want to hit disk before initializing the catalog."""
|
| +"""Generates C++ source and header files defining function to create an
|
| +in-memory representation of a static catalog manifest at runtime."""
|
| +
|
|
|
| import argparse
|
| +import imp
|
| import json
|
| import os.path
|
| import sys
|
|
|
|
|
| -# Token used to delimit raw strings in the generated source file. It's illegal
|
| -# for this token to appear within the contents of the input manifest itself.
|
| -_RAW_STRING_DELIMITER = "#CATALOG_JSON#"
|
| +_H_FILE_TEMPLATE = "catalog.h.tmpl"
|
| +_CC_FILE_TEMPLATE = "catalog.cc.tmpl"
|
| +
|
| +
|
| +# Disable lint check for finding modules:
|
| +# pylint: disable=F0401
|
| +
|
| +def _GetDirAbove(dirname):
|
| + """Returns the directory "above" this file containing |dirname| (which must
|
| + also be "above" this file)."""
|
| + path = os.path.abspath(__file__)
|
| + while True:
|
| + path, tail = os.path.split(path)
|
| + assert tail
|
| + if tail == dirname:
|
| + return path
|
| +
|
| +
|
| +try:
|
| + imp.find_module("jinja2")
|
| +except ImportError:
|
| + sys.path.append(os.path.join(_GetDirAbove("services"), "third_party"))
|
| +import jinja2
|
| +
|
| +
|
| +def ApplyTemplate(path_to_template, output_path, global_vars, **kwargs):
|
| + def make_ascii(maybe_unicode):
|
| + if type(maybe_unicode) is str:
|
| + return maybe_unicode
|
| + assert type(maybe_unicode) is unicode
|
| + return maybe_unicode.encode("ascii", "ignore")
|
| +
|
| + with open(output_path, "w") as output_file:
|
| + jinja_env = jinja2.Environment(
|
| + loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
|
| + keep_trailing_newline=True, **kwargs)
|
| + jinja_env.globals.update(global_vars)
|
| + jinja_env.filters.update({
|
| + "is_dict": lambda x : type(x) is dict,
|
| + "is_list": lambda x : type(x) is list,
|
| + "is_number": lambda x : type(x) is int or type(x) is float,
|
| + "is_bool": lambda x: type(x) is bool,
|
| + "is_string": lambda x: type(x) is str,
|
| + "is_unicode": lambda x: type(x) is unicode,
|
| + "make_ascii": make_ascii,
|
| + })
|
| + output_file.write(jinja_env.get_template(path_to_template).render())
|
|
|
|
|
| def main():
|
| parser = argparse.ArgumentParser(
|
| description="Generates a C++ constant containing a catalog manifest.")
|
| parser.add_argument("--input")
|
| - parser.add_argument("--output")
|
| - parser.add_argument("--symbol-name")
|
| - parser.add_argument("--pretty", action="store_true")
|
| + parser.add_argument("--output-filename-base")
|
| + parser.add_argument("--output-function-name")
|
| + parser.add_argument("--module-path")
|
| args, _ = parser.parse_known_args()
|
|
|
| - if args.input is None or args.output is None or args.symbol_name is None:
|
| - raise Exception("--input, --output, and --symbol-name are required")
|
| -
|
| - with open(args.input, 'r') as input_file:
|
| - manifest_contents = input_file.read()
|
| -
|
| - if manifest_contents.find(_RAW_STRING_DELIMITER) >= 0:
|
| - raise Exception(
|
| - "Unexpected '%s' found in input manifest." % _RAW_STRING_DELIMITER)
|
| -
|
| - qualified_symbol_name = args.symbol_name.split("::")
|
| - namespace = qualified_symbol_name[0:-1]
|
| - symbol_name = qualified_symbol_name[-1]
|
| -
|
| - with open(args.output, 'w') as output_file:
|
| - output_file.write(
|
| - "// This is a generated file produced by\n"
|
| - "// src/services/catalog/public/tools/sourcify_manifest.py.\n\n")
|
| - for name in namespace:
|
| - output_file.write("namespace %s {\n" % name)
|
| - output_file.write("\nextern const char %s[];" % symbol_name)
|
| - output_file.write("\nconst char %s[] = R\"%s(%s)%s\";\n\n" %
|
| - (symbol_name, _RAW_STRING_DELIMITER, manifest_contents,
|
| - _RAW_STRING_DELIMITER))
|
| - for name in reversed(namespace):
|
| - output_file.write("} // %s\n" % name)
|
| + if args.input is None:
|
| + raise Exception("--input is required")
|
| + if args.output_filename_base is None:
|
| + raise Exception("--output-filename-base is required")
|
| + if args.output_function_name is None:
|
| + raise Exception("--output-function-name is required")
|
| + if args.module_path is None:
|
| + raise Exception("--module-path is required")
|
| +
|
| + with open(args.input, "r") as input_file:
|
| + catalog = json.load(input_file)
|
| +
|
| + qualified_function_name = args.output_function_name.split("::")
|
| + namespaces = qualified_function_name[0:-1]
|
| + function_name = qualified_function_name[-1]
|
| +
|
| + def raise_error(error, value):
|
| + raise Exception(error)
|
| +
|
| + global_vars = {
|
| + "catalog": catalog,
|
| + "function_name": function_name,
|
| + "namespaces": namespaces,
|
| + "path": args.module_path,
|
| + "raise": raise_error,
|
| + }
|
| +
|
| + input_h_filename = _H_FILE_TEMPLATE
|
| + output_h_filename = "%s.h" % args.output_filename_base
|
| + ApplyTemplate(input_h_filename, output_h_filename, global_vars)
|
| +
|
| + input_cc_filename = _CC_FILE_TEMPLATE
|
| + output_cc_filename = "%s.cc" % args.output_filename_base
|
| + ApplyTemplate(input_cc_filename, output_cc_filename, global_vars)
|
|
|
| return 0
|
|
|
|
|