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 16# This file contains some Classes for gn's BUILD.gn 17 18import os 19import logging 20import re 21import ast 22import json 23import collections 24from typing import * 25if __name__ == '__main__': 26 from basic_tool import BasicTool 27else: 28 from pkgs.basic_tool import BasicTool 29 30 31class GnCommonTool: 32 """ 33 处理BUILD.gn文件的通用方法 34 """ 35 36 @classmethod 37 def _find_gn_variable_list(cls, content: str) -> List: 38 """ 39 获取s中${xxx}或$xxx形式的gn变量 40 :param content: 待查找的字符串 41 :param sep: 分隔符,使用本分隔符将内容进行分隔然后逐一查找 42 :return: 变量名及其符号,eg:${abc}、$abc 43 :FIXME 没有对a = 'a' b = a中的b这种形式进行处理 44 """ 45 result = list() 46 splited = content.split(os.sep) 47 patern = re.compile(r"\${.*?}") 48 for item in splited: 49 m = re.findall(patern, item) 50 result.extend(m) 51 if len(m) == 0 and "$" in item: 52 item = item.strip('"') 53 result.append(item[item.index("$"):]) 54 return result 55 56 @classmethod 57 def is_gn_variable(cls, target: str, quote_processed: bool = False): 58 """ 59 判断target是否是gn中的变量: 60 规则:如果是quote_processed is False,则没有引号均认为是变量,有引号的情况下,如果是"$xxx"或${xx}的模式,则认为xxx是变量; 61 如果quote_processed is True,则只要$开头就认为是变量 62 b = "xxx" 63 c = b 64 c = "${b}" 65 "$p" 66 :param target: 要进行判断的字符串对象 67 :param quote_processed: 引号是否已经去除 68 :return: target是否为gn中的变量 69 """ 70 target = target.strip() 71 if quote_processed: 72 return target.startswith("$") 73 if target.startswith('"') and target.endswith('"'): 74 target = target.strip('"') 75 if target.startswith("${") and target.endswith("}"): 76 return True 77 elif target.startswith("$"): 78 return True 79 return False 80 else: 81 return True 82 83 @classmethod 84 def contains_gn_variable(cls, s: str, quote_processed: bool = False): 85 """ 86 判断字符串s中是否包含gn变量 87 """ 88 return cls.is_gn_variable(s, quote_processed) or ("$" in s) 89 90 # 给__find_variables_in_gn用的,减少io 91 __var_val_mem_dict = collections.defaultdict(str) 92 93 @classmethod 94 def find_variables_in_gn(cls, var_name_tuple: tuple, path: str, stop_tail: str = "home", use_cache: bool = False) -> \ 95 List[str]: 96 """ 97 同时查找多个gn变量的值 98 var_name_tuple:变量名的tuple,变量名应是未经过处理后的,如: 99 xxx 100 "${xxx}" 101 "$xxx" 102 :param var_name_tuple: 待查找的变量名的列表 103 :param path: 变量名所在文件的路径 104 :param stop_tail: 当path以stop_tail结尾时,停止查找 105 :param use_cache: 是否使用缓存 106 :return: 变量值的列表 107 """ 108 if os.path.isfile(path): 109 path, _ = os.path.split(path) 110 var_val_dict = collections.defaultdict(str) 111 not_found_count = len(var_name_tuple) 112 if use_cache: 113 for var in var_name_tuple: 114 val = GnCommonTool.__var_val_mem_dict[var] 115 if val: 116 not_found_count -= 1 117 var_val_dict[var] = val 118 while (stop_tail in path) and not_found_count: 119 for v in var_name_tuple: 120 pv = v.strip('"').lstrip("${").rstrip('}') 121 # 先直接grep出pv *= *\".*?\"的 122 # 然后排除含有$符的 123 # 再取第一个 124 # 最后只取引号内的 125 cmd = fr"grep -Ern '{pv} *= *\".*?\"' --include=*.gn* {path} | grep -Ev '\$' " \ 126 r"| head -n 1 | grep -E '\".*\"' -wo" 127 output = BasicTool.execute(cmd, lambda x: x.strip().strip('"')) 128 # backup:end 129 if not output: 130 continue 131 not_found_count -= 1 132 var_val_dict[v] = output 133 GnCommonTool.__var_val_mem_dict[v] = output 134 path, _ = os.path.split(path) 135 return list(var_val_dict.values()) 136 137 @classmethod 138 def replace_gn_variables(cls, s: str, gn_path: str, stop_tail: str) -> str: 139 """ 140 替换字符串中的gn变量名为其值,注意,没有对s是否真的包含gn变量进行验证 141 :param s: 待替换的字符串 142 :param gn_path: 字符串所在的gn文件 143 :param stop_tail: 当变量查找到stop_tail目录时停止 144 :return: 将变量替换为其值的字符串 145 """ 146 variable_list = GnCommonTool._find_gn_variable_list(s) 147 if len(variable_list) == 0: 148 return s 149 value_list = GnCommonTool.find_variables_in_gn( 150 tuple(variable_list), path=gn_path, stop_tail=stop_tail) 151 for k, v in dict(zip(variable_list, value_list)).items(): 152 s = s.replace(k, v) 153 return s 154 155 @classmethod 156 def find_values_of_variable(cls, var_name: str, path: str, stop_tail: str = "home") -> list: 157 """ 158 查找变量的值,如果有多个可能值,全部返回 159 :param var_name: 变量名 160 :param path: 变量名所在的文件 161 :param stop_tail: 当变量查找到stop_tail目录时停止 162 :return: 该变量的可能值 163 """ 164 if os.path.isfile(path): 165 path, _ = os.path.split(path) 166 result = list() 167 v = var_name.strip('"').lstrip("${").rstrip('}') 168 while stop_tail in path: 169 cmd = fr"grep -Ern '^( *){v} *= *\".*?\"' --include=*.gn* {path}" 170 output = os.popen(cmd).readlines() 171 path = os.path.split(path)[0] 172 if not output: 173 continue 174 for line in output: 175 line = line.split('=')[-1].strip().strip('"') 176 if len(line) == 0: 177 continue 178 result.append(line) 179 break 180 return result 181 182 183class GnVariableParser: 184 @classmethod 185 def string_parser(cls, var: str, content: str) -> str: 186 """ 187 解析值为字符串的变量,没有对引号进行去除,如果是a = b这种b为变量的,则无法匹配 188 :param content: 要进行解析的内容 189 :param var: 变量名 190 :return: 变量值[str] 191 """ 192 result = BasicTool.re_group_1( 193 content, r"{} *= *[\n]?(\".*?\")".format(var), flags=re.S | re.M) 194 return result 195 196 @classmethod 197 def list_parser(cls, var: str, content: str) -> List[str]: 198 """ 199 解析值为列表的变量,list的元素必须全为数字或字符串,且没有对引号进行去除,如果是a = b这种b为变量的,则无法匹配 200 :param var: 变量名 201 :param content: 要进行 202 :return: 变量值[List] 203 """ 204 result = BasicTool.re_group_1( 205 content, r"{} *= *(\[.*?\])".format(var), flags=re.S | re.M) 206 result = ast.literal_eval(result.strip()) 207 return result 208 209 210if __name__ == '__main__': 211 cc = \ 212 """ 213 target("shared_library", "mmp"){ 214 xxx 215 } 216 217 ohos_shared_library("pinauthservice") { 218 sources = [ 219 "//base/useriam/pin_auth/services/modules/driver/src/pin_auth_driver_hdi.cpp", 220 "//base/useriam/pin_auth/services/modules/driver/src/pin_auth_interface_adapter.cpp", 221 "//base/useriam/pin_auth/services/modules/executors/src/pin_auth_executor_callback_hdi.cpp", 222 "//base/useriam/pin_auth/services/modules/executors/src/pin_auth_executor_hdi.cpp", 223 "//base/useriam/pin_auth/services/modules/inputters/src/i_inputer_data_impl.cpp", 224 "//base/useriam/pin_auth/services/modules/inputters/src/pin_auth_manager.cpp", 225 "//base/useriam/pin_auth/services/sa/src/pin_auth_service.cpp", 226 ] 227 228 configs = [ 229 ":pin_auth_services_config", 230 "//base/useriam/user_auth_framework/common:iam_log_config", 231 "//base/useriam/user_auth_framework/common:iam_utils_config", 232 ] 233 234 deps = [ 235 "//base/useriam/pin_auth/frameworks:pinauth_ipc", 236 "//third_party/openssl:libcrypto_shared", 237 ] 238 239 external_deps = [ 240 "access_token:libaccesstoken_sdk", 241 "c_utils:utils", 242 "drivers_interface_pin_auth:libpin_auth_proxy_1.0", 243 "hisysevent_native:libhisysevent", 244 "hiviewdfx_hilog_native:libhilog", 245 "ipc:ipc_core", 246 "safwk:system_ability_fwk", 247 "user_auth_framework:userauth_executors", 248 ] 249 t = [ 250 1, 251 2, 252 3 253 ] 254 tt = [ 255 aaa, 256 bbb, 257 ccc 258 ] 259 remove_configs = [ "//build/config/compiler:no_exceptions" ] 260 261 subsystem_name = "useriam" 262 part_name = "pin_auth" 263 }""" 264 s = """ 265updater_usb_init_cfg_path = "//base/startup/init/services/etc/init.usb.cfg" 266updater_init_usb_configfs_path_cfg = 267 "//drivers/peripheral/usb/cfg/init.usb.configfs.cfg" 268updater_faultloggerd_cfg = 269"//base/hiviewdfx/faultloggerd/services/config/faultloggerd.cfg" 270updater_hilog_cfg = "//base/hiviewdfx/hilog/services/hilogd/etc/hilogd.cfg" 271 272ohos_prebuilt_etc("updater_hilog.cfg") { 273source = "${updater_hilog_cfg}" 274install_images = [ "updater" ] 275part_name = "updater" 276} 277""" 278 s = "\"${updater_faultloggerd_cfg}\"" 279 print(GnCommonTool.contains_gn_variable(s)) 280 ... 281