1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright (c) 2024 Huawei Device Co., Ltd.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import json
19import os
20import sys
21import stat
22
23precise_repo_xts = sys.argv[1]
24DEEP = int(sys.argv[2]) if len(sys.argv) > 2 else -1
25home = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
26manifest_home = os.path.join(home, ".repo")
27preloader_path = os.path.join(home, "out", "preloader")
28PRECISE_GNI_NAME = "precise_run.gni"
29DEPENDS_TREE_NAME = "depends_tree.txt"
30F_DEPENDS_NAME = "f_depends.txt"
31MAX_PRECISE_PR_NUM = 20
32
33# 首层依赖关系dist
34dependency_dist = {}
35# 全量编译白名单
36whitelist = {"test/xts/acts", "build"}
37
38
39def get_f_dependes_dist(path):
40    count = 0
41    # 遍历目录下的所有文件和子目录
42    for root, dirs, files in os.walk(path):
43        for file in files:
44            if file == 'bundle.json':
45                count = count + 1
46                # 构建完整的文件路径
47                file_path = os.path.join(root, file)
48                # 读取 JSON 文件并转换为 Python 对象
49                with open(file_path, 'r', encoding='utf-8') as f:
50                    json_data = json.load(f)
51                    bundle_name = json_data['name'].split('/')[-1]
52                    if "deps" not in json_data['component']:
53                        continue
54                    deps = json_data['component']['deps']
55                    # 依赖关系额写入dependency_dist
56                    if bundle_name not in dependency_dist:
57                        dependency_dist[bundle_name] = []
58                    if "components" in deps:
59                        components_defs = deps['components']
60                        for c_def in components_defs:
61                            if c_def in dependency_dist:
62                                dependency_dist[c_def].append(bundle_name)
63                            else:
64                                dependency_dist[c_def] = [bundle_name]
65                    if "third_party" in deps:
66                        third_party_defs = deps['third_party']
67                        for t_def in third_party_defs:
68                            if t_def in dependency_dist:
69                                dependency_dist[t_def].append(bundle_name)
70                            else:
71                                dependency_dist[t_def] = [bundle_name]
72    print(count)
73
74
75def getbundname(path_list):
76    print(path_list)
77    bundle_list = []
78    for path in path_list:
79        # 读取JSON文件并获取指定key的value
80        with open(os.path.join(home, path, "bundle.json"), 'r') as file:
81            data = json.load(file)
82        bundle_list.append(data['component']['name'])
83    return bundle_list
84
85
86def get_all_dependencies(nodes, dependencies):
87    visited = set()  # 存储已访问的节点
88    string_buffer = []
89
90    def dfs(node, num, string_buffer):
91        string_buffer.append("  " * num + node)  # 追加内容到列表
92        if node in visited:
93            return
94        if DEEP != -1 and num > DEEP:
95            return
96        visited.add(node)
97        if node in dependencies:
98            for dependency in dependencies[node]:
99                dfs(dependency, num + 1, string_buffer)  # 传递可变对象进行修改
100
101    for node in nodes:
102        dfs(node, 0, string_buffer)
103
104    return visited, string_buffer
105
106
107def write_precise_gni(depends_list, file_name):
108    # 将数组转换为字符串形式,例如使用逗号分隔
109    array_str = json.dumps(list(depends_list))
110
111    # 打开文件并写入数组字符串
112    file_descriptor = os.open(file_name, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
113    with os.fdopen(file_descriptor, 'w') as file:
114        file.write("precise_run=")
115        file.write(array_str)
116
117
118def write_file(depends_list, file_name):
119    file_descriptor = os.open(file_name, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP)
120    with os.fdopen(file_descriptor, 'w') as f:
121        json.dump(depends_list, f, indent=4)
122
123
124def run(precise_repo_xts_list):
125    # pr数>MAX或在白名单中的
126    if len(precise_repo_xts_list) >= MAX_PRECISE_PR_NUM or any(item in precise_repo_xts_list for item in whitelist):
127        depends_tree = "all"
128        depends_list = {"all"}
129    else:
130        try:
131            # 获取bundle_name_list
132            bundlelist = getbundname(precise_repo_xts_list)
133            # 计算首层依赖map
134            get_f_dependes_dist(home)
135            print(bundlelist)
136            # 获取全部需要跑的bundlename
137            depends_list, depends_tree = get_all_dependencies(bundlelist, dependency_dist)
138            depends_list.add("acts")
139            print(depends_list)
140        except Exception as e:
141            print("发生异常:", str(e))
142            depends_tree = "all"
143            depends_list = {"all"}
144    # 依赖树输出
145    write_file(depends_tree, os.path.join(preloader_path, DEPENDS_TREE_NAME))
146    # 写入gni文件
147    write_precise_gni(depends_list, os.path.join(preloader_path, PRECISE_GNI_NAME))
148
149
150if __name__ == '__main__':
151    print("counting dependencies start")
152    run(precise_repo_xts.split(','))
153    print("counting dependencies finished")