Files
phs_v1.0.1.0/build/hb/services/loader.py
2024-09-27 19:16:49 +08:00

930 lines
43 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2023 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from services.interface.load_interface import LoadInterface
from containers.status import throw_exception
from exceptions.ohos_exception import OHOSException
from util.loader import platforms_loader # noqa: E402
from util.loader import generate_targets_gn # noqa: E402
from util.loader import load_ohos_build # noqa: E402
from util.loader import subsystem_scan # noqa: E402
from util.loader import subsystem_info # noqa: E402
from scripts.util.file_utils import read_json_file, write_json_file, write_file # noqa: E402, E501
from util.log_util import LogUtil
class OHOSLoader(LoadInterface):
def __init__(self):
super().__init__()
self.source_root_dir = ""
self.gn_root_out_dir = ""
self.os_level = ""
self.target_cpu = ""
self.target_os = ""
self.config_output_relpath = ""
self.config_output_dir = ""
self.target_arch = ""
self.subsystem_config_file = ""
self.subsystem_config_overlay_file = ""
self.platforms_config_file = ""
self.exclusion_modules_config_file = ""
self.example_subsystem_file = ""
self.build_example = ""
self.scalable_build = ""
self.build_platform_name = ""
self.build_xts = ""
self.ignore_api_check = ""
self.load_test_config = ""
self.subsystem_configs = ""
self._subsystem_info = ""
self.skip_partlist_check = ""
def __post_init__(self):
self.source_root_dir = self.config.root_path + '/'
self.gn_root_out_dir = self.config.out_path if not self.config.out_path.startswith(
'/') else os.path.relpath(self.config.out_path, self.config.root_path)
self.os_level = self.config.os_level if self.config.os_level else "standard"
self.target_cpu = self.config.target_cpu if self.config.target_cpu else "arm"
self.target_os = self.config.target_os if self.config.target_os else "ohos"
self.config_output_relpath = os.path.join(
self.gn_root_out_dir, 'build_configs')
self.config_output_dir = os.path.join(
self.source_root_dir, self.config_output_relpath)
self.target_arch = '{}_{}'.format(self.target_os, self.target_cpu)
self.subsystem_config_file = os.path.join(
self.config.root_path, 'out/preloader', self.config.product, 'subsystem_config.json')
self.platforms_config_file = os.path.join(
self.config.root_path, 'out/preloader', self.config.product, 'platforms.build')
self.exclusion_modules_config_file = os.path.join(
self.config.root_path, 'out/preloader', self.config.product, 'exclusion_modules.json')
self.example_subsystem_file = os.path.join(
self.config.root_path, 'build', 'subsystem_config_example.json')
compile_standard_allow_file = os.path.join(
self.config.root_path, 'out/preloader', self.config.product, 'compile_standard_whitelist.json')
compile_standard_allow_info = read_json_file(compile_standard_allow_file)
bundle_subsystem_allow_list = compile_standard_allow_info.get("bundle_subsystem_error", [])
# check config args
self._check_args()
self.build_example = self.args_dict.get('build_example')
if not self.build_example:
self.example_subsystem_file = ""
self.scalable_build = self.args_dict.get('scalable_build')
self.build_platform_name = self.args_dict.get('build_platform_name')
self.build_xts = self.args_dict.get('build_xts')
self.ignore_api_check = self.args_dict.get('ignore_api_check')
self.load_test_config = self.args_dict.get('load_test_config')
self.skip_partlist_check = self.args_dict.get('skip_partlist_check')
self.subsystem_configs = subsystem_scan.scan(self.subsystem_config_file,
self.example_subsystem_file,
self.source_root_dir)
self._subsystem_info = subsystem_info.get_subsystem_info(
self.subsystem_config_file,
self.example_subsystem_file,
self.source_root_dir,
self.config_output_relpath,
self.os_level)
overrided_components = self._override_components()
self._platforms_info = platforms_loader.get_platforms_info(
self.platforms_config_file,
self.source_root_dir,
self.gn_root_out_dir,
self.target_arch,
self.config_output_relpath,
self.scalable_build)
self.variant_toolchains = self._platforms_info.get(
'variant_toolchain_info').get('platform_toolchain')
self._all_platforms = self.variant_toolchains.keys()
self.build_platforms = self._get_build_platforms()
self.parts_config_info = load_ohos_build.get_parts_info(
self.source_root_dir,
self.config_output_relpath,
self._subsystem_info,
self.variant_toolchains,
self.target_arch,
self.ignore_api_check,
self.exclusion_modules_config_file,
self.load_test_config,
overrided_components,
bundle_subsystem_allow_list,
self.skip_partlist_check,
self.build_xts)
self.parts_targets = self.parts_config_info.get('parts_targets')
self.phony_targets = self.parts_config_info.get('phony_target')
self.parts_info = self.parts_config_info.get('parts_info')
self.target_platform_parts = self._get_platforms_all_parts()
self.target_platform_stubs = self._get_platforms_all_stubs()
self.required_parts_targets_list = self._get_required_build_parts_list()
self.required_phony_targets = self._get_required_phony_targets()
self.required_parts_targets = self._get_required_build_targets()
# check method
'''Description: Check the parameters passed in config. If the parameters are not
specified or the file content pointed to by the parameters does not
exist, an exception will be thrown directly.
@parameter:none
@return :none
'''
@throw_exception
def _check_args(self):
LogUtil.hb_info("Checking all build args...")
# check subsystem_config_file
if not read_json_file(self.subsystem_config_file):
self.subsystem_config_file = os.path.join(
self.source_root_dir, 'build/subsystem_config.json')
if not read_json_file(self.subsystem_config_file):
raise OHOSException("Cannot get the content from platform config file, \
please check whether the corresponding file('out/preloader/{}/subsystem_config.json' or \
'build/subsystem_config.json') is written correctly.".format(self.config.product), "2001")
# check gn_root_out_dir
if not self.gn_root_out_dir:
raise OHOSException("Args gn_root_out_dir is required.", "2002")
if not os.path.realpath(self.gn_root_out_dir).startswith(self.source_root_dir):
raise OHOSException("Args gn_root_out_dir is incorrect.", "2003")
# check platform config file
if not read_json_file(self.platforms_config_file):
raise OHOSException("Cannot get the content from platform config file, \
please check whether the corresponding file('out/preloader/${product_name}/platforms.build') \
is written correctly.".format(self.config.product), "2004")
# check example subsystem file
if not read_json_file(self.example_subsystem_file):
raise OHOSException("Cannot get the content from example subsystem file, please check whether \
the corresponding file ('build/subsystem_config_example.json') exists.", "2005")
@throw_exception
def _check_product_part_feature(self):
LogUtil.hb_info("Checking all product features...")
product_preloader_dir = os.path.dirname(self.platforms_config_file)
_preloader_feature_file = os.path.join(product_preloader_dir,
'features.json')
_preloader_feature_info = read_json_file(_preloader_feature_file)
part_to_feature = _preloader_feature_info.get('part_to_feature')
for key, vals in part_to_feature.items():
part = self.parts_info.get(key)
if part is None:
continue
_p_info = part[0]
def_feature_list = _p_info.get('feature_list')
if not def_feature_list:
continue
for _f_name in vals:
if _f_name not in def_feature_list:
raise OHOSException(
"The product use a feature that is not supported"
" by this part, part_name='{}', feature='{}'".format(
key, _f_name), "2006")
@throw_exception
def _check_parts_config_info(self):
LogUtil.hb_info("Checking parts config...")
if not ('parts_info' in self.parts_config_info
and 'subsystem_parts' in self.parts_config_info
and 'parts_variants' in self.parts_config_info
and 'parts_kits_info' in self.parts_config_info
and 'parts_inner_kits_info' in self.parts_config_info
and 'parts_targets' in self.parts_config_info):
raise OHOSException(
"Loading ohos.build information is incorrect.", "2007")
# generate method
'''Description: Generate SystemCapability.json & syscap.json & syscap.para, dir:[
(//out/preloader/${product_name}/system/etc/SystemCapability.json),
(//out/preloader/${product_name}/system/etc/syscap.json),
(//out/preloader/${product_name}/system/etc/param/syscap.para)]
@parameter:none
@return :none
'''
@throw_exception
def _generate_syscap_files(self):
pre_syscap_info_path = os.path.dirname(self.platforms_config_file)
system_path = os.path.join(self.source_root_dir, os.path.join(
os.path.dirname(self.platforms_config_file), "system/"))
syscap_product_dict = read_json_file(
os.path.join(pre_syscap_info_path, "syscap.json"))
syscap_info_list = self.parts_config_info.get('syscap_info')
target_syscap_with_part_name_list = []
target_syscap_list = []
target_syscap_for_init_list = []
all_syscap_list = []
for syscap in syscap_info_list:
if syscap['component'] not in self.required_parts_targets_list:
continue
if 'syscap' not in syscap or syscap['syscap'] is None \
or len(syscap['syscap']) == 0 or syscap['syscap'] == [""]:
continue
for syscap_string in syscap['syscap']:
all_syscap_list.append(syscap_string.split('=')[0].strip())
for key, value in syscap_product_dict['part_to_syscap'].items():
for syscap in value:
if syscap not in all_syscap_list:
raise OHOSException(
"In config.json of part [{}],the syscap[{}] is incorrect, \
please check the syscap name".format(key, syscap), "2008")
for syscap in syscap_info_list:
remove_list = []
if syscap['component'] not in self.required_parts_targets_list:
continue
if 'syscap' not in syscap or syscap['syscap'] is None \
or len(syscap['syscap']) == 0 or syscap['syscap'] == [""]:
continue
for syscap_string in syscap['syscap']:
if syscap_string.startswith("SystemCapability.") is True:
target_syscap_init_str = "const."
syscap_name = syscap_string.split('=')[0].strip()
all_syscap_product = syscap_product_dict['syscap']
if syscap_name in all_syscap_product and not all_syscap_product[syscap_name]:
remove_list.append(syscap_string)
continue
elif syscap_name in all_syscap_product and all_syscap_product[syscap_name]:
target_syscap_init_str += syscap_name + '=true\n'
else:
if syscap_string.endswith('true'):
target_syscap_init_str += syscap_name + '=true\n'
elif syscap_string.endswith('false'):
remove_list.append(syscap_string)
continue
else:
target_syscap_init_str += syscap_string + "=true\n"
if target_syscap_init_str not in target_syscap_for_init_list:
target_syscap_for_init_list.append(
target_syscap_init_str)
else:
raise OHOSException("""In bundle.json of part [{}], The syscap string [{}] is incorrect,
need start with \"SystemCapability.\"""".format(syscap['component'], syscap_string), "2009")
for remove_str in remove_list:
syscap['syscap'].remove(remove_str)
for i in range(len(syscap['syscap'])):
if syscap['syscap'][i].endswith('true') or syscap['syscap'][i].endswith('false'):
syscap['syscap'][i] = syscap['syscap'][i].split('=')[
0].strip()
syscap['syscap'].sort()
target_syscap_with_part_name_list.append(syscap)
target_syscap_list.extend(syscap['syscap'])
# Generate SystemCapability.json & syscap.json & syscap.para
target_syscap_list.sort()
syscap_info_dict = read_json_file(os.path.join(
pre_syscap_info_path, "SystemCapability.json"))
syscap_info_dict.update({'syscap': {'os': target_syscap_list}})
system_etc_path = os.path.join(system_path, "etc/")
if not os.path.exists(system_path):
os.mkdir(system_path)
if not os.path.exists(system_etc_path):
os.mkdir(system_etc_path)
syscap_info_json = os.path.join(
system_etc_path, "SystemCapability.json")
write_json_file(syscap_info_json, syscap_info_dict)
LogUtil.hb_info(
"generate syscap info file to '{}'".format(syscap_info_json))
target_syscap_with_part_name_list.sort(
key=lambda syscap: syscap['component'])
syscap_info_with_part_name_file = os.path.join(
system_etc_path, "syscap.json")
write_json_file(syscap_info_with_part_name_file, {
'components': target_syscap_with_part_name_list})
LogUtil.hb_info("generate syscap info with part name list to '{}'".format(
syscap_info_with_part_name_file))
if not os.path.exists(os.path.join(system_etc_path, "param/")):
os.mkdir(os.path.join(system_etc_path, "param/"))
target_syscap_for_init_file = os.path.join(
system_etc_path, "param/syscap.para")
with open(target_syscap_for_init_file, "w") as file:
file.writelines(target_syscap_for_init_list)
LogUtil.hb_info("generate target syscap for init list to '{}'".format(
target_syscap_for_init_file))
'''Description: output infos for testfwk into a json file. \
(/out/${product_name}/build_configs/infos_for_testfwk.json)
@parameter:none
@return :none
'''
def _generate_infos_for_testfwk(self):
infos_for_testfwk_file = os.path.join(self.config_output_dir,
"infos_for_testfwk.json")
parts_info = self.parts_config_info.get('parts_info')
parts_info_dict = {}
for _part_name, _parts in parts_info.items():
for _info in _parts:
parts_info_dict[_info.get('part_name')] = _info
_output_infos = {}
for _platform, _parts in self.target_platform_parts.items():
result = self._output_infos_by_platform(_parts, parts_info_dict)
_output_infos[_platform] = result
write_json_file(infos_for_testfwk_file,
_output_infos, check_changes=True)
LogUtil.hb_info("generate infos for testfwk to '{}'".format(
infos_for_testfwk_file))
'''Description: output all target platform parts into a json file \
(/out/${product_name}/build_configs/target_platforms_parts.json)
@parameter:none
@return :none
'''
def _generate_target_platform_parts(self):
target_platform_parts_file = os.path.join(self.config_output_dir,
"target_platforms_parts.json")
write_json_file(target_platform_parts_file,
self.target_platform_parts,
check_changes=True)
LogUtil.hb_info("generate target platform parts to '{}'".format(
target_platform_parts_file))
'''Description: Generate parts differences in different platforms, using phone as base. \
(/out/${product_name}/build_configs/parts_different_info.json)
@parameter: none
@return :none
'''
def _generate_part_different_info(self):
parts_different_info = self._get_parts_by_platform()
parts_different_info_file = os.path.join(self.config_output_dir,
"parts_different_info.json")
write_json_file(parts_different_info_file,
parts_different_info,
check_changes=True)
LogUtil.hb_info("generate part different info to '{}'".format(
parts_different_info_file))
'''Description: output platforms list into a gni file. \
(/out/${product_name}/build_configs/platforms_list.gni)
@parameter: none
@return: none
'''
def _generate_platforms_list(self):
platforms_list_gni_file = os.path.join(self.config_output_dir,
"platforms_list.gni")
_platforms = set(self.build_platforms)
_gni_file_content = ['target_platform_list = [', ' "{}"'.format('",\n "'.join(_platforms)), ']',
'kits_platform_list = [', ' "{}",'.format('",\n "'.join(_platforms))]
if 'phone' not in self.build_platforms:
_gni_file_content.append(' "phone"')
_gni_file_content.append(']')
write_file(platforms_list_gni_file, '\n'.join(_gni_file_content))
LogUtil.hb_info("generate platforms list to '{}'".format(
platforms_list_gni_file))
'''Description: output auto install part into a json file. \
(/out/${product_name}/build_configs/auto_install_parts.json)
@parameter: none
@return: none
'''
def _generate_auto_install_part(self):
parts_path_info = self.parts_config_info.get("parts_path_info")
auto_install_part_list = []
for part, path in parts_path_info.items():
if str(path).startswith("drivers/interface") or \
str(path).startswith("third_party"):
auto_install_part_list.append(part)
auto_install_list_file = os.path.join(
self.config_output_dir, "auto_install_parts.json")
write_json_file(auto_install_list_file, auto_install_part_list)
LogUtil.hb_info("generate auto install part to '{}'".format(
auto_install_list_file))
'''Description: output src flag into a json file. \
(/out/${product_name}/build_configs/parts_src_flag.json)
@parameter: none
@return :none
'''
def _generate_src_flag(self):
parts_src_flag_file = os.path.join(self.config_output_dir,
"parts_src_flag.json")
write_json_file(parts_src_flag_file,
self._get_parts_src_list(),
check_changes=True)
LogUtil.hb_info(
"generated parts src flag to '{}/subsystem_info/parts_src_flag.json'".format(self.config_output_dir))
'''Description: output build target list into a json file.\
(/out/${product_name}/build_configs/required_parts_targets_list.json)
@parameter: none
@return :none
'''
def _generate_required_parts_targets_list(self):
build_targets_list_file = os.path.join(self.config_output_dir,
"required_parts_targets_list.json")
write_json_file(build_targets_list_file,
list(self.required_parts_targets.values()))
LogUtil.hb_info("generate build targets list file to '{}'".format(
build_targets_list_file))
'''Description: output build target info into a json file. \
(/out/${product_name}/build_configs/required_parts_targets.json)
@parameter: none
@return: none
'''
def _generate_required_parts_targets(self):
build_targets_info_file = os.path.join(self.config_output_dir,
"required_parts_targets.json")
write_json_file(build_targets_info_file, self.required_parts_targets)
LogUtil.hb_info("generate required parts targets to '{}'".format(
build_targets_info_file))
'''Description: output platforms part by src into a json file. \
(/out/${product_name}/build_configs/platforms_parts_by_src.json)
@parameter: none
@return :none
'''
def _generate_platforms_part_by_src(self):
platforms_parts_by_src = self._get_platforms_parts()
platforms_parts_by_src_file = os.path.join(self.source_root_dir,
self.config_output_relpath,
"platforms_parts_by_src.json")
write_json_file(platforms_parts_by_src_file,
platforms_parts_by_src,
check_changes=True)
LogUtil.hb_info("generated platforms parts by src to '{}'".format(
platforms_parts_by_src_file))
'''Description: output system configs info into 4 files:[
(/out/${product_name}/build_configs/subsystem_info/parts_list.gni),
(/out/${product_name}/build_configs/subsystem_info/inner_kits_list.gni),
(/out/${product_name}/build_configs/subsystem_info/system_kits_list.gni),
(/out/${product_name}/build_configs/subsystem_info/parts_test_list.gni),
(/out/${product_name}/build_configs/subsystem_info/BUILD.gn)]
@parameter: none
@return :none
'''
def _generate_target_gn(self):
generate_targets_gn.gen_targets_gn(self.required_parts_targets,
self.config_output_dir)
'''Description: output phony targets build file. \
(/out/${product_name}/build_configs/phony_target/BUILD.gn)
@parameter: none
@return :none
'''
def _generate_phony_targets_build_file(self):
generate_targets_gn.gen_phony_targets(self.required_phony_targets,
self.config_output_dir)
'''Description: output system configs info into 2 files:[
(/out/${product_name}/build_configs/subsystem_info/${platform}-stub/BUILG.gn),
(/out/${product_name}/build_configs/subsystem_info/${platform}-stub/zframework_stub_exists.gni)]
@parameter: none
@return :none
'''
def _generate_stub_targets(self):
generate_targets_gn.gen_stub_targets(
self.parts_config_info.get('parts_kits_info'),
self.target_platform_stubs,
self.config_output_dir)
'''Description: output system capabilities into a json file. \
(/out/${product_name}/build_configs/${platform}_system_capabilities.json)
@parameter: none
@return :none
'''
def _generate_system_capabilities(self):
for platform in self.build_platforms:
platform_parts = self.target_platform_parts.get(platform)
platform_capabilities = []
for _, origin in platform_parts.items():
# parts_info.get() might be None if the part is a binary package
all_parts_variants = self.parts_info.get(origin)
if all_parts_variants is None:
continue
part = all_parts_variants[0]
if part.get('system_capabilities'):
entry = part.get('system_capabilities')
if len(entry) > 0:
platform_capabilities.extend(entry)
platform_part_json_file = os.path.join(
self.config_output_dir, "{0}_system_capabilities.json".format(platform))
write_json_file(platform_part_json_file,
sorted(platform_capabilities),
check_changes=True)
LogUtil.hb_info(
"generated system capabilities to '{}/{}_system_capabilities.json'".format(
self.config_output_dir, platform))
'''Description: output system configs info into three json files:[
(/out/${product_name}/build_configs/subsystem_info/subsystem_build_config.json),
(/out/${product_name}/build_configs/subsystem_info/src_subsystem_info.json),
(/out/${product_name}/build_configs/subsystem_info/no_src_subsystem_info.json)]
@parameter: none
@return :none
'''
def _generate_subsystem_configs(self):
# The function has been implemented in module util/loader/subsystem_info.py
LogUtil.hb_info(
"generated subsystem build config to '{}/subsystem_info/subsystem_build_config.json'".format(
self.config_output_dir))
LogUtil.hb_info(
"generated src subsystem info to '{}/subsystem_info/src_subsystem_info.json'".format(
self.config_output_dir))
LogUtil.hb_info(
"generated no src subsystem info to '{}/subsystem_info/no_src_subsystem_info.json'".format(
self.config_output_dir))
# get method
@throw_exception
def _get_build_platforms(self) -> list:
build_platforms = []
if self.build_platform_name == 'all':
build_platforms = self._all_platforms
elif self.build_platform_name in self._all_platforms:
build_platforms = [self.build_platform_name]
else:
raise OHOSException(
"The target_platform is incorrect, only allows [{}].".format(
', '.join(self._all_platforms)), "2010")
return build_platforms
def _get_parts_by_platform(self) -> dict:
parts_info = {}
if 'phone' in self.target_platform_parts:
phone_parts_list = self.target_platform_parts.get('phone').keys()
else:
phone_parts_list = []
for _platform, _parts_info in self.target_platform_parts.items():
base_parts_list = []
curr_parts_list = []
for _real_name, _original_name in _parts_info.items():
if _real_name in phone_parts_list:
base_parts_list.append(_real_name)
elif _original_name in phone_parts_list:
base_parts_list.append(_real_name)
else:
curr_parts_list.append(_real_name)
result_data = {
"base_parts_list": base_parts_list,
"curr_parts_list": curr_parts_list
}
parts_info[_platform] = result_data
return parts_info
def _get_platforms_all_parts(self) -> dict:
_dist_parts_variants = self._load_component_dist()
target_platform_parts = {}
all_parts = self._platforms_info.get('all_parts')
parts_variants = self.parts_config_info.get('parts_variants')
for _platform, _parts in all_parts.items():
if _platform not in self.build_platforms:
continue
part_name_info = {}
for part_def in _parts:
real_name, original_name = self._get_real_part_name(
part_def, _platform, parts_variants)
if real_name is None:
# find this from component_dist
real_name, original_name = self._get_real_part_name(
part_def, _platform, _dist_parts_variants)
if real_name is None:
continue
part_name_info[real_name] = original_name
target_platform_parts[_platform] = part_name_info
return target_platform_parts
def _get_platforms_all_stubs(self) -> dict:
_dist_parts_variants = self._load_component_dist()
platform_stubs = {}
all_stubs = self._platforms_info.get('all_stubs')
parts_variants = self.parts_config_info.get('parts_variants')
for _platform, _part_names in all_stubs.items():
if _platform not in self.build_platforms:
continue
stub_parts_from_src = []
stub_parts_from_dist = []
for part_name in _part_names:
real_name, original_name = self._get_real_part_name(
part_name, _platform, parts_variants)
# real_name=None means part_name doesn't exist in source tree,
# use binary in component_dist then.
if real_name is None:
# find this from component_dist
real_name, original_name = self._get_real_part_name(
part_name, _platform, _dist_parts_variants)
if real_name is None:
continue
else:
stub_sources = os.path.join(
self.source_root_dir,
"component_dist/{}-{}/api_stubs/{}/stubs_sources_list.txt" # noqa: E501
.format(self.target_os, self.target_cpu, real_name))
stub_parts_from_dist.append(
'"{}"'.format(stub_sources))
else:
stub_parts_from_src.append(real_name)
platform_stubs[_platform] = {
"src": stub_parts_from_src,
"dist": stub_parts_from_dist,
}
return platform_stubs
def _get_platforms_parts(self) -> dict:
platforms_parts = {}
src_parts_targets = self.parts_targets
src_all_parts = src_parts_targets.keys()
for _platform, _all_parts in self.target_platform_parts.items():
src_parts_list = []
no_src_parts_list = []
for _part in _all_parts.keys():
if _part in src_all_parts:
src_parts_list.append(_part)
else:
no_src_parts_list.append(_part)
_data = {
'src_parts': src_parts_list,
'no_src_parts': no_src_parts_list
}
platforms_parts[_platform] = _data
return platforms_parts
def _get_parts_src_list(self) -> list:
parts_name_map = {}
for _list in self.parts_info.values():
for _info in _list:
parts_name_map[_info.get('part_name')] = _info.get(
'origin_part_name')
_src_set = set()
for _name in self.required_parts_targets.keys():
_origin_name = parts_name_map.get(_name)
if _origin_name is None:
continue
_src_set.add(_origin_name)
return list(_src_set)
def _get_required_build_targets(self) -> dict:
required_build_targets = {}
for _p_name, _info in self.parts_targets.items():
if _p_name not in self.required_parts_targets_list:
continue
required_build_targets[_p_name] = _info
return required_build_targets
def _get_required_phony_targets(self) -> dict:
required_build_targets = {}
for _p_name, _info in self.phony_targets.items():
if _p_name not in self.required_parts_targets_list:
continue
required_build_targets[_p_name] = _info
return required_build_targets
def _get_required_build_parts_list(self) -> list:
parts_set = set()
for _parts_list in self.target_platform_parts.values():
parts_set.update(_parts_list)
return list(parts_set)
# util method
def _load_component_dist(self) -> dict:
_parts_variants_info = {}
_dir = "component_dist/{}-{}/packages_to_install".format(
self.target_os, self.target_cpu)
_file_name = "dist_parts_info.json"
_dist_parts_info_file = os.path.join(
self.source_root_dir, _dir, _file_name)
if not os.path.exists(_dist_parts_info_file):
# If the file does not exist, do nothing and return
return _parts_variants_info
_parts_info = read_json_file(_dist_parts_info_file)
if _parts_info is None:
raise Exception("read file '{}' failed.".format(
_dist_parts_info_file))
for _part_info in _parts_info:
origin_part_name = _part_info.get('origin_part_name')
if origin_part_name in _parts_variants_info:
variants = _parts_variants_info.get(origin_part_name)
else:
variants = []
_variant_name = _part_info.get('variant_name')
variants.append(_variant_name)
_parts_variants_info[origin_part_name] = variants
return _parts_variants_info
def _get_real_part_name(self, original_part_name, current_platform, parts_variants):
part_info = parts_variants.get(original_part_name)
if part_info is None:
return None, None
if current_platform in part_info and current_platform != 'phone':
real_name = '{}_{}'.format(original_part_name, current_platform)
else:
real_name = original_part_name
return real_name, original_part_name
'''Description: called by _out_infos_for_testfwk, output information by platform
@parameter:none
@return :none
'''
def _output_infos_by_platform(self, part_name_infos, parts_info_dict):
required_parts = {}
subsystem_infos = {}
for part_name, origin_part_name in part_name_infos.items():
part_info = parts_info_dict.get(part_name)
if part_info is None:
continue
if origin_part_name != part_info.get('origin_part_name'):
raise Exception("part configuration is incorrect.")
required_parts[origin_part_name] = part_info
_subsystem_name = part_info.get('subsystem_name')
if _subsystem_name in subsystem_infos:
p_list = subsystem_infos.get(_subsystem_name)
else:
p_list = []
p_list.append(origin_part_name)
subsystem_infos[_subsystem_name] = p_list
result = {}
result['subsystem_infos'] = subsystem_infos
result['part_infos'] = required_parts
return result
def _execute_loader_args_display(self):
LogUtil.hb_info('Loading configuration file...')
args = []
args.append('platforms_config_file="{}"'.format(
self.platforms_config_file))
args.append('subsystem_config_file="{}"'.format(
self.subsystem_config_file))
args.append('example_subsystem_file="{}"'.format(
self.example_subsystem_file))
args.append('exclusion_modules_config_file="{}"'.format(
self.exclusion_modules_config_file))
args.append('source_root_dir="{}"'.format(self.source_root_dir))
args.append('gn_root_out_dir="{}"'.format(self.gn_root_out_dir))
args.append('build_platform_name={}'.format(self.build_platform_name))
args.append('build_xts={}'.format(self.build_xts))
args.append('load_test_config={}'.format(self.load_test_config))
args.append('target_os={}'.format(self.target_os))
args.append('target_cpu={}'.format(self.target_cpu))
args.append('os_level={}'.format(self.os_level))
args.append('ignore_api_check={}'.format(self.ignore_api_check))
args.append('scalable_build={}'.format(self.scalable_build))
args.append('skip_partlist_check={}'.format(self.skip_partlist_check))
LogUtil.write_log(self.config.log_path,
'loader args:{}'.format(args), 'info')
def _override_components(self):
'''Description: Check whether there are components that need to be replaced, and if so,
replace the component configuration file bundle.json in subsystem_info and update
the component list generated by the preloader.
@parameter:none
@return :overrided_components
'''
parts_file = self.platforms_config_file.replace(
"platforms.build", "parts.json")
all_parts = read_json_file(parts_file)
if "parts" not in all_parts:
LogUtil.hb_warning("{} does not contain parts!".format(parts_file))
return {}
overrided = False
overrided_components = {}
all_parts = all_parts["parts"]
component_override_map = {}
for subsystem_name, build_config_info in self._subsystem_info.items():
if "build_files" not in build_config_info:
continue
# scan all bundle.json or ohos.build files with named groups
for build_file in build_config_info["build_files"]:
# ohos.build does not support overrided components
if not build_file.endswith('bundle.json'):
continue
# Only device or vendor components can do named groups extensions
if (not build_file.startswith(self.source_root_dir + 'device/')) \
and (not build_file.startswith(self.source_root_dir + 'vendor/')):
continue
# "subsystem", "name" and "override" is required
component = read_json_file(build_file).get("component")
if (not component) or (not all(key in component for key in ("subsystem", "name", "override"))):
continue
full_part_name = f"{component.get('subsystem')}:{component.get('name')}"
if full_part_name not in all_parts:
LogUtil.hb_warning("{} was not configured for this product: {}".format(
build_file, full_part_name))
continue
if self._override_one_component(self._subsystem_info, component, build_file, all_parts, overrided_components, component_override_map):
overrided = True
if overrided:
# Update parts.json and parts_config.json generated by preloader
write_json_file(parts_file, {"parts": all_parts})
parts_file = self.platforms_config_file.replace(
"platforms.build", "parts_config.json")
self._output_parts_config_json(all_parts, parts_file)
write_json_file(
f"{self.config_output_dir}/component_override_map.json", component_override_map)
return overrided_components
def _override_one_component(self, subsystem_info, component, build_file, all_parts, overrided_components, component_override_map):
'''Description: Perform a replacement of a single component and return the component list update result.
@parameter:subsystem_info, component, build_file, all_parts, overrided_components
@return :True or False(Whether replacement has been performed)
'''
splits = component["override"].split(":")
if len(splits) != 2:
LogUtil.hb_warning(
"{} override value is invalid format. Skip override process".format(build_file))
return False
overrided_subsystem = splits[0]
overrided_component = splits[1]
if overrided_subsystem not in subsystem_info:
LogUtil.hb_warning(
"{} override invalid subsystem. Skip override process".format(build_file))
return False
founded_bundle = ""
for bundle in subsystem_info[overrided_subsystem]["build_files"]:
if not bundle.endswith('bundle.json'):
continue
bundle_obj = read_json_file(bundle)
if bundle_obj.get("component", {}).get("name") == overrided_component:
founded_bundle = bundle
break
if founded_bundle:
origin_component = read_json_file(build_file).get('component')
LogUtil.hb_warning(
f"You are trying to override \"{component['override']}\" with \"{origin_component.get('subsystem')}:{origin_component.get('name')}\". \nPlease ensure that the modules in \"{component['override']}\" only rely on the interfaces of other components through \"external_deps\"")
# replace bundle.json in subsystem_info's build_files
subsystem_info[overrided_subsystem]["build_files"].remove(
founded_bundle)
# Update parts.json generated by preloader, which means that new added components will not be installed
# Ensure that the overrided components will be installed
full_partname = f"{overrided_subsystem}:{overrided_component}"
if full_partname in all_parts:
all_parts.remove(full_partname)
overrided_components[f"{component['subsystem']}:{component['name']}"] = {
'subsystem': overrided_subsystem,
'partName': overrided_component
}
component_override_map[overrided_component] = component["name"]
return True
LogUtil.hb_warning(
"{}:{} is not configured in product, \new add component will be installed!".format(
overrided_subsystem, overrided_component))
return False
def _output_parts_config_json(self, all_parts, output_file):
'''Description: Update the parts list file generated by preloader
@parameter: all_parts, output_file
@return :none
'''
parts_config = {}
for part in all_parts:
part = part.replace(":", "_")
part = part.replace("-", "_")
part = part.replace(".", "_")
part = part.replace("/", "_")
parts_config[part] = True
write_json_file(output_file, parts_config)