123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- # Copyright 2022 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 collections
- import importlib.util
- import os
- import re
- import sys
- from typing import Dict, List
- from json_data_generator.util import (GetDirNameFromPath, GetFileNameFromPath,
- GetFileNameWithoutExtensionFromPath,
- JoinPath)
- _FILE_PATH = os.path.dirname(os.path.realpath(__file__))
- _JSON5_PATH = os.path.join(_FILE_PATH, os.pardir, os.pardir, 'third_party',
- 'pyjson5', 'src')
- sys.path.insert(1, _JSON5_PATH)
- import json5
- _JINJA2_PATH = os.path.join(_FILE_PATH, os.pardir, os.pardir, 'third_party')
- sys.path.insert(1, _JINJA2_PATH)
- import jinja2
- class JSONDataGenerator(object):
- '''A generic json data generator.'''
- def __init__(self, out_dir: str):
- self.out_dir = out_dir
- self.model: Dict = {}
- # Store all json sources used in the generator.
- self.sources: List[str] = list()
- def AddJSONFilesToModel(self, paths: List[str]):
- '''Adds one or more JSON files to the model.'''
- for path in paths:
- try:
- with open(path, 'r') as f:
- self.AddJSONToModel(path, f.read())
- self.sources.append(path)
- except ValueError as err:
- raise ValueError('\n%s:\n %s' % (path, err))
- def AddJSONToModel(self, json_path: str, json_string: str):
- '''Adds a |json_string| with data to the model.
- Every json file is added to |self.model| with the original file
- name as the key.
- '''
- data = json5.loads(json_string,
- object_pairs_hook=collections.OrderedDict)
- # Use the json file name as the key of the loaded json data.
- key = GetFileNameWithoutExtensionFromPath(json_path)
- self.model[key] = data
- def GetGlobals(self, template_path: str):
- file_name_without_ext = GetFileNameWithoutExtensionFromPath(
- template_path)
- out_file_path = JoinPath(self.out_dir, file_name_without_ext)
- return {
- 'model': self.model,
- 'source_json_files': self.sources,
- 'out_file_path': out_file_path,
- }
- def GetFilters(self):
- return {
- 'to_header_guard': self._ToHeaderGuard,
- }
- def RenderTemplate(self,
- path_to_template: str,
- path_to_template_helper: str = None):
- template_dir = GetDirNameFromPath(path_to_template)
- template_name = GetFileNameFromPath(path_to_template)
- jinja_env = jinja2.Environment(
- loader=jinja2.FileSystemLoader(template_dir),
- keep_trailing_newline=True)
- jinja_env.globals.update(self.GetGlobals(path_to_template))
- jinja_env.filters.update(self.GetFilters())
- if path_to_template_helper:
- template_helper_module = self._LoadTemplateHelper(
- path_to_template_helper)
- jinja_env.globals.update(
- template_helper_module.get_custom_globals(self.model))
- jinja_env.filters.update(
- template_helper_module.get_custom_filters(self.model))
- template = jinja_env.get_template(template_name)
- return template.render()
- def _LoadTemplateHelper(self, path_to_template_helper: str):
- template_helper_dir = GetDirNameFromPath(path_to_template_helper)
- try:
- sys.path.append(template_helper_dir)
- spec = importlib.util.spec_from_file_location(
- path_to_template_helper, path_to_template_helper)
- module = importlib.util.module_from_spec(spec)
- spec.loader.exec_module(module)
- return module
- finally:
- # Restore sys.path to what it was before.
- sys.path.remove(template_helper_dir)
- def _ToHeaderGuard(self, path: str):
- return re.sub(r'[\\\/\.\-]+', '_', path.upper())
|