1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2022 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import os 17import json 18import sys 19 20sys.path.append(os.path.dirname(os.path.abspath(__file__))) 21from sort_sa_by_bootphase import SARearrangement 22import sa_info_config_errors as json_err # noqa E402 23 24 25class JsonSAInfoMerger(object): 26 class SAInfoCollector(object): 27 """ 28 Class for collecting sa info pieces shared with same process name 29 """ 30 def __init__(self, process_name, wdir): 31 self.process_name = process_name 32 self.systemabilities = [] 33 self.wdir = wdir 34 35 @property 36 def output_filename(self): 37 basename = self.process_name + '.json' 38 return os.path.join(self.wdir, basename) 39 40 def add_systemability_info(self, systemability): 41 self.systemabilities += systemability 42 43 def merge_sa_info(self): 44 """ 45 Write all pieces of sa info shared with same process to a new file 46 """ 47 xml_lines = {} 48 xml_lines['process'] = self.process_name 49 xml_lines['systemability'] = self.systemabilities 50 if not os.path.exists(self.wdir): 51 os.mkdir(self.wdir) 52 with os.fdopen(os.open(self.output_filename, os.O_RDWR | os.O_CREAT, 0o640), 'w') as json_files: 53 json.dump(xml_lines, json_files, indent=4, ensure_ascii=False) 54 55 def __init__(self): 56 self.process_sas_dict = {} 57 self.output_filelist = [] 58 59 def add_to_output_filelist(self, infile: str): 60 self.output_filelist.append(os.path.join(self.output_dir, infile)) 61 62 def merge(self, sa_info_filelist, output_dir): 63 return self.__merge(sa_info_filelist, output_dir) 64 65 def parse_json_file(self, file: str): 66 with open(file, 'r') as json_files: 67 data = json.load(json_files) 68 _format = 'one and only one {} tag is expected, actually {} is found' 69 # check process tag 70 if 'process' not in data or data['process'] == '': 71 raise json_err.BadFormatJsonError('provide a valid value for process', file) 72 process_name = data['process'] 73 if self.process_sas_dict.get(process_name) is None: 74 # create a new collector if a new process tag is found 75 sa_info_collector = self.SAInfoCollector(process_name, self.temp_dir) 76 self.process_sas_dict[process_name] = sa_info_collector 77 self.add_to_output_filelist(process_name + '.json') 78 else: 79 sa_info_collector = self.process_sas_dict.get(process_name) 80 # check systemability tag 81 if 'systemability' not in data or data['systemability'] == '': 82 raise json_err.BadFormatJsonError('provide a valid value for systemability', file) 83 sys_count = len(data['systemability']) 84 if sys_count != 1: 85 raise json_err.BadFormatJsonError(_format.format('systemabiltiy', sys_count), file) 86 sys_value = data['systemability'] 87 if 'name' not in sys_value[0] or 'libpath' not in sys_value[0]: 88 raise json_err.BadFormatJsonError('systemability must have name and libpath', file) 89 sa_info_collector.add_systemability_info(sys_value) 90 91 def __merge(self, sa_info_filelist: list, path_merges: str): 92 """ 93 merge the json files of sa_info_filelist 94 :param sa_info_filelist : input_files 95 :param path_merges : merges_path 96 """ 97 self.temp_dir = path_merges 98 self.output_dir = path_merges 99 for file in sa_info_filelist: 100 self.parse_json_file(file) 101 global_ordered_systemability_names = [] 102 global_systemability_deps_dict = {} 103 # merge systemability info for each process 104 for process, collector in self.process_sas_dict.items(): 105 rearragement = SARearrangement() 106 collector.merge_sa_info() 107 merged_file = collector.output_filename 108 rearragement.sort(merged_file, merged_file) 109 # get deps info for later detecting globally circular 110 deps_info = rearragement.get_deps_info() 111 global_ordered_systemability_names += deps_info[0] 112 global_systemability_deps_dict.update(deps_info[1]) 113 # detect possible cross-process circular dependency 114 try: 115 SARearrangement.detect_invalid_dependency_globally( 116 global_ordered_systemability_names, 117 global_systemability_deps_dict) 118 except json_err.CircularDependencyError as error: 119 for _file in self.output_filelist: 120 try: 121 os.remove(_file) 122 except OSError: 123 pass 124 raise json_err.CrossProcessCircularDependencyError(error) 125 # finally return an output filelist 126 return self.output_filelist 127