初次创建仓库提交代码
1. 已经构建好了架子了。 2. 添加了示例的插件
This commit is contained in:
30
database/__init__.py
Normal file
30
database/__init__.py
Normal file
@ -0,0 +1,30 @@
|
||||
from .base import *
|
||||
from .dirs import *
|
||||
from .configs import *
|
||||
from .options import *
|
||||
from .common import *
|
||||
from .customer import *
|
||||
from .black import *
|
||||
|
||||
def load_from_file(config_path:str=None):
|
||||
"""从文件加载customer配置
|
||||
"""
|
||||
if not os.path.exists(config_path):
|
||||
log.warning(f"{config_path} doesn't exists")
|
||||
return
|
||||
with open(config_path, 'r') as f:
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||
from thirdparty import yaml
|
||||
obj = yaml.safe_load(f.read())
|
||||
# 遍历该package下的所有数据,如果是 BaseConfig 类型的实例则进行更新操作
|
||||
for class_name in globals():
|
||||
instance = globals()[class_name]
|
||||
if isinstance(instance, BaseConfig):
|
||||
class_name = instance.__class__.__name__
|
||||
if class_name not in obj:
|
||||
log.debug(f"No Customer Config update ==> {class_name}")
|
||||
continue
|
||||
log.info(f"Update Customer Config Cnt: {len(obj[class_name]):3d} ==> {class_name}")
|
||||
instance = instance.update_from_extra(obj[class_name])
|
||||
globals()[class_name] = instance
|
||||
|
355
database/base.py
Normal file
355
database/base.py
Normal file
@ -0,0 +1,355 @@
|
||||
from typing import Any
|
||||
from core.defines import Dict, List
|
||||
import json
|
||||
import sys, os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||
import core.logger as logger
|
||||
log = logger.get_logger()
|
||||
|
||||
class BaseConfig():
|
||||
"""
|
||||
所有配置类的基类, 所有配置类都继承自该类
|
||||
提供配置的统一使用方式:
|
||||
1. 基类通过 __getattr__ 方法,实现通过点号访问配置
|
||||
2. 基类通过 __setattr__ 方法,实现通过点号设置配置
|
||||
3. 基类通过 __getitem__ 方法,实现通过索引访问配置
|
||||
4. 基类通过 __setitem__ 方法,实现通过索引设置配置
|
||||
5. 基类通过 __delitem__ 方法,实现通过索引删除配置
|
||||
6. 基类通过 __len__ 方法,实现获取配置的长度
|
||||
7. 基类通过 __str__ 方法,实现获取配置的json字符串
|
||||
8. 基类通过 __repr__ 方法,实现获取配置的json字符串
|
||||
9. 子类通过 check 方法,实现检查配置是否合法
|
||||
10. 子类通过 @AutoInstanceDecorator 装饰器,自动将类替换为它的实例
|
||||
"""
|
||||
# 存储原始配置数据,子类复写该属性以表明其配置,其可以是列表或字典
|
||||
_config = None
|
||||
_list = List() # 用于存储配置是一个list的形式
|
||||
_dict = Dict() # 配置的key-value形式,以及list也会扩展为dict存储,方便使用
|
||||
_value = None # 配置仅仅是一个value的情况
|
||||
# 用于存储实例, 单例模式,防止重复实例化 子类无须操作该属性
|
||||
_instance = None
|
||||
|
||||
def __new__(cls):
|
||||
"""
|
||||
如果实例已经存在,则直接返回实例,实现单例模式。
|
||||
"""
|
||||
if cls._instance is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
return cls._instance
|
||||
def _value_raise(self):
|
||||
if self._value is not None:
|
||||
raise AttributeError(f"{self.__class__.__name__} not support this method")
|
||||
def __init__(self) -> None:
|
||||
"""
|
||||
初始化实例的_list和_dict,
|
||||
并将其绑定到类属性上,
|
||||
"""
|
||||
# log.info(f"Load config: {self.__class__.__name__}")
|
||||
# 获取子类的 _config 属性
|
||||
_config = getattr(self.__class__, '_config', None)
|
||||
if _config is None:
|
||||
raise ValueError(f"_config must be defined in {self.__class__.__name__}")
|
||||
self._list = List()
|
||||
self._dict = Dict()
|
||||
if isinstance(_config, list):
|
||||
self._list = List(_config)
|
||||
for key in self._list:
|
||||
# 将列表项同时添加到属性中 以便于通过Dot方式访问
|
||||
self._dict[key] = key
|
||||
elif isinstance(_config, dict):
|
||||
self._dict = Dict(_config)
|
||||
# 配置是单个值的情况
|
||||
elif isinstance(_config, (int, float, str, bool)):
|
||||
self._value = _config
|
||||
self._dict = Dict({str(_config) : _config})
|
||||
self._list = List([_config])
|
||||
else:
|
||||
raise ValueError(f"{self.__class__.__name__} _config must be a list or dict")
|
||||
log.debug(f"Load config cnt: {len(self._dict):3} => {self.__class__.__name__}")
|
||||
|
||||
def __getattr__(self, key):
|
||||
"""
|
||||
当通过类属性方式访问不存在的属性时,尝试从 _dict 中获取
|
||||
"""
|
||||
return self[key]
|
||||
|
||||
def __setattr__(self, key, value):
|
||||
"""
|
||||
当通过类属性方式设置值时,同时更新 _dict
|
||||
"""
|
||||
# log.info(f"setattr: {self.__class__.__name__}, key: {key}, value: {value}")
|
||||
# 如果是非字符串,或者是非_开头的字符串,则将其添加到_dict中
|
||||
if not isinstance(key, str) or not key.startswith('_'):
|
||||
self[key] = value
|
||||
# 如果key是字符串且是合法的标识符,则将其添加到类属性中
|
||||
elif isinstance(key, str):
|
||||
super().__setattr__(key, value)
|
||||
else:
|
||||
raise AttributeError(f"Attribute {key} is not a valid identifier")
|
||||
def __delattr__(self, key:str):
|
||||
"""
|
||||
当通过类属性方式删除值时,同时删除 _dict 中的值
|
||||
"""
|
||||
del self[key]
|
||||
|
||||
def items(self):
|
||||
return self._dict.items()
|
||||
|
||||
def get(self, key=None, default=None):
|
||||
"""
|
||||
获取配置值
|
||||
"""
|
||||
if key is None:
|
||||
if self._value is not None:
|
||||
return self._value
|
||||
else:
|
||||
raise KeyError(f"{self.__class__.__name__} must set key to get")
|
||||
return self[key] if key in self else default
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""
|
||||
当通过索引方式访问值:
|
||||
1. 如果key是整数,按列表方式访问
|
||||
2. 如果key是字符串,按字典方式访问
|
||||
3. 如果key既不是整数也不是字符串,抛出TypeError
|
||||
例如:
|
||||
config = MyConfig()
|
||||
print(config[0])
|
||||
print(config["key"])
|
||||
"""
|
||||
if isinstance(key, int):
|
||||
return self._list[key]
|
||||
elif isinstance(key, str):
|
||||
# 如果key中包含/,说明可能是个路径。返回key本身
|
||||
# 因为有些配置直接将路径作为配置项
|
||||
if '/' in key:
|
||||
return key
|
||||
else:
|
||||
# 如果 key 是字符串,按字典方式访问
|
||||
return self._dict[key]
|
||||
else:
|
||||
raise TypeError("Key must be either an integer or a string")
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
"""
|
||||
当通过索引方式设置值:
|
||||
1. 如果key是整数,按列表方式设置
|
||||
2. 如果key是字符串,按字典方式设置
|
||||
3. 如果key既不是整数也不是字符串,抛出TypeError
|
||||
例如:
|
||||
config = MyConfig()
|
||||
config[0] = "value"
|
||||
config["key"] = "value"
|
||||
"""
|
||||
# log.info(f"setitem: {self.__class__.__name__}, key: {key}, value: {value}")
|
||||
if isinstance(key, int):
|
||||
old_value = self._list[key]
|
||||
self._list[key] = value
|
||||
self._dict.pop(old_value)
|
||||
key = value
|
||||
elif isinstance(key, str):
|
||||
if self._list:
|
||||
# 我们会将新的key和value同时添加到_list和_dict中 确保key和value是相同的
|
||||
if key in self._list:
|
||||
self._list[self._list.index(key)] = value
|
||||
self._dict.pop(key)
|
||||
key = value
|
||||
else:
|
||||
self._list.append(key)
|
||||
else:
|
||||
raise TypeError("Key must be either an integer or a string")
|
||||
self._dict[key] = value
|
||||
# log.info(f"setitem ok: {self.__class__.__name__}, key: {key}, value: {self._dict[key]}")
|
||||
|
||||
def __delitem__(self, key):
|
||||
"""
|
||||
当通过索引方式删除值:
|
||||
1. 如果key是整数,按列表方式删除
|
||||
2. 如果key是字符串,按字典方式删除
|
||||
3. 如果key既不是整数也不是字符串,抛出TypeError
|
||||
例如:
|
||||
config = MyConfig()
|
||||
del config[0]
|
||||
del config["key"]
|
||||
"""
|
||||
if isinstance(key, int):
|
||||
self.__delattr__(self._list[key])
|
||||
elif isinstance(key, str):
|
||||
# 如果 key 是字符串,按字典方式删除
|
||||
if key not in self._dict:
|
||||
raise KeyError(f"Key {key} not found in the dictionary")
|
||||
self._dict.pop(key)
|
||||
if key in self._list:
|
||||
self._list.pop(self._list.index(key))
|
||||
else:
|
||||
raise TypeError("Key must be either an integer or a string")
|
||||
|
||||
def __contains__(self, key):
|
||||
"""
|
||||
检查配置是否包含某个key
|
||||
"""
|
||||
return key in self._dict
|
||||
def __iter__(self):
|
||||
"""
|
||||
返回配置的迭代器
|
||||
"""
|
||||
if self._value is not None:
|
||||
yield self._value
|
||||
elif self._list:
|
||||
yield from self._list
|
||||
elif self._dict:
|
||||
yield from self._dict
|
||||
else:
|
||||
raise StopIteration
|
||||
def __len__(self):
|
||||
"""
|
||||
返回配置的长度
|
||||
"""
|
||||
if self._value is not None:
|
||||
return 1
|
||||
elif self._list:
|
||||
return len(self._list)
|
||||
elif self._dict:
|
||||
return len(self._dict)
|
||||
else:
|
||||
return 0
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
返回对象的字符串表示,使用json 风格来呈现
|
||||
"""
|
||||
# log.info(f"str: {self.__class__.__name__}, len: {len(self._list)}")
|
||||
if self._value is not None:
|
||||
return f"{self._value}"
|
||||
elif self._list:
|
||||
return json.dumps(self._list, indent=4)
|
||||
elif self._dict:
|
||||
return json.dumps(self._dict, indent=4)
|
||||
else:
|
||||
return ""
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
返回对象的字符串表示,使用json 风格来呈现
|
||||
"""
|
||||
return self.__str__()
|
||||
|
||||
def __eq__(self, other):
|
||||
"""
|
||||
实现对象的相等比较
|
||||
1. 如果other是字符串,且self._value不为None,则与_value进行比较
|
||||
2. 如果other是BaseConfig实例:
|
||||
- 如果两者都有_value,则比较_value
|
||||
- 如果两者都有_list,则比较_list
|
||||
- 如果两者都有_dict,则比较_dict
|
||||
3. 如果other是列表,且self._list不为空,则与_list进行比较
|
||||
4. 如果other是字典,且self._dict不为空,则与_dict进行比较
|
||||
5. 否则,使用默认的比较行为
|
||||
"""
|
||||
# 处理字符串比较
|
||||
if isinstance(other, (int, float, str, bool)) and self._value is not None:
|
||||
return self._value == other
|
||||
# 处理BaseConfig实例比较
|
||||
elif isinstance(other, BaseConfig):
|
||||
if self._value is not None and other._value is not None:
|
||||
return self._value == other._value
|
||||
elif self._list and other._list:
|
||||
return self._list == other._list
|
||||
elif self._dict and other._dict:
|
||||
return self._dict == other._dict
|
||||
else:
|
||||
return False
|
||||
elif isinstance(other, list) and self._list:
|
||||
return self._list == other
|
||||
elif isinstance(other, dict) and self._dict:
|
||||
return self._dict == other
|
||||
else:
|
||||
return super().__eq__(other)
|
||||
|
||||
def check(self) -> bool:
|
||||
"""检查配置是否合法
|
||||
Returns:
|
||||
bool: 如果配置合法,返回True,否则返回False
|
||||
子类可以复写该方法,以检查配置是否合法
|
||||
"""
|
||||
return True
|
||||
|
||||
def update(self, _config):
|
||||
"""更新配置
|
||||
Args:
|
||||
_config (dict): 需要更新的配置
|
||||
|
||||
Raises:
|
||||
ValueError: 如果_config不是字典或列表
|
||||
"""
|
||||
if isinstance(_config, dict):
|
||||
for key, value in _config.items():
|
||||
self[key] = value
|
||||
elif isinstance(_config, list):
|
||||
for item in _config:
|
||||
self[item] = item
|
||||
elif isinstance(_config, (int, float, str, bool)):
|
||||
self._value = _config
|
||||
self._dict = Dict({str(_config) : _config})
|
||||
self._list = List([_config])
|
||||
else:
|
||||
raise ValueError(f"_config type {type(_config)} is not support!")
|
||||
|
||||
def _clean(self):
|
||||
"""清除所有配置
|
||||
"""
|
||||
[self.__delitem__(_) for _ in self._dict.copy()]
|
||||
|
||||
def update_from_extra(self, new_data:Any):
|
||||
""" 从json中更新数据,默认行为是加载,子类可以重载该函数使得其可以具备不同的行为
|
||||
|
||||
Args:
|
||||
new_data (Any): 带有直接属于该配置的数据
|
||||
"""
|
||||
self.load(new_data)
|
||||
|
||||
def load(self, new_data:Any):
|
||||
""" 加载数据:会先清除当前配置,然后更新配置
|
||||
|
||||
Args:
|
||||
new_data (Any): 带有直接属于该配置的数据
|
||||
例如:
|
||||
```python
|
||||
MyConfig.load({"key1": "value1", "key2": "value2"})
|
||||
MyConfig1.load([1, 2, 3])
|
||||
MyConfig2.load(123)
|
||||
MyConfig3.load("123")
|
||||
MyConfig4.load(True)
|
||||
```
|
||||
"""
|
||||
|
||||
if not isinstance(new_data, (dict, list, int, float, str, bool)):
|
||||
raise ValueError(f"Datatype {type(new_data)} is not support!")
|
||||
self._clean()
|
||||
self.update(new_data)
|
||||
|
||||
def remove(self, new_data: Any):
|
||||
"""删除数据
|
||||
"""
|
||||
if isinstance(new_data, (list, dict)):
|
||||
for item in new_data:
|
||||
del self[item]
|
||||
elif isinstance(new_data, (int, float, str, bool)):
|
||||
del self[new_data]
|
||||
else:
|
||||
raise ValueError(f"Datatype {type(new_data)} is not support!")
|
||||
|
||||
def AutoInstanceDecorator(cls):
|
||||
"""自动实例化装饰器:自动将类替换为它的实例,实现类名访问即实例访问,
|
||||
例如:
|
||||
```python
|
||||
print(MyConfig.key)
|
||||
```
|
||||
等价于
|
||||
```python
|
||||
config = MyConfig()
|
||||
print(config["key"])
|
||||
```
|
||||
"""
|
||||
instance = cls() # 创建实例
|
||||
return instance # 返回实例,替换原始类
|
120
database/black.py
Normal file
120
database/black.py
Normal file
@ -0,0 +1,120 @@
|
||||
from functools import wraps
|
||||
import sys, os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||
import core.logger as logger
|
||||
log = logger.get_logger()
|
||||
from database.base import BaseConfig, AutoInstanceDecorator
|
||||
from database.dirs import CheckDirAliasDecorator
|
||||
from database.common import *
|
||||
|
||||
|
||||
def BlackListUpdateRemoveDecorator(cls:BaseConfig):
|
||||
"""黑名单更新装饰器:对于黑名单来说更新配置就是将默认的黑名单里面的项目删除
|
||||
Args:
|
||||
cls: 被装饰的类
|
||||
Returns:
|
||||
cls: 装饰后的类
|
||||
"""
|
||||
cls.update_from_extra = cls.remove
|
||||
return cls
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@BlackListUpdateRemoveDecorator
|
||||
class ProjectBlackList(BaseConfig):
|
||||
_config = [
|
||||
"project/tools/codesize",
|
||||
"project/image/codesize",
|
||||
]
|
||||
def check(self) -> bool:
|
||||
for item in self._list:
|
||||
if not check_file_exists(item):
|
||||
log.warning(f"path {item} not exists")
|
||||
return True
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@CheckDirAliasDecorator
|
||||
@BlackListUpdateRemoveDecorator
|
||||
class BlackListDefault(BaseConfig):
|
||||
"""BLACK_LIST_DEFAULT
|
||||
"""
|
||||
_config = [
|
||||
"mi_ai",
|
||||
"mi_ao",
|
||||
"mi_aio",
|
||||
"mi_alsa",
|
||||
"mi_cipher",
|
||||
"mi_common",
|
||||
"mi_cus3a",
|
||||
"mi_debug",
|
||||
"mi_dummy",
|
||||
"mi_disp",
|
||||
"mi_dpu",
|
||||
"mi_dsp",
|
||||
"mi_fb",
|
||||
"mi_gfx",
|
||||
"mi_hdmi",
|
||||
"mi_hdmirx",
|
||||
"mi_hvp",
|
||||
"mi_ipu",
|
||||
"mi_iqserver",
|
||||
"mi_ive",
|
||||
"mi_jpd",
|
||||
"mi_mipitx",
|
||||
"mi_nir",
|
||||
"mi_panel",
|
||||
"mi_pcie",
|
||||
"mi_pspi",
|
||||
"mi_rgn",
|
||||
"mi_scl",
|
||||
"mi_sed",
|
||||
"mi_sensor",
|
||||
"mi_shadow",
|
||||
"sdk/impl/sys/",
|
||||
"mi_vdec",
|
||||
"mi_vdf",
|
||||
"sdk/interface/src/vcodec/",
|
||||
"mi_vdisp",
|
||||
"mi_wlan",
|
||||
"dualos",
|
||||
"otp",
|
||||
"usb_gadget_udc_usb30",
|
||||
"freertos",
|
||||
"context_switch",
|
||||
"lh_monitor",
|
||||
"pm_mhal_pm_default",
|
||||
"pm_mhal_pm_aio",
|
||||
"pm_mhal_pm_idle",
|
||||
"pm_mhal_pm_jpe",
|
||||
"pm_mhal_pm_md",
|
||||
"pm_mhal_pm_radar",
|
||||
"pm_mhal_pm_usbpoc",
|
||||
"pm_mhal_pm_vif",
|
||||
"pm_mhal_pm_usb_gadget_udc_usb30",
|
||||
]
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@BlackListUpdateRemoveDecorator
|
||||
@CheckDirAliasDecorator
|
||||
class BlackListInternal(BaseConfig):
|
||||
"""BLACK_LIST_INTERNAL
|
||||
"""
|
||||
_config = [
|
||||
"mi_isp",
|
||||
"mi_ispalgo",
|
||||
"mi_ldc",
|
||||
"mi_venc",
|
||||
"mi_vif",
|
||||
"pm_mhal_pm_isp",
|
||||
"pm_mhal_pm_ispalgo",
|
||||
"pm_mhal_pm_radar_algo",
|
||||
]
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@BlackListUpdateRemoveDecorator
|
||||
class DemoBlackList(BaseConfig):
|
||||
"""verify 目录下面的黑名单,不允许被 release 出去
|
||||
"""
|
||||
_config = [
|
||||
"sdk/verify/mi_demo/source/ipu",
|
||||
"sdk/verify/vectorcast",
|
||||
]
|
54
database/common.py
Normal file
54
database/common.py
Normal file
@ -0,0 +1,54 @@
|
||||
import sys, os
|
||||
from typing import Any
|
||||
from pathlib import Path
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||
from core.logger import get_logger
|
||||
log = get_logger()
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__)))
|
||||
from .base import BaseConfig
|
||||
from .options import ReleaseOptions
|
||||
import dirs
|
||||
|
||||
def config_expand(instance: Any):
|
||||
"""配置展开:
|
||||
1. 将DirAlias中的alias展开,为实际路径
|
||||
2. 将BaseConfig中的配置展开 将字符串中的{key}替换为Args._dict[key]
|
||||
3. 如果为多层嵌套,则递归展开
|
||||
Returns:
|
||||
List: 展开后的列表
|
||||
"""
|
||||
_ret = []
|
||||
if isinstance(instance, str):
|
||||
# 将字符串中的{key}替换为ReleaseOptions._dict[key] 实现动态路径
|
||||
instance = dirs.str_format(instance)
|
||||
# 尝试从DirAlias中获取instance的值
|
||||
value = dirs.DirAlias.get(instance, instance)
|
||||
if value == instance:
|
||||
# 如果value和instance相同,说明其已经不可以再拓展了 已经是最终路径了
|
||||
_ret.append(instance)
|
||||
else:
|
||||
# 如果value和instance不同,说明其还可以继续拓展
|
||||
_ret.extend(config_expand(value))
|
||||
elif isinstance(instance, list):
|
||||
for item in instance:
|
||||
_ret.extend(config_expand(item))
|
||||
elif isinstance(instance, dict):
|
||||
for _, value in instance.items():
|
||||
_ret.extend(config_expand(value))
|
||||
elif isinstance(instance, BaseConfig):
|
||||
if instance._list:
|
||||
_ret.extend(config_expand(instance._list))
|
||||
elif instance._dict:
|
||||
_ret.extend(config_expand(instance._dict))
|
||||
else:
|
||||
raise ValueError(f"Invalid config type: {type(instance)}")
|
||||
#log.info(f"config_expand: {instance.__class__.__name__} {_ret}")
|
||||
return sorted(set(_ret))
|
||||
|
||||
def check_file_exists(item: str) -> bool:
|
||||
"""检查文件是否存在
|
||||
"""
|
||||
file = Path(ReleaseOptions.AlkaidRootPath) / item
|
||||
if not file.exists():
|
||||
return False
|
||||
return True
|
306
database/configs.py
Normal file
306
database/configs.py
Normal file
@ -0,0 +1,306 @@
|
||||
from functools import wraps
|
||||
import sys, os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||
import core.logger as logger
|
||||
log = logger.get_logger()
|
||||
from database.base import BaseConfig, AutoInstanceDecorator
|
||||
from database.dirs import CheckDirAliasDecorator
|
||||
from database.common import *
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class GIT_REMOTE_REPO(BaseConfig):
|
||||
_config = "origin"
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class TAG_IGNORE_PROJECT(BaseConfig):
|
||||
_config = "build"
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class TAR_EXFILES(BaseConfig):
|
||||
_config = "--exclude=.git --exclude=.svn --exclude=.gitignore --exclude=.vimproj"
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class RELEASE_SNAPSHOT(BaseConfig):
|
||||
_config = ".repo/manifests/release_snapshot/"
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class REPO_URL(BaseConfig):
|
||||
_config = "http://hcgit04:9080/manifest/alkaid"
|
||||
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class ProductIngoreList(BaseConfig):
|
||||
_config = [
|
||||
"include",
|
||||
"sigma_common_libs",
|
||||
]
|
||||
def check(self) -> bool:
|
||||
# 检查当前 配置是否合法
|
||||
return True
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class ChipIngoreList(BaseConfig):
|
||||
_config = [
|
||||
"ifado",
|
||||
"iford",
|
||||
"maruko",
|
||||
"opera",
|
||||
"pcupid",
|
||||
"souffle",
|
||||
"mercury6p",
|
||||
"infinity6c",
|
||||
"infinity6e",
|
||||
"infinity6f",
|
||||
"infinity7",
|
||||
"pioneer5",
|
||||
"ibopper",
|
||||
#---chip support OpenRtosCm4SourceEx after ifackel
|
||||
"ifackel",
|
||||
]
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class ChipCheckConfigConsistencyList(BaseConfig):
|
||||
_config = [
|
||||
"iford",
|
||||
"ifado",
|
||||
"ibopper",
|
||||
"pcupid",
|
||||
"ifackel",
|
||||
]
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class ReleaseDirDefaultList(BaseConfig):
|
||||
_config = [
|
||||
"boot",
|
||||
"kernel",
|
||||
"optee",
|
||||
"pm_rtos",
|
||||
"project",
|
||||
"riscv",
|
||||
"rtos",
|
||||
"sdk",
|
||||
]
|
||||
def check(self) -> bool:
|
||||
for item in self._list:
|
||||
if not check_file_exists(item):
|
||||
log.warning(f"path {item} not exists")
|
||||
return True
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class ExReleaseList(BaseConfig):
|
||||
_config = [
|
||||
"sdk/driver",
|
||||
]
|
||||
def check(self) -> bool:
|
||||
for item in self._list:
|
||||
if not check_file_exists(item):
|
||||
raise ValueError(f"path {item} not exiest")
|
||||
return True
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class AppDemoDefaultList(BaseConfig):
|
||||
"""DEMO_LIST default files
|
||||
"""
|
||||
_config = [
|
||||
"sdk/makefile",
|
||||
"sdk/sdk.mk",
|
||||
"sdk/verify/makefile",
|
||||
]
|
||||
def check(self) -> bool:
|
||||
for item in self._list:
|
||||
if not check_file_exists(item):
|
||||
raise ValueError(f"path {item} not exists")
|
||||
return True
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@CheckDirAliasDecorator
|
||||
class RtosDefaultList(BaseConfig):
|
||||
"""RTOS default drivers
|
||||
"""
|
||||
_config = [
|
||||
"bench",
|
||||
"bootloader",
|
||||
"dualos_camera",
|
||||
"cust_isp",
|
||||
"cust_usb_gadget",
|
||||
"earlyinit_setting",
|
||||
"earlyinit_main",
|
||||
"earlyinit_vsrc",
|
||||
"sysdesc",
|
||||
"sensordriver",
|
||||
]
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@CheckDirAliasDecorator
|
||||
class RtosWhiteList(BaseConfig):
|
||||
"""RTOS white drivers
|
||||
"""
|
||||
_config = [
|
||||
"application_selector",
|
||||
"aov_preload",
|
||||
"cm4_preload",
|
||||
"coremark",
|
||||
"common",
|
||||
"audio_app",
|
||||
"disp_app",
|
||||
"dualos_camera",
|
||||
"font",
|
||||
"iqserver",
|
||||
"lvgl",
|
||||
"sample_code",
|
||||
"preload_rtos",
|
||||
"preload_sample",
|
||||
"usb_gadget_app",
|
||||
"usb_gadget_app_uvc",
|
||||
"sensordriver",
|
||||
"aesdma",
|
||||
"bdma",
|
||||
"camclk",
|
||||
"cpufreq",
|
||||
"drvutil",
|
||||
"emac",
|
||||
"fcie",
|
||||
"flash",
|
||||
"fsp_qspi",
|
||||
"gpio",
|
||||
"i2c",
|
||||
"input",
|
||||
"int",
|
||||
"ir",
|
||||
"kernel",
|
||||
"loadns",
|
||||
"mbx",
|
||||
"miu",
|
||||
"mmupte",
|
||||
"mspi",
|
||||
"msys",
|
||||
"padmux",
|
||||
"pwm",
|
||||
"riu",
|
||||
"rtc",
|
||||
"rtcpwc",
|
||||
"saradc",
|
||||
"sdmmc",
|
||||
"str",
|
||||
"timer",
|
||||
"tsensor",
|
||||
"uart",
|
||||
"voltage",
|
||||
"watchdog",
|
||||
"algo",
|
||||
"decompress",
|
||||
"freertos_plus_fat",
|
||||
"lwfs",
|
||||
"proxyfs",
|
||||
"tcpip",
|
||||
"arm",
|
||||
"riscv",
|
||||
"libc",
|
||||
"newlib_stub",
|
||||
"cam_dev_wrapper",
|
||||
"cam_drv_poll",
|
||||
"cam_fs_wrapper",
|
||||
"cam_os_wrapper",
|
||||
"cam_proc_wrapper",
|
||||
"env_util",
|
||||
"initcall",
|
||||
"loadable_module",
|
||||
"memmang",
|
||||
"memmap",
|
||||
"mempool",
|
||||
"MsWrapper",
|
||||
"newlib_stub",
|
||||
"freertos_main",
|
||||
"freertos_posix",
|
||||
"sys_I_SW",
|
||||
]
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@CheckDirAliasDecorator
|
||||
class PmRtosDefaultList(BaseConfig):
|
||||
"""PM_RTOS default drivers
|
||||
"""
|
||||
_config = [
|
||||
"pm_slnn_raw_hpd",
|
||||
"pm_cm4_pipeline",
|
||||
"pm_sysdesc",
|
||||
]
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@CheckDirAliasDecorator
|
||||
class PmRtosWhiteList(BaseConfig):
|
||||
"""PM_RTOS white drivers
|
||||
"""
|
||||
_config = [
|
||||
"pm_aesdma",
|
||||
"pm_bdma",
|
||||
"pm_camclk",
|
||||
"pm_cpufreq",
|
||||
"pm_drvutil",
|
||||
"pm_loadns",
|
||||
"pm_emac",
|
||||
"pm_flash",
|
||||
"pm_fsp_qspi",
|
||||
"pm_gpio",
|
||||
"pm_i2c",
|
||||
"pm_int",
|
||||
"pm_ir",
|
||||
"pm_kernel",
|
||||
"pm_miu",
|
||||
"pm_mmupte",
|
||||
"pm_mspi",
|
||||
"pm_msys",
|
||||
"pm_padmux",
|
||||
"pm_pcie",
|
||||
"pm_pl011",
|
||||
"pm_mhal_pm_clk",
|
||||
"pm_pm_idle",
|
||||
"pm_mhal_pm_mbx",
|
||||
"pm_mhal_imi_heap",
|
||||
"pm_mhal_pm_pir",
|
||||
"pm_rtcpwc",
|
||||
"pm_mhal_pm_sys",
|
||||
"pm_mhal_pm_wdt",
|
||||
"pm_pspi",
|
||||
"pm_pwm",
|
||||
"pm_pm_power",
|
||||
"pm_rtc",
|
||||
"pm_rtcpwc",
|
||||
"pm_saradc",
|
||||
"pm_sdmmc",
|
||||
"pm_timer",
|
||||
"pm_tsensor",
|
||||
"pm_uart",
|
||||
"pm_voltage",
|
||||
"pm_watchdog",
|
||||
"pm_decompress",
|
||||
"pm_freertos_plus_fat",
|
||||
"pm_lwfs",
|
||||
"pm_proxyfs",
|
||||
"pm_tcpip",
|
||||
"pm_arm",
|
||||
"pm_riscv",
|
||||
"pm_cam_dev_wrapper",
|
||||
"pm_cam_drv_poll",
|
||||
"pm_cam_fs_wrapper",
|
||||
"pm_cam_os_wrapper",
|
||||
"pm_cam_proc_wrapper",
|
||||
"pm_env_util",
|
||||
"pm_initcall",
|
||||
"pm_libc",
|
||||
"pm_memmang",
|
||||
"pm_memmap",
|
||||
"pm_mempool",
|
||||
"pm_MsWrapper",
|
||||
"pm_freertos",
|
||||
"pm_freertos_posix",
|
||||
"pm_sys_I_SW",
|
||||
]
|
||||
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class DemoListDefault(BaseConfig):
|
||||
"""DEMO_LIST_DEFAULT
|
||||
"""
|
||||
_config = [
|
||||
]
|
45
database/customer.py
Normal file
45
database/customer.py
Normal file
@ -0,0 +1,45 @@
|
||||
import json
|
||||
import sys, os
|
||||
from functools import wraps
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||
import core.logger as logger
|
||||
log = logger.get_logger()
|
||||
sys.path.append(os.path.dirname(__file__))
|
||||
from .base import BaseConfig, AutoInstanceDecorator
|
||||
from .dirs import CheckDirAliasDecorator
|
||||
from .common import *
|
||||
|
||||
# 定义配置类
|
||||
@AutoInstanceDecorator
|
||||
class ConfigList(BaseConfig):
|
||||
"""支持的配置列表
|
||||
"""
|
||||
_config = []
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@CheckDirAliasDecorator
|
||||
class MiReleaseList(BaseConfig):
|
||||
"""MI release 列表
|
||||
"""
|
||||
_config = []
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@CheckDirAliasDecorator
|
||||
class MhalReleaseList(BaseConfig):
|
||||
"""MHAL release 列表
|
||||
"""
|
||||
_config = []
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@CheckDirAliasDecorator
|
||||
class RtosReleaseList(BaseConfig):
|
||||
"""RTOS release 列表
|
||||
"""
|
||||
_config = []
|
||||
|
||||
@AutoInstanceDecorator
|
||||
@CheckDirAliasDecorator
|
||||
class PmRtosReleaseList(BaseConfig):
|
||||
"""PM RTOS release 列表
|
||||
"""
|
||||
_config = []
|
1021
database/dirs.py
Normal file
1021
database/dirs.py
Normal file
File diff suppressed because it is too large
Load Diff
241
database/options.py
Normal file
241
database/options.py
Normal file
@ -0,0 +1,241 @@
|
||||
import argparse
|
||||
import sys, os
|
||||
from typing import List
|
||||
import textwrap
|
||||
import argparse
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||
import core.logger as logger
|
||||
from utils.utils import get_alkaid_root
|
||||
log = logger.get_logger()
|
||||
from database.base import BaseConfig, AutoInstanceDecorator
|
||||
|
||||
class ConfigureStyleHelpFormatter(argparse.HelpFormatter):
|
||||
"""自定义的帮助信息格式化类,用于美化 argparse 的帮助输出
|
||||
|
||||
特点:
|
||||
1. 带有彩色标记的输出样式
|
||||
2. 优化了选项和描述的对齐
|
||||
"""
|
||||
|
||||
# 颜色代码定义
|
||||
BLUE = "\033[1;34m" # 蓝色,用于位置参数
|
||||
GREEN = "\033[1;32m" # 绿色,用于普通选项
|
||||
YELLOW = "\033[1;33m" # 黄色,用于必选参数
|
||||
RESET = "\033[0m" # 重置颜色
|
||||
|
||||
def __init__(self, prog, indent_increment=2, max_help_position=8, width=None):
|
||||
# 根据终端宽度自动调整
|
||||
try:
|
||||
width = width or min(120, os.get_terminal_size().columns)
|
||||
except OSError:
|
||||
width = width or 120 # 使用默认宽度
|
||||
super().__init__(prog, indent_increment, max_help_position, width)
|
||||
|
||||
def _format_action_invocation(self, action):
|
||||
"""格式化参数选项的显示方式,添加彩色显示"""
|
||||
if not action.option_strings:
|
||||
# 位置参数,显示为蓝色
|
||||
metavar, = self._metavar_formatter(action, action.dest)(1)
|
||||
return f"{self.BLUE}{metavar}{self.RESET}"
|
||||
|
||||
# 处理可选参数
|
||||
parts = []
|
||||
|
||||
# 判断是否为必选参数,是则使用黄色,否则使用绿色
|
||||
color = self.YELLOW if action.required else self.GREEN
|
||||
|
||||
# 如果同时有短选项和长选项
|
||||
if len(action.option_strings) > 1:
|
||||
short, long = action.option_strings
|
||||
parts.append(f"{color}{short}{self.RESET}, {color}{long}{self.RESET}")
|
||||
else:
|
||||
# 只有一个选项
|
||||
parts.append(f"{color}{action.option_strings[0]}{self.RESET}")
|
||||
|
||||
# 添加 metavar(如果有)
|
||||
if action.metavar is not None:
|
||||
parts.append(f" {action.metavar}")
|
||||
elif action.nargs != 0:
|
||||
parts.append(f" {action.dest.upper()}")
|
||||
|
||||
return ''.join(parts)
|
||||
|
||||
def add_usage(self, usage, actions, groups, prefix=None):
|
||||
"""重写帮助信息的用法部分,优化了显示格式"""
|
||||
if prefix is None:
|
||||
prefix = 'usage: '
|
||||
return super().add_usage(usage, actions, groups, prefix)
|
||||
|
||||
def _format_action(self, action):
|
||||
"""重写格式化动作方法,确保帮助文本正确对齐和显示"""
|
||||
# 获取基础格式化的帮助文本
|
||||
result = super()._format_action(action)
|
||||
|
||||
# 如果有choices且不是帮助动作,则添加选项信息
|
||||
if hasattr(action, 'choices') and action.choices and action.option_strings:
|
||||
# 查找最后一个换行符后的位置
|
||||
last_line_start = result.rfind('\n') + 1
|
||||
# indentation = ' ' * (last_line_start - result.rfind('\n', 0, last_line_start - 1) - 1)
|
||||
indentation = ' ' * 8
|
||||
|
||||
# 格式化choices选项
|
||||
choices_str = f"{indentation} 可选值: {', '.join([str(c) for c in action.choices])}"
|
||||
result = f"{result}\n{choices_str} \n"
|
||||
|
||||
return result
|
||||
|
||||
def _split_lines(self, text, width):
|
||||
"""优化帮助文本的换行处理"""
|
||||
if not text:
|
||||
return []
|
||||
if '\n' in text:
|
||||
# 开头的文本按原样分行显示
|
||||
ret = []
|
||||
for _ in text.splitlines():
|
||||
_ = _.strip()
|
||||
ret.append(_[1:] if _[0] == '|' else _)
|
||||
return ret
|
||||
# 正常文本使用 textwrap 换行
|
||||
return textwrap.wrap(text, width)
|
||||
|
||||
def _fill_text(self, text, width, indent):
|
||||
"""优化帮助文本的填充显示"""
|
||||
if not text:
|
||||
return ""
|
||||
# 使用textwrap对文本进行缩进和填充
|
||||
text = self._whitespace_matcher.sub(' ', text).strip()
|
||||
paragraphs = text.split('.\n ')
|
||||
multi_paragraphs = '\n'.join([textwrap.fill(p, width) for p in paragraphs])
|
||||
return textwrap.indent(multi_paragraphs, indent)
|
||||
|
||||
|
||||
@AutoInstanceDecorator
|
||||
class ReleaseOptions(BaseConfig):
|
||||
"""Release 选项
|
||||
|
||||
Args:
|
||||
SkipCheckout (bool, optional): 是否跳过checkout kernel/mboot 的操作. Defaults to False.
|
||||
OpenSource (bool, optional):
|
||||
#是否开启SDK开源模式:
|
||||
#闭源模式: MI编译为lib和ko对外提供功能
|
||||
#开源模式:MI源码发布, 客户可直接获得MI原始代码
|
||||
# 开源的list:
|
||||
# sdk/interface/src/vpe/
|
||||
# sdk/interface/src/venc/
|
||||
# sdk/impl/vpe
|
||||
# sdk/impl/venc/. Defaults to False.
|
||||
Cm4Support (bool, optional): 支持release CM4. Defaults to False.
|
||||
RiscVSupport (bool, optional): 支持release RiscV. Defaults to False.
|
||||
MounRiverSDK (int, optional): 选择MounRiver SDK版本. Defaults to 0.
|
||||
ThreadNum (int, optional): 编译线程数. Defaults to 1.
|
||||
Doc2Pdf (bool, optional): 编译文档为pdf格式. Defaults to False.
|
||||
VerifyBuild (bool, optional): 验证编译结果. Defaults to False.
|
||||
Doc2Html (bool, optional): 编译文档为html格式. Defaults to False.
|
||||
ReduceCodeSize (bool, optional): 减小编译代码大小. Defaults to False.
|
||||
SkipSyncCode (bool, optional): 跳过代码同步. Defaults to False.
|
||||
Ipl_version (str, optional): 选择IPL版本. Defaults to "CN".
|
||||
"""
|
||||
_config = {
|
||||
# 必需参数
|
||||
"SWBoardAlias": "", # -a: 板子别名
|
||||
"TagId": "", # -t: 标签ID
|
||||
"SnapShotXml": "", # -s: 快照XML文件
|
||||
"SWBoardType": "", # -b: 板子类型
|
||||
"SWProductType": "", # -p: 产品类型
|
||||
|
||||
# 可选参数
|
||||
"AlkaidRootPath": '', # 仓库根路径
|
||||
"DocsPath": "", # -d: 文档路径
|
||||
"HWChipType": "", # -c: 硬件芯片类型
|
||||
"HWPackageType": "", # -k: 硬件包类型
|
||||
"OutPath": "", # -o: 输出路径
|
||||
"ThreadNum": 1, # -j: 线程数
|
||||
"IplVersion": "CN", # -l: IPL版本
|
||||
|
||||
# 布尔参数
|
||||
"SkipCheckout": False, # -i: 跳过从bin检出kernel/mboot
|
||||
"OpenSource": False, # -f: 开放源代码
|
||||
"MounRiverSDK": False, # -m: 启用RiscVSupport时支持MounRiverSDK
|
||||
"RiscVSupport": False, # -n: 支持riscv源码
|
||||
"Cm4Support": False, # -y: 支持cm4源码
|
||||
"Doc2Pdf": False, # -z: 文档转换为pdf
|
||||
"Doc2Html": False, # -h: 文档转换为html
|
||||
"VerifyBuild": False, # -v: 验证构建
|
||||
"ReduceCodeSize": False, # -u: 减小代码大小
|
||||
"SkipSyncCode": False, # -x: 跳过通过快照XML同步代码
|
||||
"OpenRtosWhiteList": False, # -X: 开放所有rtos白名单
|
||||
"OpenCm4WhiteList": False, # -Y: 开放所有cm4白名单
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
parser = argparse.ArgumentParser(description='Sigmastar Release SDK Options',
|
||||
formatter_class=ConfigureStyleHelpFormatter,
|
||||
epilog= "more help info see: http://xxxxxx",
|
||||
add_help=False) #-hhelp 信息被占用了
|
||||
add = parser.add_argument
|
||||
add('-a', '--SWBoardAlias' , required=True, type=str, help='板子别名 iford souffle muffin...')
|
||||
add('-t', '--TagId' , required=True, type=str, help='Release的Tag')
|
||||
add('-s', '--SnapShotXml' , required=True, type=str, help='Alkaid仓库快照XML文件')
|
||||
add('-b', '--SWBoardType' , required=True, type=str, help='板子类型')
|
||||
add('-p', '--SWProductType' , required=True, type=str, help='Release产品类型列表')
|
||||
add('-r', '--AlkaidRootPath', default = get_alkaid_root(), type=str, help='Alkaid仓库根目录路径')
|
||||
add('-d', '--DocsPath' , default = '', type=str, help='文档路径')
|
||||
add('-c', '--HWChipType' , default = '', type=str, help='硬件芯片类型')
|
||||
add('-k', '--HWPackageType' , default = '', type=str, help='硬件封装类型')
|
||||
add('-o', '--OutPath' , default = "release", type=str, help='Release输出路径')
|
||||
add('-j', '--ThreadNum' , default = 1, type=int, help='编译使用的线程数')
|
||||
add('-i', '--SkipCheckout' , default = False, action = "store_true", help='跳过从bin检出kernel/mboot')
|
||||
add('-f', '--OpenSource' , default = False, action = "store_true",
|
||||
help="""是否开启SDK开源模式:
|
||||
| 闭源模式: MI编译为lib和ko对外提供功能
|
||||
| 开源模式: MI源码发布, 客户可直接获得MI原始代码""")
|
||||
add('-n', '--RiscVSupport' , default = False, action = "store_true", help='支持riscv源码')
|
||||
add('-y', '--Cm4Support' , default = False, action = "store_true", help='支持cm4源码')
|
||||
add('-m', '--MounRiverSDK' , default = False, action = "store_true", help='启用RiscVSupport时支持MounRiverSDK')
|
||||
add('-z', '--Doc2Pdf' , default = False, action = "store_true", help='将文档转换为PDF格式')
|
||||
add('-l', '--IplVersion' , default = "CN", type=str, choices=["CN", "WW"], help='选择IPL版本')
|
||||
add('-h', '--Doc2Html' , default = False, action = "store_true", help='将文档转换为HTML格式')
|
||||
add('-v', '--VerifyBuild' , default = False, action = "store_true", help='验证构建')
|
||||
add('-u', '--ReduceCodeSize', default = False, action = "store_true", help='减小代码体积')
|
||||
add('-x', '--SkipSyncCode' , default = False, action = "store_true", help='跳过通过快照XML同步代码')
|
||||
add('--help', action='help', help='显示帮助信息')
|
||||
add('--log', type=str,choices=['error', 'warn', 'info', 'debug', 'trace'], default='info', help='设置日志级别')
|
||||
self.parser = parser
|
||||
|
||||
def parse(self, args:List[str]):
|
||||
args = self.parser.parse_args(args)
|
||||
for k,v in args.__dict__.items():
|
||||
if k.startswith('__'):
|
||||
continue
|
||||
self[k] = v
|
||||
def check(self) -> bool:
|
||||
"""
|
||||
检查参数配置是否合法
|
||||
"""
|
||||
# 检查必需参数
|
||||
required_params = ["SWBoardAlias", "TagId", "SWBoardType", "SWProductType"]
|
||||
for param in required_params:
|
||||
if not self[param]:
|
||||
raise ValueError(f"必需参数 {param} 不能为空")
|
||||
|
||||
# 检查数值参数
|
||||
if not isinstance(self.ThreadNum, int) or self.ThreadNum <= 0:
|
||||
raise ValueError("ThreadNum 必须为正整数")
|
||||
|
||||
# 检查布尔参数
|
||||
bool_params = [
|
||||
"SkipCheckout", "OpenSource", "RiscVSupport", "Cm4Support",
|
||||
"Doc2Pdf", "Doc2Html", "VerifyBuild", "ReduceCodeSize",
|
||||
"SkipSyncCode", "OpenRtosWhiteList", "OpenCm4WhiteList", "MounRiverSDK"
|
||||
]
|
||||
for param in bool_params:
|
||||
if not isinstance(self[param], bool):
|
||||
raise ValueError(f"参数 {param} 必须为布尔值")
|
||||
# 检查快照XML文件是否存在
|
||||
if not self.SkipSyncCode and not self.SnapShotXml:
|
||||
raise ValueError("SnapShotXml is required when SkipSyncCode is False")
|
||||
return True
|
||||
|
||||
def help(self):
|
||||
self.parser.print_help()
|
Reference in New Issue
Block a user