15f9996aaSopenharmony_ci#!/usr/bin/env python 25f9996aaSopenharmony_ci# -*- coding: utf-8 -*- 35f9996aaSopenharmony_ci# Copyright (c) 2022 Huawei Device Co., Ltd. 45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License. 65f9996aaSopenharmony_ci# You may obtain a copy of the License at 75f9996aaSopenharmony_ci# 85f9996aaSopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 95f9996aaSopenharmony_ci# 105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software 115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, 125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and 145f9996aaSopenharmony_ci# limitations under the License. 155f9996aaSopenharmony_ci 165f9996aaSopenharmony_ciimport os 175f9996aaSopenharmony_ciimport json 185f9996aaSopenharmony_ciimport sys 195f9996aaSopenharmony_ci 205f9996aaSopenharmony_cisys.path.append(os.path.dirname(os.path.abspath(__file__))) 215f9996aaSopenharmony_cifrom sort_sa_by_bootphase import SARearrangement 225f9996aaSopenharmony_ciimport sa_info_config_errors as json_err # noqa E402 235f9996aaSopenharmony_ci 245f9996aaSopenharmony_ci 255f9996aaSopenharmony_ciclass JsonSAInfoMerger(object): 265f9996aaSopenharmony_ci class SAInfoCollector(object): 275f9996aaSopenharmony_ci """ 285f9996aaSopenharmony_ci Class for collecting sa info pieces shared with same process name 295f9996aaSopenharmony_ci """ 305f9996aaSopenharmony_ci def __init__(self, process_name, wdir): 315f9996aaSopenharmony_ci self.process_name = process_name 325f9996aaSopenharmony_ci self.systemabilities = [] 335f9996aaSopenharmony_ci self.wdir = wdir 345f9996aaSopenharmony_ci 355f9996aaSopenharmony_ci @property 365f9996aaSopenharmony_ci def output_filename(self): 375f9996aaSopenharmony_ci basename = self.process_name + '.json' 385f9996aaSopenharmony_ci return os.path.join(self.wdir, basename) 395f9996aaSopenharmony_ci 405f9996aaSopenharmony_ci def add_systemability_info(self, systemability): 415f9996aaSopenharmony_ci self.systemabilities += systemability 425f9996aaSopenharmony_ci 435f9996aaSopenharmony_ci def merge_sa_info(self): 445f9996aaSopenharmony_ci """ 455f9996aaSopenharmony_ci Write all pieces of sa info shared with same process to a new file 465f9996aaSopenharmony_ci """ 475f9996aaSopenharmony_ci xml_lines = {} 485f9996aaSopenharmony_ci xml_lines['process'] = self.process_name 495f9996aaSopenharmony_ci xml_lines['systemability'] = self.systemabilities 505f9996aaSopenharmony_ci if not os.path.exists(self.wdir): 515f9996aaSopenharmony_ci os.mkdir(self.wdir) 525f9996aaSopenharmony_ci with os.fdopen(os.open(self.output_filename, os.O_RDWR | os.O_CREAT, 0o640), 'w') as json_files: 535f9996aaSopenharmony_ci json.dump(xml_lines, json_files, indent=4, ensure_ascii=False) 545f9996aaSopenharmony_ci 555f9996aaSopenharmony_ci def __init__(self): 565f9996aaSopenharmony_ci self.process_sas_dict = {} 575f9996aaSopenharmony_ci self.output_filelist = [] 585f9996aaSopenharmony_ci 595f9996aaSopenharmony_ci def add_to_output_filelist(self, infile: str): 605f9996aaSopenharmony_ci self.output_filelist.append(os.path.join(self.output_dir, infile)) 615f9996aaSopenharmony_ci 625f9996aaSopenharmony_ci def merge(self, sa_info_filelist, output_dir): 635f9996aaSopenharmony_ci return self.__merge(sa_info_filelist, output_dir) 645f9996aaSopenharmony_ci 655f9996aaSopenharmony_ci def parse_json_file(self, file: str): 665f9996aaSopenharmony_ci with open(file, 'r') as json_files: 675f9996aaSopenharmony_ci data = json.load(json_files) 685f9996aaSopenharmony_ci _format = 'one and only one {} tag is expected, actually {} is found' 695f9996aaSopenharmony_ci # check process tag 705f9996aaSopenharmony_ci if 'process' not in data or data['process'] == '': 715f9996aaSopenharmony_ci raise json_err.BadFormatJsonError('provide a valid value for process', file) 725f9996aaSopenharmony_ci process_name = data['process'] 735f9996aaSopenharmony_ci if self.process_sas_dict.get(process_name) is None: 745f9996aaSopenharmony_ci # create a new collector if a new process tag is found 755f9996aaSopenharmony_ci sa_info_collector = self.SAInfoCollector(process_name, self.temp_dir) 765f9996aaSopenharmony_ci self.process_sas_dict[process_name] = sa_info_collector 775f9996aaSopenharmony_ci self.add_to_output_filelist(process_name + '.json') 785f9996aaSopenharmony_ci else: 795f9996aaSopenharmony_ci sa_info_collector = self.process_sas_dict.get(process_name) 805f9996aaSopenharmony_ci # check systemability tag 815f9996aaSopenharmony_ci if 'systemability' not in data or data['systemability'] == '': 825f9996aaSopenharmony_ci raise json_err.BadFormatJsonError('provide a valid value for systemability', file) 835f9996aaSopenharmony_ci sys_count = len(data['systemability']) 845f9996aaSopenharmony_ci if sys_count != 1: 855f9996aaSopenharmony_ci raise json_err.BadFormatJsonError(_format.format('systemabiltiy', sys_count), file) 865f9996aaSopenharmony_ci sys_value = data['systemability'] 875f9996aaSopenharmony_ci if 'name' not in sys_value[0] or 'libpath' not in sys_value[0]: 885f9996aaSopenharmony_ci raise json_err.BadFormatJsonError('systemability must have name and libpath', file) 895f9996aaSopenharmony_ci sa_info_collector.add_systemability_info(sys_value) 905f9996aaSopenharmony_ci 915f9996aaSopenharmony_ci def __merge(self, sa_info_filelist: list, path_merges: str): 925f9996aaSopenharmony_ci """ 935f9996aaSopenharmony_ci merge the json files of sa_info_filelist 945f9996aaSopenharmony_ci :param sa_info_filelist : input_files 955f9996aaSopenharmony_ci :param path_merges : merges_path 965f9996aaSopenharmony_ci """ 975f9996aaSopenharmony_ci self.temp_dir = path_merges 985f9996aaSopenharmony_ci self.output_dir = path_merges 995f9996aaSopenharmony_ci for file in sa_info_filelist: 1005f9996aaSopenharmony_ci self.parse_json_file(file) 1015f9996aaSopenharmony_ci global_ordered_systemability_names = [] 1025f9996aaSopenharmony_ci global_systemability_deps_dict = {} 1035f9996aaSopenharmony_ci # merge systemability info for each process 1045f9996aaSopenharmony_ci for process, collector in self.process_sas_dict.items(): 1055f9996aaSopenharmony_ci rearragement = SARearrangement() 1065f9996aaSopenharmony_ci collector.merge_sa_info() 1075f9996aaSopenharmony_ci merged_file = collector.output_filename 1085f9996aaSopenharmony_ci rearragement.sort(merged_file, merged_file) 1095f9996aaSopenharmony_ci # get deps info for later detecting globally circular 1105f9996aaSopenharmony_ci deps_info = rearragement.get_deps_info() 1115f9996aaSopenharmony_ci global_ordered_systemability_names += deps_info[0] 1125f9996aaSopenharmony_ci global_systemability_deps_dict.update(deps_info[1]) 1135f9996aaSopenharmony_ci # detect possible cross-process circular dependency 1145f9996aaSopenharmony_ci try: 1155f9996aaSopenharmony_ci SARearrangement.detect_invalid_dependency_globally( 1165f9996aaSopenharmony_ci global_ordered_systemability_names, 1175f9996aaSopenharmony_ci global_systemability_deps_dict) 1185f9996aaSopenharmony_ci except json_err.CircularDependencyError as error: 1195f9996aaSopenharmony_ci for _file in self.output_filelist: 1205f9996aaSopenharmony_ci try: 1215f9996aaSopenharmony_ci os.remove(_file) 1225f9996aaSopenharmony_ci except OSError: 1235f9996aaSopenharmony_ci pass 1245f9996aaSopenharmony_ci raise json_err.CrossProcessCircularDependencyError(error) 1255f9996aaSopenharmony_ci # finally return an output filelist 1265f9996aaSopenharmony_ci return self.output_filelist 127