• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
23import unittest
24
25__all__ = ["translate_str_unit", "BasicTool", "do_nothing", "get_unit", "unit_adaptive"]
26
27
28def unit_adaptive(size: int) -> str:
29    unit_list = ["Byte", "KB", "MB", "GB"]
30    index = 0
31    while index < len(unit_list) and size >= 1024:
32        size /= 1024
33        index += 1
34    if index == len(unit_list):
35        index = len(unit_list)-1
36        size *= 1024
37    return str(round(size))+unit_list[index]
38
39def get_unit(x: str) -> str:
40    pattern = r"[a-z|A-Z]*$"
41    unit = re.search(pattern, x).group()
42    return unit
43
44
45def translate_str_unit(x: str, dest: str, prefix: str = "~") -> float:
46    src_unit = get_unit(x)
47    trans_dict: Dict[str, int] = {
48        "Byte": 1,
49        "byte": 1,
50        "KB": 1024,
51        "kb": 1024,
52        "MB": 1024*1024,
53        "M": 1024*1024,
54        "GB": 1024*1024*1024,
55        "G": 1024*1024*1024
56    }
57    if src_unit not in trans_dict.keys():
58        raise Exception(
59            f"unsupport unit: {src_unit}. only support {list(trans_dict.keys())}")
60    x = float(x.lstrip(prefix).rstrip(src_unit))
61    return round(x*(trans_dict.get(src_unit)/trans_dict.get(dest)), 2)
62
63
64def do_nothing(x: Any) -> Any:
65    return x
66
67
68class BasicTool:
69    @classmethod
70    def find_files_with_pattern(cls, folder: str, pattern: str = "/**", recursive: bool = True, apply_abs: bool = True,
71                                real_path: bool = True, de_duplicate: bool = True, is_sort: bool = True,
72                                post_handler: Callable[[List[str]], List[str]] = None) -> list:
73        """
74        根据指定paatern匹配folder下的所有文件,默认递归地查找所有文件
75        folder:要查找的目录,会先经过cls.abspath处理(结尾不带/)
76        pattern:要查找的模式,需要以/开头,因为会和folder拼接
77        recursive:是否递归查找
78        apply_abs:是否将路径转换为绝对路径
79        real_path:如果是软链接,是否转换为真正的路径
80        de_duplicate:是否去重
81        is_sort:是否排序
82        post_handler: 对文件进行额外处理的方法,参数为文件名的List,返回值为字符串列表
83        FIXME 有可能会卡住,可能原因为符号链接
84        """
85        file_list = glob.glob(cls.abspath(folder)+pattern, recursive=recursive)
86        if apply_abs:
87            file_list = list(map(lambda x: cls.abspath(x), file_list))
88        if real_path:
89            file_list = list(map(lambda x: os.path.realpath(x), file_list))
90        if de_duplicate:
91            file_list = list(set(file_list))
92        if is_sort:
93            file_list = sorted(file_list, key=str.lower)
94        if post_handler:
95            file_list = post_handler(file_list)
96        if folder in file_list:
97            file_list.remove(folder)
98        return file_list
99
100    @classmethod
101    def match_paragraph(cls, content: str, start_pattern: str = r"\w+\(\".*?\"\) *{", end_pattern: str = "\}") -> \
102            Iterator[re.Match]:
103        """
104        匹配代码段,支持单行
105        注意:ptrn中已经包含前面的空格,所以start_pattern中可以省略
106        :param content: 被匹配的字符串
107        :param start_pattern: 模式的开头
108        :param end_pattern: 模式的结尾
109        :return: 匹配到的段落的迭代器
110        """
111        ptrn = r'^( *){s}(?#匹配开头).*?(?#中间非贪婪)\1(?#如果开头前面有空格,则结尾的前面应该有相同数量的空格)?{e}$(?#匹配结尾)'.format(
112            s=start_pattern, e=end_pattern)
113        ptrn = re.compile(ptrn, re.M | re.S)
114        result = re.finditer(ptrn, content)
115        return result
116
117    @classmethod
118    def re_group_1(cls, content: str, pattern: str, **kwargs) -> str:
119        """
120        匹配正则表达式,如果有匹配到内容,返回group(1)的内容
121        :param content: 要被匹配的内容
122        :param pattern: 进行匹配的模式
123        :return: 匹配到的结果(group(1))
124        TODO 对()的检查应该更严格
125        """
126        if not (r'(' in pattern and r')' in pattern):
127            raise ValueError("parentheses'()' must in the pattern")
128        result = re.search(pattern, content, **kwargs)
129        if result:
130            return result.group(1)
131        return str()
132
133    @classmethod
134    def abspath(cls, path: str) -> str:
135        """
136        将路径转换为绝对路径,如果有~,展开
137        :param path: 要被转换的路径
138        :return: 绝对路径
139        """
140        return os.path.abspath(os.path.expanduser(path))
141
142    @classmethod
143    def grep_ern(cls, pattern: str, path: str, include: str = str(), exclude: tuple = tuple(),
144                 post_handler: Callable[[Text], Any] = do_nothing) -> Any:
145        """
146        执行grep命令来查找内容
147        :param exclude: 不搜索path下的的exclude目录
148        :param include: 指定要搜索的文件
149        :param pattern: 使用pattern进行grep
150        :param path: 搜索路径
151        :param post_handler: 对grep的结果进行后处理
152        :return: post_handler对grep结果进行处理后的结果
153        TODO 将cls.execute用subprocess代替
154        """
155        cmd = f"grep -Ern '{pattern}' '{cls.abspath(path)}'"
156        # E:启用正则表达式  r:递归搜索  n:显示行号
157        if include:
158            cmd += f" --include='{include}'"
159        for e in exclude:
160            cmd += f" --exclude-dir='{e}'"
161        o = cls.execute(cmd)
162        if post_handler:
163            o = post_handler(o)
164        return o
165
166    @classmethod
167    def execute(cls, cmd: str, post_processor: Callable[[Text], Text] = do_nothing) -> Any:
168        """
169        封装popen,返回标准输出的列表
170        :param post_processor: 对执行结果进行处理
171        :param cmd: 待执行的命令
172        :return: 经处理过后的字符串列表
173
174        """
175        output = os.popen(cmd).read()
176        output = post_processor(output)
177        return output
178