• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1import os
2import json
3
4
5class GnCommonTool:
6    """
7    处理BUILD.gn文件的通用方法
8    """
9
10    @classmethod
11    def is_gn_variable(cls, target: str, has_quote: bool = True):
12        """
13        判断target是否是gn中的变量:
14        规则:如果是有引号的模式,则没有引号均认为是变量,有引号的情况下,如有是"$xxx"的模式,则认为xxx是变量;如果是无引号模式,则只要$开头就认为是变量
15        b = "xxx"
16        c = b
17        c = "${b}"
18        "$p"
19        """
20        target = target.strip()
21        if not has_quote:
22            return target.startswith("$")
23        if target.startswith('"') and target.endswith('"'):
24            target = target.strip('"')
25            if target.startswith("${") and target.endswith("}"):
26                return True
27            elif target.startswith("$"):
28                return True
29            return False
30        else:
31            return True
32
33    # 给__find_variables_in_gn用的,减少io
34    __var_val_mem_dict = dict()
35
36    @classmethod
37    def find_variables_in_gn(cls, var_name_tuple: tuple, path: str, stop_tail: str = "home") -> tuple:
38        """
39        同时查找多个gn变量的值
40        var_name_tuple:变量名的tuple,变量名应是未经过处理后的,如:
41        xxx
42        "${xxx}"
43        "$xxx"
44        """
45
46        if os.path.isfile(path):
47            path = os.path.split(path)[0]
48        var_val_dict = dict()
49        not_found_count = len(var_name_tuple)
50        for var in var_name_tuple:
51            val = GnCommonTool.__var_val_mem_dict.get(var)
52            if val is not None:
53                not_found_count -= 1
54            var_val_dict[var] = val
55        while not path.endswith(stop_tail) and not_found_count != 0:
56            for v in var_name_tuple:
57                cmd = r"grep -Ern '^( *){} *= *\".*?\"' --include=*.gn* {}| grep -Ev '\$' | head -n 1 | grep -E '\".*\"' -wo".format(
58                    v.strip('"').lstrip("${").rstrip('}'), path)
59                output = os.popen(cmd).read().strip().strip('"')
60                if len(output) != 0:
61                    not_found_count -= 1
62                    var_val_dict[v] = output
63                    GnCommonTool.__var_val_mem_dict[v] = output
64            path = os.path.split(path)[0]
65        return tuple(var_val_dict.values())
66
67    @classmethod
68    def __find_part_subsystem_from_bundle(cls, gnpath: str, stop_tail: str = "home") -> tuple:
69        """
70        根据BUILD.gn的全路径,一层层往上面查找bundle.json文件,
71        并从bundle.json中查找part_name和subsystem
72        """
73        filename = "bundle.json"
74        part_name = None
75        subsystem_name = None
76        if stop_tail not in gnpath:
77            return part_name, subsystem_name
78        if os.path.isfile(gnpath):
79            gnpath = os.path.split(gnpath)[0]
80        while not gnpath.endswith(stop_tail):
81            bundle_path = os.path.join(gnpath, filename)
82            if not os.path.isfile(bundle_path):  # 如果该文件不在该目录下
83                gnpath = os.path.split(gnpath)[0]
84                continue
85            with open(bundle_path, 'r', encoding='utf-8') as f:
86                content = json.load(f)
87                try:
88                    part_name = content["component"]["name"]
89                    subsystem_name = content["component"]["subsystem"]
90                except KeyError:
91                    ...
92                finally:
93                    break
94        part_name = None if (part_name is not None and len(
95            part_name) == 0) else part_name
96        subsystem_name = None if (subsystem_name is not None and len(
97            subsystem_name) == 0) else subsystem_name
98        return part_name, subsystem_name
99
100    @classmethod
101    def find_part_subsystem(cls, gn_file: str, project_path: str) -> tuple:
102        """
103        查找gn_file对应的part_name和subsystem
104        如果在gn中找不到,就到bundle.json中去找
105        """
106        part_name = None
107        subsystem_name = None
108        part_var_flag = False  # 标识这个变量从gn中取出的原始值是不是变量
109        subsystem_var_flag = False
110        var_list = list()
111        part_name_pattern = r"part_name *=\s*\S*"
112        subsystem_pattern = r"subsystem_name *=\s*\S*"
113        meta_grep_pattern = "grep -E '{}' {} | head -n 1"
114        part_cmd = meta_grep_pattern.format(part_name_pattern, gn_file)
115        subsystem_cmd = meta_grep_pattern.format(subsystem_pattern, gn_file)
116        part = os.popen(part_cmd).read().strip()
117        if len(part) != 0:
118            part = part.split('=')[-1].strip()
119            if GnCommonTool.is_gn_variable(part):
120                part_var_flag = True
121                var_list.append(part)
122            else:
123                part_name = part.strip('"')
124                if len(part_name) == 0:
125                    part_name = None
126        subsystem = os.popen(subsystem_cmd).read().strip()
127        if len(subsystem) != 0:  # 这里是只是看有没有grep到关键字
128            subsystem = subsystem.split('=')[-1].strip()
129            if GnCommonTool.is_gn_variable(subsystem):
130                subsystem_var_flag = True
131                var_list.append(subsystem)
132            else:
133                subsystem_name = subsystem.strip('"')
134                if len(subsystem_name) == 0:
135                    subsystem_name = None
136        if part_var_flag and subsystem_var_flag:
137            part_name, subsystem_name = GnCommonTool.find_variables_in_gn(
138                tuple(var_list), gn_file, project_path)
139        elif part_var_flag:
140            t = GnCommonTool.find_variables_in_gn(
141                tuple(var_list), gn_file, project_path)[0]
142            part_name = t if t is not None and len(t) != 0 else part_name
143        elif subsystem_var_flag:
144            t = GnCommonTool.find_variables_in_gn(
145                tuple(var_list), gn_file, project_path)[0]
146            subsystem_name = t if t is not None and len(
147                t) != 0 else subsystem_name
148        if part_name is not None and subsystem_name is not None:
149            return part_name, subsystem_name
150        # 如果有一个没有找到,就要一层层去找bundle.json文件
151        t_part_name, t_subsystem_name = cls.__find_part_subsystem_from_bundle(
152            gn_file, stop_tail=project_path)
153        if t_part_name is not None:
154            part_name = t_part_name
155        if t_subsystem_name is not None:
156            subsystem_name = t_subsystem_name
157        return part_name, subsystem_name
158