• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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            file_node = os.open(self.output_filename, os.O_RDWR | os.O_CREAT, 0o640)
53            with os.fdopen(file_node, 'w') as json_files:
54                json.dump(xml_lines, json_files, indent=4, ensure_ascii=False)
55
56    def __init__(self):
57        self.process_sas_dict = {}
58        self.output_filelist = []
59
60    def __add_to_output_filelist(self, infile: str):
61        self.output_filelist.append(os.path.join(self.output_dir, infile))
62
63    def __parse_json_file(self, file: str):
64        with open(file, 'r') as json_files:
65            data = json.load(json_files)
66            _format = 'one and only one {} tag is expected, actually {} is found'
67        # check process tag
68        if 'process' not in data or data['process'] == '':
69            raise json_err.BadFormatJsonError('provide a valid value for process', file)
70        process_name = data['process']
71        if self.process_sas_dict.get(process_name) is None:
72            # create a new collector if a new process tag is found
73            sa_info_collector = self.SAInfoCollector(process_name, self.temp_dir)
74            self.process_sas_dict[process_name] = sa_info_collector
75            self.__add_to_output_filelist(process_name + '.json')
76        else:
77            sa_info_collector = self.process_sas_dict.get(process_name)
78        # check systemability tag
79        if 'systemability' not in data or data['systemability'] == '':
80            raise  json_err.BadFormatJsonError('provide a valid value for systemability', file)
81        sys_count = len(data['systemability'])
82        if sys_count != 1:
83            raise  json_err.BadFormatJsonError(_format.format('systemabiltiy', sys_count), file)
84        sys_value = data['systemability']
85        if 'name' not in sys_value[0] or 'libpath' not in sys_value[0]:
86            raise json_err.BadFormatJsonError('systemability must have name and libpath', file)
87        sa_info_collector.add_systemability_info(sys_value)
88
89    def __merge(self, sa_info_filelist: list, path_merges: str):
90        """
91        merge the json files of sa_info_filelist
92        :param sa_info_filelist : input_files
93        :param path_merges : merges_path
94        """
95        self.temp_dir = path_merges
96        self.output_dir = path_merges
97        for file in sa_info_filelist:
98            self.__parse_json_file(file)
99        global_ordered_systemability_names = []
100        global_systemability_deps_dict = {}
101        # merge systemability info for each process
102        for process, collector in self.process_sas_dict.items():
103            rearragement = SARearrangement()
104            collector.merge_sa_info()
105            merged_file = collector.output_filename
106            rearragement.sort(merged_file, merged_file)
107            # get deps info for later detecting globally circular
108            deps_info = rearragement.get_deps_info()
109            global_ordered_systemability_names += deps_info[0]
110            global_systemability_deps_dict.update(deps_info[1])
111        # detect possible cross-process circular dependency
112        try:
113            SARearrangement.detect_invalid_dependency_globally(
114                global_ordered_systemability_names,
115                global_systemability_deps_dict)
116        except json_err.CircularDependencyError as error:
117            for _file in self.output_filelist:
118                try:
119                    os.remove(_file)
120                except OSError:
121                    pass
122            raise json_err.CrossProcessCircularDependencyError(error)
123        # finally return an output filelist
124        return self.output_filelist
125
126    def merge(self, sa_info_filelist, output_dir):
127        return self.__merge(sa_info_filelist, output_dir)
128