import copy
import os
import sys
if sys.version_info.major == 2:
import cPickle as pickle
else:
import pickle
from blinkbuild.name_style_converter import NameStyleConverter
import make_runtime_features_utilities as util
import json5_generator
import template_expander
class BaseRuntimeFeatureWriter(json5_generator.Writer):
class_name = None
file_basename = None
def __init__(self, json5_file_path, output_dir):
super(BaseRuntimeFeatureWriter, self).__init__(json5_file_path,
output_dir)
for path in json5_file_path:
file_root, file_ext = os.path.splitext(path)
override_file_path = f"{file_root}.override{file_ext}"
if os.path.exists(override_file_path):
self.json5_file.load_override_file(override_file_path)
self._outputs = {}
assert self.file_basename
self._features = self.json5_file.name_dictionaries
origin_trial_set = util.origin_trials(self._features)
for feature in self._features:
feature['in_origin_trial'] = str(
feature['name']) in origin_trial_set
feature['data_member_name'] = self._data_member_name(
feature['name'])
if isinstance(feature['status'], dict):
feature['status'] = self._status_with_all_platforms(
feature['status'])
feature['status_type'] = "dict" if isinstance(
feature['status'], dict) else "str"
if feature['base_feature'] == 'none':
feature['base_feature'] = ''
elif feature['base_feature'] == '':
feature['base_feature'] = feature['name']
self._origin_trial_features = [
feature for feature in self._features if feature['in_origin_trial']
]
self._header_guard = self.make_header_guard(self._relative_output_dir +
self.file_basename + '.h')
@staticmethod
def _data_member_name(str_or_converter):
converter = NameStyleConverter(str_or_converter) if type(
str_or_converter) is str else str_or_converter
return converter.to_class_data_member(prefix='is', suffix='enabled')
def _feature_sets(self):
return self.json5_file.parameters['status']['valid_values']
def _status_with_all_platforms(self, status):
new_status = copy.deepcopy(status)
default = new_status['default'] if 'default' in new_status else ''
new_status['default'] = default
for platform in self._platforms():
if platform not in new_status:
new_status[platform] = default
return new_status
def _platforms(self):
platforms = self.json5_file.parameters['status']['valid_keys']
return [platform for platform in platforms if platform != 'default']
class RuntimeFeatureWriter(BaseRuntimeFeatureWriter):
class_name = 'RuntimeEnabledFeatures'
file_basename = 'runtime_enabled_features'
def __init__(self, json5_file_path, output_dir):
super(RuntimeFeatureWriter, self).__init__(json5_file_path, output_dir)
self._outputs = {
(self.file_basename + '.h'):
self.generate_header,
(self.file_basename + '.cc'):
self.generate_implementation,
('exported/web_runtime_features_base.cc'):
self.generate_web_implementation,
}
self._write_features_to_pickle_file(output_dir)
self._overridable_features = util.overridable_features(self._features)
overridable_set = set()
for feature in self._overridable_features:
overridable_set.add(str(feature['name']))
for feature in self._features:
feature['is_overridable_feature'] = str(
feature['name']) in overridable_set
def _write_features_to_pickle_file(self, platform_output_dir):
file_name = os.path.join(platform_output_dir, '..', 'build', 'scripts',
'runtime_enabled_features.pickle')
features_map = {}
for feature in self._features:
features_map[str(feature['name'])] = {
'in_origin_trial': feature['in_origin_trial']
}
if os.path.isfile(file_name):
with open(os.path.abspath(file_name)) as pickle_file:
try:
if pickle.load(pickle_file) == features_map:
return
except Exception:
pass
with open(os.path.abspath(file_name), 'wb') as pickle_file:
pickle.dump(features_map, pickle_file)
def _template_inputs(self):
return {
'features': self._features,
'feature_sets': self._feature_sets(),
'platforms': self._platforms(),
'input_files': self._input_files,
'origin_trial_controlled_features': self._origin_trial_features,
'header_guard': self._header_guard,
}
@template_expander.use_jinja('templates/' + file_basename + '.h.tmpl')
def generate_header(self):
return self._template_inputs()
@template_expander.use_jinja('templates/' + file_basename + '.cc.tmpl')
def generate_implementation(self):
return self._template_inputs()
@template_expander.use_jinja('templates/web_runtime_features_base.cc.tmpl')
def generate_web_implementation(self):
return self._template_inputs()
class RuntimeFeatureTestHelpersWriter(BaseRuntimeFeatureWriter):
class_name = 'ScopedRuntimeEnabledFeatureForTest'
file_basename = 'runtime_enabled_features_test_helpers'
def __init__(self, json5_file_path, output_dir):
super(RuntimeFeatureTestHelpersWriter, self).__init__(
json5_file_path, output_dir)
self._outputs = {
('testing/' + self.file_basename + '.h'): self.generate_header
}
def _template_inputs(self):
return {
'features': self._features,
'input_files': self._input_files,
'header_guard': self._header_guard,
}
@template_expander.use_jinja('templates/' + file_basename + '.h.tmpl')
def generate_header(self):
return self._template_inputs()
if __name__ == '__main__':
json5_generator.Maker(RuntimeFeatureWriter).main()
json5_generator.Maker(RuntimeFeatureTestHelpersWriter).main()