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