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 17 18import itertools 19import os 20import re 21import glob 22from typing import * 23 24 25def do_nothing(x: Any) -> Any: 26 return x 27 28 29class BasicTool: 30 @classmethod 31 def find_files_with_pattern(cls, folder: str, pattern: str = "/**", recursive: bool = True, apply_abs: bool = True, 32 real_path: bool = True, de_duplicate: bool = True, is_sort: bool = True, 33 post_handler: Callable[[List[str]], List[str]] = None) -> list: 34 """ 35 根据指定paatern匹配folder下的所有文件,默认递归地查找所有文件 36 folder:要查找的目录,会先经过cls.abspath处理(结尾不带/) 37 pattern:要查找的模式,需要以/开头,因为会和folder拼接 38 recursive:是否递归查找 39 apply_abs:是否将路径转换为绝对路径 40 real_path:如果是软链接,是否转换为真正的路径 41 de_duplicate:是否去重 42 is_sort:是否排序 43 post_handler: 对文件进行额外处理的方法,参数为文件名的List,返回值为字符串列表 44 FIXME 有可能会卡住,可能原因为符号链接 45 """ 46 file_list = glob.glob(cls.abspath(folder)+pattern, recursive=recursive) 47 if apply_abs: 48 file_list = list(map(lambda x: cls.abspath(x), file_list)) 49 if real_path: 50 file_list = list(map(lambda x: os.path.realpath(x), file_list)) 51 if de_duplicate: 52 file_list = list(set(file_list)) 53 if is_sort: 54 file_list = sorted(file_list, key=str.lower) 55 if post_handler: 56 file_list = post_handler(file_list) 57 if folder in file_list: 58 file_list.remove(folder) 59 return file_list 60 61 @classmethod 62 def match_paragraph(cls, content: str, start_pattern: str = r"\w+\(\".*?\"\) *{", end_pattern: str = "\}") -> \ 63 Iterator[re.Match]: 64 """ 65 匹配代码段,支持单行 66 注意:ptrn中已经包含前面的空格,所以start_pattern中可以省略 67 :param content: 被匹配的字符串 68 :param start_pattern: 模式的开头 69 :param end_pattern: 模式的结尾 70 :return: 匹配到的段落的迭代器 71 """ 72 ptrn = r'^( *){s}(?#匹配开头).*?(?#中间非贪婪)\1(?#如果开头前面有空格,则结尾的前面应该有相同数量的空格)?{e}$(?#匹配结尾)'.format( 73 s=start_pattern, e=end_pattern) 74 ptrn = re.compile(ptrn, re.M | re.S) 75 result = re.finditer(ptrn, content) 76 return result 77 78 @classmethod 79 def re_group_1(cls, content: str, pattern: str, **kwargs) -> str: 80 """ 81 匹配正则表达式,如果有匹配到内容,返回group(1)的内容 82 :param content: 要被匹配的内容 83 :param pattern: 进行匹配的模式 84 :return: 匹配到的结果(group(1)) 85 TODO 对()的检查应该更严格 86 """ 87 if not (r'(' in pattern and r')' in pattern): 88 raise ValueError("parentheses'()' must in the pattern") 89 result = re.search(pattern, content, **kwargs) 90 if result: 91 return result.group(1) 92 return str() 93 94 @classmethod 95 def abspath(cls, path: str) -> str: 96 """ 97 将路径转换为绝对路径,如果有~,展开 98 :param path: 要被转换的路径 99 :return: 绝对路径 100 """ 101 return os.path.abspath(os.path.expanduser(path)) 102 103 @classmethod 104 def grep_ern(cls, pattern: str, path: str, include: str = str(), exclude: tuple = tuple(), 105 post_handler: Callable[[Text], Any] = do_nothing) -> Any: 106 """ 107 执行grep命令来查找内容 108 :param exclude: 不搜索path下的的exclude目录 109 :param include: 指定要搜索的文件 110 :param pattern: 使用pattern进行grep 111 :param path: 搜索路径 112 :param post_handler: 对grep的结果进行后处理 113 :return: post_handler对grep结果进行处理后的结果 114 TODO 将cls.execute用subprocess代替 115 """ 116 cmd = f"grep -Ern '{pattern}' '{cls.abspath(path)}'" 117 # E:启用正则表达式 r:递归搜索 n:显示行号 118 if include: 119 cmd += f" --include='{include}'" 120 for e in exclude: 121 cmd += f" --exclude-dir='{e}'" 122 o = cls.execute(cmd) 123 if post_handler: 124 o = post_handler(o) 125 return o 126 127 @classmethod 128 def execute(cls, cmd: str, post_processor: Callable[[Text], Text] = do_nothing) -> Any: 129 """ 130 封装popen,返回标准输出的列表 131 :param post_processor: 对执行结果进行处理 132 :param cmd: 待执行的命令 133 :return: 经处理过后的字符串列表 134 135 """ 136 output = os.popen(cmd).read() 137 output = post_processor(output) 138 return output 139 140 141if __name__ == '__main__': 142 res = BasicTool.grep_ern("^( *)ohos_prebuilt_shared_library", "/home/aodongbiao/oh", include="BUILD.gn", exclude=("/home/aodongbiao/oh/out","doc", ".ccache"), post_handler=lambda x: x.split('\n')) 143 # print(res) 144 for i in res: 145 if "oh/out" in i: 146 print(i) 147