1#!/usr/bin/env python3
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 argparse
17import os
18import stat
19import json
20
21
22class ErrorInfo:
23    g_subsystem_path_error = []  # subsystem path exist in subsystem_config.json
24    g_component_path_empty = []  # bundle.json path which cant get component path.
25    g_component_abs_path = []    # destPath can't be absolute path.
26
27
28def get_subsystem_components(ohos_path: str):
29    subsystem_json_path = os.path.join(
30        ohos_path, r"build/subsystem_config.json")
31    subsystem_item = {}
32
33    with open(subsystem_json_path, 'rb') as file:
34        subsystem_json = json.load(file)
35
36    bundle_json_list = []
37    subsystem_name = ""
38    # get sunsystems
39    for i in subsystem_json:
40        subsystem_name = subsystem_json[i]["name"]
41        subsystem_path = os.path.join(ohos_path, subsystem_json[i]["path"])
42        if not os.path.exists(subsystem_path):
43            ErrorInfo.g_subsystem_path_error.append(subsystem_path)
44            continue
45        cmd = 'find %s -name bundle.json' % subsystem_path
46        with os.popen(cmd) as input_cmd:
47            bundle_json_list = input_cmd.readlines()
48
49        # get components
50        component_list = []
51        for j in bundle_json_list:
52            bundle_path = j.strip()
53            with open(bundle_path, 'rb') as bundle_file:
54                bundle_json = json.load(bundle_file)
55            component_item = {}
56            if 'segment' in bundle_json and 'destPath' in bundle_json["segment"]:
57                destpath = bundle_json["segment"]["destPath"]
58                component_item[bundle_json["component"]["name"]] = destpath
59                if os.path.isabs(destpath):
60                    ErrorInfo.g_component_abs_path.append(destpath)
61            else:
62                component_item[bundle_json["component"]["name"]] = \
63                                "Unknow. Please check %s" % bundle_path
64                ErrorInfo.g_component_path_empty.append(bundle_path)
65            component_list.append(component_item)
66
67        subsystem_item[subsystem_name] = component_list
68    return subsystem_item
69
70
71def get_subsystem_components_modified(ohos_root: str) -> dict:
72    ret = dict()
73
74    subsystem_info = get_subsystem_components(ohos_root)
75    if subsystem_info is None:
76        return ret
77    for subsystem_k, subsystem_v in subsystem_info.items():
78        for component in subsystem_v:
79            for key, value in component.items():
80                ret.update({value: {'subsystem': subsystem_k, 'component': key}})
81    return ret
82
83
84def export_to_json(subsystem_item: dict,
85                   output_path: str,
86                   output_name: str = "subsystem_component_path.json"):
87    subsystem_item_json = json.dumps(
88        subsystem_item, indent=4, separators=(', ', ': '))
89
90    out_abs_path = os.path.abspath(
91        os.path.normpath(output_path)) + '/' + output_name
92    flags = os.O_WRONLY | os.O_CREAT
93    modes = stat.S_IWUSR | stat.S_IRUSR
94    with os.fdopen(os.open(out_abs_path, flags, modes), 'w') as file:
95        file.write(subsystem_item_json)
96    print("output path: " + out_abs_path)
97
98
99def parse_args():
100    parser = argparse.ArgumentParser()
101    parser.add_argument("project", help="project root path.", type=str)
102    parser.add_argument("-o", "--outpath",
103                        help="specify an output path.", type=str)
104    args = parser.parse_args()
105
106    ohos_path = os.path.abspath(args.project)
107    if not is_project(ohos_path):
108        print("'" + ohos_path + "' is not a valid project path.")
109        exit(1)
110
111    output_path = r'.'
112    if args.outpath:
113        output_path = args.outpath
114
115    return ohos_path, output_path
116
117
118def is_project(path: str) -> bool:
119    '''
120    @func: 判断是否源码工程。
121    @note: 通过是否含有 .repo/manifests 目录粗略判断。
122    '''
123    norm_parh = os.path.normpath(path)
124    return os.path.exists(norm_parh + '/.repo/manifests')
125
126
127def print_warning_info():
128    '''
129    @func: 打印一些异常信息。
130    '''
131    def print_list(print_list):
132        for i in print_list:
133            print('\t' + i)
134
135    if ErrorInfo.g_component_path_empty or \
136        ErrorInfo.g_component_abs_path:
137        print("------------ warning info ------------------")
138
139    if ErrorInfo.g_subsystem_path_error:
140        print("subsystem path not exist:")
141        print_list(ErrorInfo.g_subsystem_path_error)
142
143    if ErrorInfo.g_component_path_empty:
144        print("can't find destPath in:")
145        print_list(ErrorInfo.g_component_path_empty)
146
147    if ErrorInfo.g_component_abs_path:
148        print("destPath can't be absolute path:")
149        print_list(ErrorInfo.g_component_abs_path)
150
151
152if __name__ == '__main__':
153    oh_path, out_path = parse_args()
154    info = get_subsystem_components(oh_path)
155    export_to_json(info, out_path)
156    print_warning_info()
157