openubmc-bingo 0.5.240__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of openubmc-bingo might be problematic. Click here for more details.
- bmcgo/__init__.py +12 -0
- bmcgo/bmcgo.py +22 -0
- bmcgo/bmcgo_config.py +176 -0
- bmcgo/cli/__init__.py +10 -0
- bmcgo/cli/cli.py +584 -0
- bmcgo/codegen/__init__.py +14 -0
- bmcgo/codegen/c/__init__.py +9 -0
- bmcgo/codegen/c/annotation.py +52 -0
- bmcgo/codegen/c/argument.py +42 -0
- bmcgo/codegen/c/codegen.py +153 -0
- bmcgo/codegen/c/comment.py +22 -0
- bmcgo/codegen/c/ctype_defination.py +353 -0
- bmcgo/codegen/c/helper.py +87 -0
- bmcgo/codegen/c/interface.py +63 -0
- bmcgo/codegen/c/method.py +82 -0
- bmcgo/codegen/c/property.py +180 -0
- bmcgo/codegen/c/renderer.py +21 -0
- bmcgo/codegen/c/signal.py +64 -0
- bmcgo/codegen/c/template/client.c.mako +145 -0
- bmcgo/codegen/c/template/client.h.mako +36 -0
- bmcgo/codegen/c/template/interface.c.mako +0 -0
- bmcgo/codegen/c/template/interface.introspect.xml.mako +99 -0
- bmcgo/codegen/c/template/micro_component.c.mako +32 -0
- bmcgo/codegen/c/template/public.c.mako +228 -0
- bmcgo/codegen/c/template/public.h.mako +128 -0
- bmcgo/codegen/c/template/server.c.mako +104 -0
- bmcgo/codegen/c/template/server.h.mako +36 -0
- bmcgo/codegen/lua/.lua-format +7 -0
- bmcgo/codegen/lua/Makefile +101 -0
- bmcgo/codegen/lua/__init__.py +9 -0
- bmcgo/codegen/lua/codegen.py +171 -0
- bmcgo/codegen/lua/proto/Makefile +87 -0
- bmcgo/codegen/lua/proto/ipmi_types.proto +17 -0
- bmcgo/codegen/lua/proto/types.proto +52 -0
- bmcgo/codegen/lua/script/check_intfs.py +161 -0
- bmcgo/codegen/lua/script/dto/__init__.py +11 -0
- bmcgo/codegen/lua/script/dto/exception.py +53 -0
- bmcgo/codegen/lua/script/dto/kepler_abstract.py +47 -0
- bmcgo/codegen/lua/script/dto/options.py +33 -0
- bmcgo/codegen/lua/script/dto/print_simple.py +19 -0
- bmcgo/codegen/lua/script/dto/redfish_api.py +241 -0
- bmcgo/codegen/lua/script/dto/url_route.py +195 -0
- bmcgo/codegen/lua/script/gen_db_json.py +444 -0
- bmcgo/codegen/lua/script/gen_depends.py +89 -0
- bmcgo/codegen/lua/script/gen_entry.py +263 -0
- bmcgo/codegen/lua/script/gen_feature_json.py +156 -0
- bmcgo/codegen/lua/script/gen_historical_local_db_json.py +88 -0
- bmcgo/codegen/lua/script/gen_intf_json.py +261 -0
- bmcgo/codegen/lua/script/gen_intf_rpc_json.py +575 -0
- bmcgo/codegen/lua/script/gen_ipmi_json.py +485 -0
- bmcgo/codegen/lua/script/gen_mdb_json.py +117 -0
- bmcgo/codegen/lua/script/gen_rpc_msg_json.py +487 -0
- bmcgo/codegen/lua/script/gen_schema.py +302 -0
- bmcgo/codegen/lua/script/ipmi_types_pb2.py +135 -0
- bmcgo/codegen/lua/script/loader/__init__.py +11 -0
- bmcgo/codegen/lua/script/loader/file_utils.py +33 -0
- bmcgo/codegen/lua/script/loader/kepler_abstract_collect.py +79 -0
- bmcgo/codegen/lua/script/loader/kepler_abstract_loader.py +47 -0
- bmcgo/codegen/lua/script/loader/redfish_loader.py +127 -0
- bmcgo/codegen/lua/script/lua_format.py +62 -0
- bmcgo/codegen/lua/script/mds_util.py +385 -0
- bmcgo/codegen/lua/script/merge_model.py +330 -0
- bmcgo/codegen/lua/script/merge_proto_algo.py +85 -0
- bmcgo/codegen/lua/script/proto_loader.py +47 -0
- bmcgo/codegen/lua/script/proto_plugin.py +140 -0
- bmcgo/codegen/lua/script/redfish_source_tree.py +118 -0
- bmcgo/codegen/lua/script/render_utils/__init__.py +38 -0
- bmcgo/codegen/lua/script/render_utils/base.py +25 -0
- bmcgo/codegen/lua/script/render_utils/client_lua.py +98 -0
- bmcgo/codegen/lua/script/render_utils/controller_lua.py +71 -0
- bmcgo/codegen/lua/script/render_utils/db_lua.py +224 -0
- bmcgo/codegen/lua/script/render_utils/error_lua.py +185 -0
- bmcgo/codegen/lua/script/render_utils/factory.py +52 -0
- bmcgo/codegen/lua/script/render_utils/ipmi_lua.py +159 -0
- bmcgo/codegen/lua/script/render_utils/ipmi_message_lua.py +24 -0
- bmcgo/codegen/lua/script/render_utils/mdb_lua.py +177 -0
- bmcgo/codegen/lua/script/render_utils/mdb_register.py +215 -0
- bmcgo/codegen/lua/script/render_utils/message_lua.py +26 -0
- bmcgo/codegen/lua/script/render_utils/messages_lua.py +156 -0
- bmcgo/codegen/lua/script/render_utils/model_lua.py +485 -0
- bmcgo/codegen/lua/script/render_utils/old_model_lua.py +429 -0
- bmcgo/codegen/lua/script/render_utils/plugin_lua.py +38 -0
- bmcgo/codegen/lua/script/render_utils/redfish_proto.py +86 -0
- bmcgo/codegen/lua/script/render_utils/request_lua.py +76 -0
- bmcgo/codegen/lua/script/render_utils/service_lua.py +130 -0
- bmcgo/codegen/lua/script/render_utils/utils_message_lua.py +125 -0
- bmcgo/codegen/lua/script/render_utils/validate_lua.py +221 -0
- bmcgo/codegen/lua/script/sep_ipmi_message_cmds.py +217 -0
- bmcgo/codegen/lua/script/template.py +166 -0
- bmcgo/codegen/lua/script/types_pb2.py +516 -0
- bmcgo/codegen/lua/script/utils.py +663 -0
- bmcgo/codegen/lua/script/validate.py +80 -0
- bmcgo/codegen/lua/script/yaml_to_json.py +73 -0
- bmcgo/codegen/lua/templates/Makefile +114 -0
- bmcgo/codegen/lua/templates/apps/Makefile +261 -0
- bmcgo/codegen/lua/templates/apps/Makefile.mdb.mk +64 -0
- bmcgo/codegen/lua/templates/apps/app.lua.mako +19 -0
- bmcgo/codegen/lua/templates/apps/class.lua.mako +35 -0
- bmcgo/codegen/lua/templates/apps/client.lua.mako +429 -0
- bmcgo/codegen/lua/templates/apps/controller.lua.mako +276 -0
- bmcgo/codegen/lua/templates/apps/datas.lua.mako +8 -0
- bmcgo/codegen/lua/templates/apps/db.lua.mako +89 -0
- bmcgo/codegen/lua/templates/apps/entry.lua.mako +128 -0
- bmcgo/codegen/lua/templates/apps/feature.lua.mako +37 -0
- bmcgo/codegen/lua/templates/apps/generate_route.mako +25 -0
- bmcgo/codegen/lua/templates/apps/impl_feature.lua.mako +72 -0
- bmcgo/codegen/lua/templates/apps/ipmi.lua.mako +97 -0
- bmcgo/codegen/lua/templates/apps/ipmi_cmd.lua.mako +18 -0
- bmcgo/codegen/lua/templates/apps/ipmi_message.lua.mako +36 -0
- bmcgo/codegen/lua/templates/apps/local_db.lua.mako +263 -0
- bmcgo/codegen/lua/templates/apps/main.lua.mako +25 -0
- bmcgo/codegen/lua/templates/apps/mc.lua.mako +77 -0
- bmcgo/codegen/lua/templates/apps/mdb.lua.mako +45 -0
- bmcgo/codegen/lua/templates/apps/mdb_interface.lua.mako +73 -0
- bmcgo/codegen/lua/templates/apps/message.lua.mako +38 -0
- bmcgo/codegen/lua/templates/apps/model.lua.mako +239 -0
- bmcgo/codegen/lua/templates/apps/orm_classes.lua.mako +16 -0
- bmcgo/codegen/lua/templates/apps/plugin.lua.mako +8 -0
- bmcgo/codegen/lua/templates/apps/redfish.proto.mako +47 -0
- bmcgo/codegen/lua/templates/apps/service.lua.mako +440 -0
- bmcgo/codegen/lua/templates/apps/signal_listen.lua.mako +19 -0
- bmcgo/codegen/lua/templates/apps/utils/default_intf.lua.mako +41 -0
- bmcgo/codegen/lua/templates/apps/utils/enum.mako +10 -0
- bmcgo/codegen/lua/templates/apps/utils/imports.mako +13 -0
- bmcgo/codegen/lua/templates/apps/utils/mdb_intf.lua.mako +25 -0
- bmcgo/codegen/lua/templates/apps/utils/mdb_obj.lua.mako +23 -0
- bmcgo/codegen/lua/templates/apps/utils/message.mako +160 -0
- bmcgo/codegen/lua/templates/apps/utils/request.lua.mako +59 -0
- bmcgo/codegen/lua/templates/apps/utils/validate.mako +83 -0
- bmcgo/codegen/lua/templates/errors.lua.mako +36 -0
- bmcgo/codegen/lua/templates/messages.lua.mako +32 -0
- bmcgo/codegen/lua/templates/new_app/.clang-format.mako +170 -0
- bmcgo/codegen/lua/templates/new_app/.gitignore.mako +26 -0
- bmcgo/codegen/lua/templates/new_app/CHANGELOG.md.mako +0 -0
- bmcgo/codegen/lua/templates/new_app/CMakeLists.txt.mako +29 -0
- bmcgo/codegen/lua/templates/new_app/Makefile.mako +25 -0
- bmcgo/codegen/lua/templates/new_app/README.md.mako +0 -0
- bmcgo/codegen/lua/templates/new_app/conanfile.py.mako +7 -0
- bmcgo/codegen/lua/templates/new_app/config.cfg.mako +6 -0
- bmcgo/codegen/lua/templates/new_app/mds/model.json.mako +3 -0
- bmcgo/codegen/lua/templates/new_app/mds/service.json.mako +21 -0
- bmcgo/codegen/lua/templates/new_app/permissions.ini.mako +16 -0
- bmcgo/codegen/lua/templates/new_app/src/lualib/${project_name}_app.lua.mako +16 -0
- bmcgo/codegen/lua/templates/new_app/src/service/main.lua.mako +25 -0
- bmcgo/codegen/lua/templates/new_app/test/integration/test_${project_name}.conf.mako +9 -0
- bmcgo/codegen/lua/templates/new_app/test/integration/test_${project_name}.lua.mako +47 -0
- bmcgo/codegen/lua/templates/new_app/test/unit/test.lua.mako +23 -0
- bmcgo/codegen/lua/templates/new_app/user_conf/rootfs/etc/systemd/system/${project_name}.service.mako +18 -0
- bmcgo/codegen/lua/templates/new_app/user_conf/rootfs/etc/systemd/system/multi-user.target.wants/${project_name}.service.link +1 -0
- bmcgo/component/__init__.py +10 -0
- bmcgo/component/analysis/analysis.py +183 -0
- bmcgo/component/analysis/build_deps.py +165 -0
- bmcgo/component/analysis/data_deps.py +333 -0
- bmcgo/component/analysis/dep-rules.json +912 -0
- bmcgo/component/analysis/dep_node.py +110 -0
- bmcgo/component/analysis/intf_deps.py +163 -0
- bmcgo/component/analysis/intf_validation.py +254 -0
- bmcgo/component/analysis/rule.py +211 -0
- bmcgo/component/analysis/smc_dfx_whitelist.json +11 -0
- bmcgo/component/analysis/sr_validation.py +391 -0
- bmcgo/component/build.py +222 -0
- bmcgo/component/component_dt_version_parse.py +348 -0
- bmcgo/component/component_helper.py +114 -0
- bmcgo/component/coverage/__init__.py +11 -0
- bmcgo/component/coverage/c_incremental_cov_report.template +53 -0
- bmcgo/component/coverage/incremental_cov.py +464 -0
- bmcgo/component/deploy.py +110 -0
- bmcgo/component/gen.py +169 -0
- bmcgo/component/package_info.py +236 -0
- bmcgo/component/template/conanbase.py.mako +278 -0
- bmcgo/component/template/conanfile.deploy.py.mako +40 -0
- bmcgo/component/test.py +947 -0
- bmcgo/errors.py +119 -0
- bmcgo/frame.py +217 -0
- bmcgo/functional/__init__.py +10 -0
- bmcgo/functional/analysis.py +96 -0
- bmcgo/functional/bmc_studio_action.py +98 -0
- bmcgo/functional/check.py +185 -0
- bmcgo/functional/conan_index_build.py +251 -0
- bmcgo/functional/config.py +332 -0
- bmcgo/functional/csr_build.py +724 -0
- bmcgo/functional/deploy.py +263 -0
- bmcgo/functional/diff.py +235 -0
- bmcgo/functional/fetch.py +235 -0
- bmcgo/functional/full_component.py +391 -0
- bmcgo/functional/maintain.py +381 -0
- bmcgo/functional/new.py +166 -0
- bmcgo/functional/schema_valid.py +111 -0
- bmcgo/functional/simple_sign.py +104 -0
- bmcgo/functional/upgrade.py +78 -0
- bmcgo/ipmigen/__init__.py +13 -0
- bmcgo/ipmigen/ctype_defination.py +82 -0
- bmcgo/ipmigen/ipmigen.py +309 -0
- bmcgo/ipmigen/template/cmd.c.mako +366 -0
- bmcgo/ipmigen/template/ipmi.c.mako +25 -0
- bmcgo/ipmigen/template/ipmi.h.mako +51 -0
- bmcgo/logger.py +176 -0
- bmcgo/misc.py +117 -0
- bmcgo/target/app.yml +17 -0
- bmcgo/target/install_sdk.yml +15 -0
- bmcgo/target/personal.yml +53 -0
- bmcgo/target/publish.yml +45 -0
- bmcgo/tasks/__init__.py +11 -0
- bmcgo/tasks/download_buildtools_hm.py +124 -0
- bmcgo/tasks/misc.py +15 -0
- bmcgo/tasks/task.py +354 -0
- bmcgo/tasks/task_build_conan.py +714 -0
- bmcgo/tasks/task_build_rootfs_img.py +595 -0
- bmcgo/tasks/task_buildgppbin.py +88 -0
- bmcgo/tasks/task_buildhpm_ext4.py +82 -0
- bmcgo/tasks/task_create_interface_config.py +122 -0
- bmcgo/tasks/task_download_buildtools.py +99 -0
- bmcgo/tasks/task_download_dependency.py +72 -0
- bmcgo/tasks/task_hpm_envir_prepare.py +112 -0
- bmcgo/tasks/task_packet_to_supporte.py +87 -0
- bmcgo/tasks/task_prepare.py +105 -0
- bmcgo/tasks/task_sign_and_pack_hpm.py +42 -0
- bmcgo/utils/__init__.py +10 -0
- bmcgo/utils/buffer.py +128 -0
- bmcgo/utils/combine_json_schemas.py +170 -0
- bmcgo/utils/component_post.py +54 -0
- bmcgo/utils/component_version_check.py +86 -0
- bmcgo/utils/config.py +1067 -0
- bmcgo/utils/fetch_component_code.py +232 -0
- bmcgo/utils/install_manager.py +61 -0
- bmcgo/utils/installations/__init__.py +10 -0
- bmcgo/utils/installations/base_installer.py +70 -0
- bmcgo/utils/installations/install_consts.py +30 -0
- bmcgo/utils/installations/install_plans/bingo.yml +11 -0
- bmcgo/utils/installations/install_workflow.py +50 -0
- bmcgo/utils/installations/installers/apt_installer.py +177 -0
- bmcgo/utils/installations/installers/pip_installer.py +46 -0
- bmcgo/utils/installations/version_util.py +100 -0
- bmcgo/utils/mapping_config_patch.py +443 -0
- bmcgo/utils/perf_analysis.py +114 -0
- bmcgo/utils/tools.py +704 -0
- bmcgo/worker.py +417 -0
- openubmc_bingo-0.5.240.dist-info/METADATA +30 -0
- openubmc_bingo-0.5.240.dist-info/RECORD +242 -0
- openubmc_bingo-0.5.240.dist-info/WHEEL +5 -0
- openubmc_bingo-0.5.240.dist-info/entry_points.txt +2 -0
- openubmc_bingo-0.5.240.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# encoding=utf-8
|
|
3
|
+
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
|
|
4
|
+
# openUBMC is licensed under Mulan PSL v2.
|
|
5
|
+
# You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
6
|
+
# You may obtain a copy of Mulan PSL v2 at:
|
|
7
|
+
# http://license.coscl.org.cn/MulanPSL2
|
|
8
|
+
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
9
|
+
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
10
|
+
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
11
|
+
# See the Mulan PSL v2 for more details.
|
|
12
|
+
import os
|
|
13
|
+
import argparse
|
|
14
|
+
import tempfile
|
|
15
|
+
import stat
|
|
16
|
+
import shutil
|
|
17
|
+
import re
|
|
18
|
+
import filecmp
|
|
19
|
+
import yaml
|
|
20
|
+
from colorama import Fore, Style
|
|
21
|
+
from git import Repo
|
|
22
|
+
from git import Commit
|
|
23
|
+
from bmcgo.misc import CommandInfo
|
|
24
|
+
from bmcgo.utils.tools import Tools
|
|
25
|
+
from bmcgo.component.build import BuildComp
|
|
26
|
+
from bmcgo import errors
|
|
27
|
+
from bmcgo.bmcgo_config import BmcgoConfig
|
|
28
|
+
from bmcgo import misc
|
|
29
|
+
|
|
30
|
+
tool = Tools("maintain")
|
|
31
|
+
log = tool.log
|
|
32
|
+
command_info: CommandInfo = CommandInfo(
|
|
33
|
+
group="Misc commands",
|
|
34
|
+
name="maintain",
|
|
35
|
+
description=["组件维护,按conan方式生成维护组件构建脚本, 同时维护版本号、patch等"],
|
|
36
|
+
hidden=True
|
|
37
|
+
)
|
|
38
|
+
CONANDATA_SOURCES = "sources"
|
|
39
|
+
CONANDATA_VERSIONS = "versions"
|
|
40
|
+
CONANDATA_PATCHES = "patches"
|
|
41
|
+
PATCH_FILE_KEY = "patch_file"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def if_available(bconfig: BmcgoConfig):
|
|
45
|
+
return bconfig.conan_index is not None
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class PatchInfo():
|
|
49
|
+
def __init__(self, commit: Commit):
|
|
50
|
+
self.commit = commit
|
|
51
|
+
log.info("补丁提交信息 =============================>>>>")
|
|
52
|
+
log.info(self.commit.message)
|
|
53
|
+
log.info("补丁提交信息 =============================<<<<")
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def author(self):
|
|
57
|
+
return self.commit.author.name
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def description(self):
|
|
61
|
+
match = re.search("(【修改描述】(.*))\n", self.commit.message)
|
|
62
|
+
if match:
|
|
63
|
+
return match.group(1)
|
|
64
|
+
lines = self.commit.message.split("\n")
|
|
65
|
+
for line in lines:
|
|
66
|
+
if line.strip() == "":
|
|
67
|
+
continue
|
|
68
|
+
if re.search("merge.*into.*", line):
|
|
69
|
+
continue
|
|
70
|
+
return line.strip()
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def merged_by(self):
|
|
74
|
+
match = re.search("Merged-by: (.*)\n", self.commit.message)
|
|
75
|
+
if match:
|
|
76
|
+
return match.group(1)
|
|
77
|
+
raise RuntimeError("无法找到合法的Merged-by合入人信息,请检查待提取的提交节点是否正确配置")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class BmcgoCommand:
|
|
81
|
+
url = None
|
|
82
|
+
tag = None
|
|
83
|
+
revision = None
|
|
84
|
+
next_version = None
|
|
85
|
+
sub_folder = None
|
|
86
|
+
recipe_folder = None
|
|
87
|
+
conan_folder = None
|
|
88
|
+
|
|
89
|
+
def __init__(self, bconfig: BmcgoConfig, *args):
|
|
90
|
+
self.patch_file = []
|
|
91
|
+
self.bconfig = bconfig
|
|
92
|
+
parser = argparse.ArgumentParser(prog="bmcgo maintain", description="BMC组件的维护管理工具", add_help=True,
|
|
93
|
+
formatter_class=argparse.RawTextHelpFormatter)
|
|
94
|
+
parser.add_argument("-cp", "--conan_package", help="指定需要维护的组件版本,示例:component/1.2.3", required=True)
|
|
95
|
+
parser.add_argument("-p", "--patch_file", help="添加patch文件,可指定多个,顺序追加到代码中", action='append')
|
|
96
|
+
parser.add_argument("-b", "--branch", help="用于提取patch的分支,与commit_id配合使用", default="master")
|
|
97
|
+
parser.add_argument("-c", "--commit_id", help="需要生成patch的提交节点,长度不低于8个字符,可指定多个,顺序追加到代码中",
|
|
98
|
+
action='append')
|
|
99
|
+
parser.add_argument("-v", "--version", help="指定需要生成的组件版本号", default=None)
|
|
100
|
+
parser.add_argument("-r", "--remote", default=misc.CONAN_REPO,
|
|
101
|
+
help="conan远程仓,请检查conan remote list查看已配置的conan仓")
|
|
102
|
+
parsed_args = parser.parse_args(*args)
|
|
103
|
+
cp = parsed_args.conan_package
|
|
104
|
+
if (not re.match("^[a-zA-Z0-9_-]+/([1-9][0-9]*|[0-9])\.[0-9]+\.[0-9]+$", cp) and
|
|
105
|
+
not re.match("^[a-zA-Z0-9_-]+/(([1-9][0-9]*|[0-9])\.[0-9]+\.[0-9]+)(-build\.[0-9]+)$", cp) and
|
|
106
|
+
not re.match("^[a-zA-Z0-9_-]+/(([1-9][0-9]*|[0-9])\.[0-9]+\.[0-9]+)(.p[0-9]+)$" + cp)):
|
|
107
|
+
raise errors.BmcGoException("-cp参数错误,不满足格式\"<name>/<version>\"要求")
|
|
108
|
+
self.conan_package = cp
|
|
109
|
+
self.name = self.conan_package.split("/")[0]
|
|
110
|
+
self.base_version = self.conan_package.split("/")[1]
|
|
111
|
+
self.remote = parsed_args.remote
|
|
112
|
+
self.arg_special_version = parsed_args.version
|
|
113
|
+
if parsed_args.patch_file is None:
|
|
114
|
+
parsed_args.patch_file = []
|
|
115
|
+
for patch_file in parsed_args.patch_file:
|
|
116
|
+
if not os.path.isfile(patch_file):
|
|
117
|
+
raise errors.BmcGoException(f"补丁文件 {patch_file} 不存在")
|
|
118
|
+
self.patch_file.append(os.path.realpath(patch_file))
|
|
119
|
+
|
|
120
|
+
# 待提取的提交节点基本信息
|
|
121
|
+
self.patch_commit: dict[str, PatchInfo] = {}
|
|
122
|
+
self.branch = parsed_args.branch
|
|
123
|
+
self.commit_id = parsed_args.commit_id
|
|
124
|
+
if self.commit_id is None:
|
|
125
|
+
self.commit_id = []
|
|
126
|
+
for commit in self.commit_id:
|
|
127
|
+
if re.match(r"^[a-f0-9]{8,40}$", commit) is None:
|
|
128
|
+
raise errors.ConfigException(f"参数错误, --commit_id({commit}) 格式错误")
|
|
129
|
+
self.patch_description = ""
|
|
130
|
+
self.dir = tempfile.TemporaryDirectory(prefix="bmcgo_maint")
|
|
131
|
+
for file in self.patch_file:
|
|
132
|
+
if not os.path.isfile(file):
|
|
133
|
+
raise errors.BmcGoException(f"补丁文件 {file} 不存在")
|
|
134
|
+
log.debug(f"临时文件夹: {self.dir.name}")
|
|
135
|
+
|
|
136
|
+
def run(self):
|
|
137
|
+
self._fetch_conan_info()
|
|
138
|
+
os.chdir(self.dir.name)
|
|
139
|
+
log.info(f"开始克隆 {self.url}")
|
|
140
|
+
repo = Repo.clone_from(self.url, ".")
|
|
141
|
+
repo.git.checkout(self.tag)
|
|
142
|
+
if not os.path.isfile("mds/service.json"):
|
|
143
|
+
raise errors.NotFoundException("文件 mds/service.json 不存在, 可能不是一个有效的组件")
|
|
144
|
+
# 生成conanbase.py和conanfile.yml
|
|
145
|
+
log.info(f"生成 conanfil.py 和conanbase.py")
|
|
146
|
+
bconfig = BmcgoConfig()
|
|
147
|
+
comp = BuildComp(bconfig, ["--maintain"], gen_conanbase=True)
|
|
148
|
+
self.recipe_folder = os.path.join(self.bconfig.conan_index.folder, comp.info.name)
|
|
149
|
+
if not os.path.isdir(self.recipe_folder):
|
|
150
|
+
os.makedirs(self.recipe_folder)
|
|
151
|
+
self._update_next_version()
|
|
152
|
+
|
|
153
|
+
conanfile = os.path.realpath("conanfile.py")
|
|
154
|
+
conanbase = os.path.realpath("conanbase.py")
|
|
155
|
+
if not os.path.isfile(conanfile):
|
|
156
|
+
raise errors.NotFoundException("文件 conanfile.py 不存在, 可能不是一个有效的组件")
|
|
157
|
+
if not os.path.isfile(conanbase):
|
|
158
|
+
raise errors.NotFoundException("文件 conanbase.py 不存在, 可能不是一个有效的组件")
|
|
159
|
+
# 计算recipe目录
|
|
160
|
+
self.sub_folder = self.next_version + ".x"
|
|
161
|
+
while self.sub_folder != ".x":
|
|
162
|
+
self.conan_folder = os.path.join(self.recipe_folder, self.sub_folder)
|
|
163
|
+
# 找到recipe
|
|
164
|
+
if not self._recipe_need_change(conanfile, conanbase):
|
|
165
|
+
break
|
|
166
|
+
self.conan_folder = None
|
|
167
|
+
self.sub_folder = ".".join(self.sub_folder.split(".")[0:-2]) + ".x"
|
|
168
|
+
if not self.conan_folder:
|
|
169
|
+
# 默认是版号前2段 + ".x"
|
|
170
|
+
self.sub_folder = ".".join(self.next_version.split(".")[0:2]) + ".x"
|
|
171
|
+
|
|
172
|
+
self.conan_folder = os.path.join(self.recipe_folder, self.sub_folder)
|
|
173
|
+
if not os.path.isdir(self.conan_folder):
|
|
174
|
+
os.makedirs(self.conan_folder)
|
|
175
|
+
|
|
176
|
+
self._gen_patches(repo)
|
|
177
|
+
if not self._gen_conandata():
|
|
178
|
+
return -1
|
|
179
|
+
self._gen_config()
|
|
180
|
+
shutil.copyfile(conanfile, os.path.join(self.conan_folder, "conanfile.py"))
|
|
181
|
+
shutil.copyfile(conanbase, os.path.join(self.conan_folder, "conanbase.py"))
|
|
182
|
+
log.success(f"生成维护版本 {self.name}/{self.next_version} 成功")
|
|
183
|
+
return 0
|
|
184
|
+
|
|
185
|
+
def _fetch_conan_info(self):
|
|
186
|
+
user = tool.conan_user
|
|
187
|
+
export_path = os.path.join(tool.conan_data, self.conan_package, f"{user}/stable", "export")
|
|
188
|
+
if not os.path.isdir(export_path):
|
|
189
|
+
cmd = f"conan download {self.conan_package}@{user}/stable -r {self.remote} -re"
|
|
190
|
+
tool.run_command(cmd, error_log=f"组件 {self.conan_package} 未找到,请检查网络连接以及该版本是否已发布")
|
|
191
|
+
conanfile = os.path.join(export_path, "conanfile.py")
|
|
192
|
+
conandata = os.path.join(export_path, "conandata.yml")
|
|
193
|
+
if os.path.isfile(conandata):
|
|
194
|
+
log.info(f"从 {conandata} 读取源码tag的url")
|
|
195
|
+
# 尝试从conandata中获取代码仓地址
|
|
196
|
+
with open(conandata, "r") as fp:
|
|
197
|
+
data = yaml.safe_load(fp)
|
|
198
|
+
cfg = data.get("sources", {}).get(self.base_version)
|
|
199
|
+
if cfg is None:
|
|
200
|
+
raise RuntimeError(f"${conandata}不存在组件 {self.conan_package} 配置, 请检查是否正确")
|
|
201
|
+
self.url = cfg.get("url")
|
|
202
|
+
branch = cfg.get("branch")
|
|
203
|
+
if re.match("^refs/tags/[0-9]+\\.[0-9]+\\.[0-9]+$", branch):
|
|
204
|
+
self.tag = branch[len("refs/tags/"):]
|
|
205
|
+
else:
|
|
206
|
+
raise RuntimeError(f"${conandata}的组件 {self.conan_package} 配置错误, 未找到有效的tag")
|
|
207
|
+
else:
|
|
208
|
+
log.info(f"从 {conanfile} 读取源码tag的url")
|
|
209
|
+
self.tag = self.base_version
|
|
210
|
+
with open(conanfile, "r") as fp:
|
|
211
|
+
lines = fp.readlines()
|
|
212
|
+
for idx, line in enumerate(lines):
|
|
213
|
+
if line.find('scm = {"revision":') > 0:
|
|
214
|
+
self.url = re.split(r'["]', lines[idx + 2])[-2]
|
|
215
|
+
break
|
|
216
|
+
else:
|
|
217
|
+
raise RuntimeError("无法找到版本(revision)和地址(url)字段")
|
|
218
|
+
|
|
219
|
+
def _update_next_version(self):
|
|
220
|
+
self.next_version = self.arg_special_version
|
|
221
|
+
if not self.next_version:
|
|
222
|
+
if re.match("^(([1-9][0-9]*|[0-9])\.[0-9]+\.[0-9]+)(-build\.[0-9]+)$", self.base_version):
|
|
223
|
+
temp_version = self.base_version.split(".")
|
|
224
|
+
temp_version[-1] = str(int(temp_version[-1]) + 1)
|
|
225
|
+
self.next_version = ".".join(temp_version)
|
|
226
|
+
else:
|
|
227
|
+
self.next_version = self.base_version.split("-")[0] + "-build.1"
|
|
228
|
+
log.info(f"自动生成的版本号为 {Fore.GREEN}{self.next_version}{Style.RESET_ALL}")
|
|
229
|
+
version = input("请回车确认 或者 输入你期望的版本号(必须以-build.x结束,如1.2.3-build.1): ").strip()
|
|
230
|
+
if version:
|
|
231
|
+
self.next_version = version
|
|
232
|
+
if not self.arg_special_version and "-build." not in self.next_version:
|
|
233
|
+
raise errors.BmcGoException(f"版本号格式必须以-build.x结束,如1.2.3-build.1")
|
|
234
|
+
restr = r"^(([1-9][0-9]*|[0-9])\.[0-9]+\.[0-9]+)(-build\.[1-9][0-9]*)?$"
|
|
235
|
+
match = re.match(restr, self.next_version)
|
|
236
|
+
if not match:
|
|
237
|
+
raise errors.BmcGoException(f"版本号 {self.next_version} 不满足正则表达式 '{restr}' 要求")
|
|
238
|
+
log.info(f"创建组件版本 {Fore.GREEN}{self.next_version}{Style.RESET_ALL}")
|
|
239
|
+
|
|
240
|
+
def _gen_patches(self, repo: Repo):
|
|
241
|
+
# 用户指定patch
|
|
242
|
+
patches_dir = os.path.join(self.conan_folder, "..", CONANDATA_PATCHES)
|
|
243
|
+
if len(self.patch_file) > 0 and not os.path.isdir(patches_dir):
|
|
244
|
+
os.makedirs(patches_dir)
|
|
245
|
+
for file in self.patch_file:
|
|
246
|
+
patch_file = os.path.join(patches_dir, os.path.basename(file))
|
|
247
|
+
if not os.path.isfile(patch_file) or not filecmp.cmp(file, patch_file):
|
|
248
|
+
log.info(f"复制补丁文件 {patch_file}")
|
|
249
|
+
shutil.copyfile(file, patch_file)
|
|
250
|
+
|
|
251
|
+
if len(self.commit_id) == 0:
|
|
252
|
+
return
|
|
253
|
+
# 从代码仓生成patch
|
|
254
|
+
if not os.path.isdir(patches_dir):
|
|
255
|
+
os.makedirs(patches_dir)
|
|
256
|
+
|
|
257
|
+
repo.git.checkout(self.branch)
|
|
258
|
+
for commit_id in self.commit_id:
|
|
259
|
+
found = False
|
|
260
|
+
for commit in repo.iter_commits():
|
|
261
|
+
if commit.hexsha.startswith(commit_id):
|
|
262
|
+
commit_id = commit.hexsha
|
|
263
|
+
found = True
|
|
264
|
+
break
|
|
265
|
+
if not found:
|
|
266
|
+
raise errors.ParameterException(f"无效的提交节点: {commit_id}")
|
|
267
|
+
log.info(f"开始生成补丁文件, 提交节点: {commit_id}")
|
|
268
|
+
patch_info = PatchInfo(commit)
|
|
269
|
+
cmd = f"git format-patch -1 {commit_id} --numbered-files -- ':!mds/service.json' ':!CHANGELOG*'"
|
|
270
|
+
cmd += " ':!ChangeLog*'"
|
|
271
|
+
tool.run_command(cmd)
|
|
272
|
+
patch_id = 0
|
|
273
|
+
while True:
|
|
274
|
+
if patch_id == 0:
|
|
275
|
+
patch_file = os.path.join(patches_dir, commit.hexsha + ".patch")
|
|
276
|
+
else:
|
|
277
|
+
patch_file = os.path.join(patches_dir, commit.hexsha + f"_{patch_id}.patch")
|
|
278
|
+
if not os.path.isfile(patch_file) or filecmp.cmp("1", patch_file):
|
|
279
|
+
break
|
|
280
|
+
log.warning(f"待生成的补丁 与 {patch_file} 不一致,尝试生成新的补丁文件名")
|
|
281
|
+
patch_id += 1
|
|
282
|
+
shutil.copyfile("1", patch_file)
|
|
283
|
+
log.success(f"补丁文件 {patch_file} 创建成功")
|
|
284
|
+
self.patch_file.append(patch_file)
|
|
285
|
+
self.patch_commit[patch_file] = patch_info
|
|
286
|
+
|
|
287
|
+
def _gen_config(self):
|
|
288
|
+
"""生成config.yml文件"""
|
|
289
|
+
config_file = os.path.join(self.recipe_folder, "config.yml")
|
|
290
|
+
config = {}
|
|
291
|
+
if os.path.isfile(config_file):
|
|
292
|
+
with open(config_file, "r") as fp:
|
|
293
|
+
config = yaml.safe_load(fp)
|
|
294
|
+
if config.get(CONANDATA_VERSIONS) is None:
|
|
295
|
+
config[CONANDATA_VERSIONS] = {}
|
|
296
|
+
config[CONANDATA_VERSIONS][self.next_version] = {
|
|
297
|
+
"folder": os.path.basename(self.sub_folder)
|
|
298
|
+
}
|
|
299
|
+
with os.fdopen(os.open(config_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
300
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w') as file_handler:
|
|
301
|
+
yaml.dump(config, file_handler, encoding='utf-8', allow_unicode=True)
|
|
302
|
+
|
|
303
|
+
def _recipe_need_change(self, conanfile, conanbase):
|
|
304
|
+
"""检查recipe目录是否需要切换"""
|
|
305
|
+
ori_conanfile = os.path.join(self.conan_folder, "conanfile.py")
|
|
306
|
+
ori_conanbase = os.path.join(self.conan_folder, "conanbase.py")
|
|
307
|
+
# 文件不存在时无需切换
|
|
308
|
+
if not os.path.isfile(ori_conanfile) or not os.path.isfile(ori_conanbase):
|
|
309
|
+
return True
|
|
310
|
+
# 文件完全相同时无需切换
|
|
311
|
+
if filecmp.cmp(ori_conanfile, conanfile) and filecmp.cmp(ori_conanbase, conanbase):
|
|
312
|
+
return False
|
|
313
|
+
# 其它场景需要切换
|
|
314
|
+
return True
|
|
315
|
+
|
|
316
|
+
def _get_prev_patches(self):
|
|
317
|
+
"""获取上个版本的补丁列表"""
|
|
318
|
+
config_file = os.path.join(self.recipe_folder, "config.yml")
|
|
319
|
+
if not os.path.isfile(config_file):
|
|
320
|
+
return []
|
|
321
|
+
with open(config_file, "r") as fp:
|
|
322
|
+
config = yaml.safe_load(fp)
|
|
323
|
+
folder = config.get("versions", {}).get(self.base_version, {}).get("folder")
|
|
324
|
+
if folder is None:
|
|
325
|
+
return []
|
|
326
|
+
config_file = os.path.join(self.recipe_folder, folder, "conandata.yml")
|
|
327
|
+
if not os.path.isfile(config_file):
|
|
328
|
+
return []
|
|
329
|
+
with open(config_file, "r") as fp:
|
|
330
|
+
config = yaml.safe_load(fp)
|
|
331
|
+
return config.get("patches", {}).get(self.base_version, [])
|
|
332
|
+
|
|
333
|
+
def _gen_conandata(self):
|
|
334
|
+
"""生成conandata.yml文件"""
|
|
335
|
+
config_file = os.path.join(self.conan_folder, "conandata.yml")
|
|
336
|
+
config = {}
|
|
337
|
+
if os.path.isfile(config_file):
|
|
338
|
+
with open(config_file, "r") as fp:
|
|
339
|
+
config = yaml.safe_load(fp)
|
|
340
|
+
if config.get(CONANDATA_SOURCES) is None:
|
|
341
|
+
config[CONANDATA_SOURCES] = {}
|
|
342
|
+
source = {
|
|
343
|
+
"url": self.url,
|
|
344
|
+
"branch": f"refs/tags/{self.tag}",
|
|
345
|
+
"shallow": True
|
|
346
|
+
}
|
|
347
|
+
if config.get(CONANDATA_PATCHES) is None:
|
|
348
|
+
config[CONANDATA_PATCHES] = {}
|
|
349
|
+
patches = config[CONANDATA_PATCHES].get(self.next_version, [])
|
|
350
|
+
if not patches:
|
|
351
|
+
patches = self._get_prev_patches()
|
|
352
|
+
for file in self.patch_file:
|
|
353
|
+
found = False
|
|
354
|
+
for patch in patches:
|
|
355
|
+
if patch.get(PATCH_FILE_KEY, "") == "patches/" + os.path.basename(file):
|
|
356
|
+
found = True
|
|
357
|
+
break
|
|
358
|
+
if found:
|
|
359
|
+
continue
|
|
360
|
+
patch_item = {}
|
|
361
|
+
commit = self.patch_commit.get(file)
|
|
362
|
+
if commit:
|
|
363
|
+
patch_item["description"] = commit.description
|
|
364
|
+
patch_item["author"] = commit.author
|
|
365
|
+
patch_item["merged_by"] = commit.merged_by
|
|
366
|
+
patch_item["commit_id"] = commit.commit.hexsha
|
|
367
|
+
patch_item[PATCH_FILE_KEY] = "patches/" + os.path.basename(file)
|
|
368
|
+
patches.append(patch_item)
|
|
369
|
+
for patch in patches:
|
|
370
|
+
log.success(f"组件 {self.next_version} 包含补丁文件: " + patch.get(PATCH_FILE_KEY))
|
|
371
|
+
log.info(f" description: " + patch.get("description", ""))
|
|
372
|
+
log.info(f" author: " + patch.get("author", ""))
|
|
373
|
+
log.info(f" merged_by: " + patch.get("merged_by", ""))
|
|
374
|
+
log.info(f" commit_id: " + patch.get("commit_id", ""))
|
|
375
|
+
config[CONANDATA_SOURCES][self.next_version] = source
|
|
376
|
+
config[CONANDATA_PATCHES][self.next_version] = patches
|
|
377
|
+
log.info(f"生成 {config_file}")
|
|
378
|
+
with os.fdopen(os.open(config_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
379
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w') as file_handler:
|
|
380
|
+
yaml.dump(config, file_handler, encoding='utf-8', allow_unicode=True, sort_keys=False)
|
|
381
|
+
return True
|
bmcgo/functional/new.py
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# encoding=utf-8
|
|
3
|
+
# 描述:创建组件
|
|
4
|
+
# Copyright (c) 2024 Huawei Technologies Co., Ltd.
|
|
5
|
+
# openUBMC is licensed under Mulan PSL v2.
|
|
6
|
+
# You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
7
|
+
# You may obtain a copy of Mulan PSL v2 at:
|
|
8
|
+
# http://license.coscl.org.cn/MulanPSL2
|
|
9
|
+
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
10
|
+
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
11
|
+
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
12
|
+
# See the Mulan PSL v2 for more details.
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
import select
|
|
16
|
+
import argparse
|
|
17
|
+
import shutil
|
|
18
|
+
import subprocess
|
|
19
|
+
from bmcgo.bmcgo_config import BmcgoConfig
|
|
20
|
+
from bmcgo.utils.tools import Tools
|
|
21
|
+
from bmcgo import misc
|
|
22
|
+
|
|
23
|
+
tools = Tools("new")
|
|
24
|
+
log = tools.log
|
|
25
|
+
cwd = os.getcwd()
|
|
26
|
+
|
|
27
|
+
command_info: misc.CommandInfo = misc.CommandInfo(
|
|
28
|
+
group="Misc commands",
|
|
29
|
+
name="new",
|
|
30
|
+
description=["创建组件"],
|
|
31
|
+
hidden=False
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def if_available(bconfig: BmcgoConfig):
|
|
36
|
+
return True
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
_LUA = "lua"
|
|
40
|
+
_APP = "application"
|
|
41
|
+
_DEFAULT = ""
|
|
42
|
+
# 必选项:选项缩写,选项,选项的中文说明
|
|
43
|
+
_REQUIRES = [["n", "name", "组件名"]]
|
|
44
|
+
# 可选项:选项缩写,选项,选项的中文说明,可选值,默认值
|
|
45
|
+
_OPTIONS = [["t", "type", "组件类型", ["application"], "application"], ["l", "language", "组件编程语言", ["lua"], "lua"]]
|
|
46
|
+
# 环境中存放bmcgo自动生成工具相对的目录,组件中存放bmcgo自动生成工具的临时相对目录,模板脚本的相对路径,模板的相对目录
|
|
47
|
+
_TEMPLATES = {
|
|
48
|
+
_LUA : {
|
|
49
|
+
_APP : ['codegen/lua', 'temp/lua_codegen', 'script/template.py', 'templates/new_app']
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class BmcgoCommand:
|
|
55
|
+
def __init__(self, bconfig: BmcgoConfig, *args):
|
|
56
|
+
self.bconfig = bconfig
|
|
57
|
+
parser = argparse.ArgumentParser(prog="bingo new", description="创建组件", add_help=True,
|
|
58
|
+
formatter_class=argparse.RawTextHelpFormatter)
|
|
59
|
+
for item in _REQUIRES:
|
|
60
|
+
parser.add_argument(f"-{item[0]}", f"--{item[1]}", help=f"指定{item[2]}", required=True)
|
|
61
|
+
for item in _OPTIONS:
|
|
62
|
+
parser.add_argument(f"-{item[0]}", f"--{item[1]}", help=f"指定{item[2]}, " +
|
|
63
|
+
f"可选值: {', '.join(item[3])}\n默认: {item[4]}")
|
|
64
|
+
|
|
65
|
+
parsed_args, _ = parser.parse_known_args(*args)
|
|
66
|
+
self.name = parsed_args.name
|
|
67
|
+
self.type = parsed_args.type
|
|
68
|
+
self.language = parsed_args.language
|
|
69
|
+
self.path = os.path.join(cwd, self.name)
|
|
70
|
+
|
|
71
|
+
def run(self):
|
|
72
|
+
if os.path.exists(self.path):
|
|
73
|
+
log.error(f"当前目录下已存在{self.name}子目录, 无法创建{self.name}组件")
|
|
74
|
+
return -1
|
|
75
|
+
|
|
76
|
+
if not self._check_options():
|
|
77
|
+
return -1
|
|
78
|
+
|
|
79
|
+
self._ask_options()
|
|
80
|
+
|
|
81
|
+
self._render()
|
|
82
|
+
|
|
83
|
+
return 0
|
|
84
|
+
|
|
85
|
+
def _check_options(self):
|
|
86
|
+
for item in _OPTIONS:
|
|
87
|
+
val = getattr(self, item[1])
|
|
88
|
+
if not val:
|
|
89
|
+
continue
|
|
90
|
+
|
|
91
|
+
if val.lower() not in item[3]:
|
|
92
|
+
log.error(f"无效的{item[2]}: {val}")
|
|
93
|
+
return False
|
|
94
|
+
|
|
95
|
+
setattr(self, item[1], val.lower())
|
|
96
|
+
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
def _ask_options(self):
|
|
100
|
+
for item in _OPTIONS:
|
|
101
|
+
if not getattr(self, item[1]):
|
|
102
|
+
self._ask_option(item)
|
|
103
|
+
|
|
104
|
+
def _ask_option(self, item):
|
|
105
|
+
option_str = ''
|
|
106
|
+
index = 0
|
|
107
|
+
while index < len(item[3]):
|
|
108
|
+
if index != 0:
|
|
109
|
+
option_str += ', '
|
|
110
|
+
option_str += str(index + 1) + ": " + item[3][index]
|
|
111
|
+
index += 1
|
|
112
|
+
|
|
113
|
+
log.info(f"请指定{item[2]}后回车({option_str}), 不指定则使用默认值{item[4]}")
|
|
114
|
+
while True:
|
|
115
|
+
select_in, _, _ = select.select([sys.stdin], [], [], 10)
|
|
116
|
+
c_item = sys.stdin.readline().strip().lower()
|
|
117
|
+
if c_item == _DEFAULT:
|
|
118
|
+
c_item = item[4]
|
|
119
|
+
elif c_item.isdigit() and (int(c_item) >= 1 and int(c_item) <= len(item[3])):
|
|
120
|
+
c_item = item[3][int(c_item) - 1]
|
|
121
|
+
if select_in is None or c_item not in item[3]:
|
|
122
|
+
log.error(f"不支持的{item[2]}选项, 请重新输入")
|
|
123
|
+
continue
|
|
124
|
+
|
|
125
|
+
setattr(self, item[1], c_item)
|
|
126
|
+
break
|
|
127
|
+
|
|
128
|
+
def _render(self):
|
|
129
|
+
log.info(f"请稍等, 组件生成中...")
|
|
130
|
+
template = _TEMPLATES[self.language][self.type]
|
|
131
|
+
gen_tool_dir = os.path.join(self.name, template[1])
|
|
132
|
+
shutil.rmtree(gen_tool_dir, ignore_errors=True)
|
|
133
|
+
shutil.copytree(f"{os.path.dirname(__file__)}/../{template[0]}", gen_tool_dir)
|
|
134
|
+
|
|
135
|
+
script_file = os.path.join(gen_tool_dir, template[2])
|
|
136
|
+
template_dir = os.path.join(gen_tool_dir, template[3])
|
|
137
|
+
|
|
138
|
+
for root, _, files in os.walk(template_dir):
|
|
139
|
+
rel_dir = os.path.relpath(root, template_dir)
|
|
140
|
+
out_dir = os.path.join(cwd, self.name, rel_dir)
|
|
141
|
+
os.makedirs(out_dir, exist_ok=True)
|
|
142
|
+
for file in files:
|
|
143
|
+
template_path = os.path.join(root, file)
|
|
144
|
+
out_file = file.replace("${project_name}", self.name)
|
|
145
|
+
out_file = out_file[:(len(out_file)-5)]
|
|
146
|
+
if file.endswith('.link'):
|
|
147
|
+
self._link(out_dir, template_path, out_file)
|
|
148
|
+
continue
|
|
149
|
+
|
|
150
|
+
out_path = os.path.join(out_dir, out_file)
|
|
151
|
+
cmd = [
|
|
152
|
+
"python3", script_file, "-n", self.name, "-t", template_path, "-o", out_path
|
|
153
|
+
]
|
|
154
|
+
subprocess.run(cmd, env=dict(os.environ), check=True)
|
|
155
|
+
cmd = ["chmod", '644', out_path]
|
|
156
|
+
subprocess.run(cmd, env=dict(os.environ), check=True)
|
|
157
|
+
log.success(f"组件已生成到{self.path}目录")
|
|
158
|
+
|
|
159
|
+
def _link(self, out_dir, path, file_name):
|
|
160
|
+
with open(path, "r") as fp:
|
|
161
|
+
src_file = fp.read()
|
|
162
|
+
src_file = src_file.replace("${project_name}", self.name)
|
|
163
|
+
os.chdir(out_dir)
|
|
164
|
+
cmd = ["ln", "-s", src_file, file_name]
|
|
165
|
+
subprocess.run(cmd, env=dict(os.environ), check=True)
|
|
166
|
+
os.chdir(cwd)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# 描述:检查当前目录下, .yml/.yaml 文件是否符合配置的 schema 规范
|
|
4
|
+
# Copyright (c) 2024 Huawei Technologies Co., Ltd.
|
|
5
|
+
# openUBMC is licensed under Mulan PSL v2.
|
|
6
|
+
# You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
7
|
+
# You may obtain a copy of Mulan PSL v2 at:
|
|
8
|
+
# http://license.coscl.org.cn/MulanPSL2
|
|
9
|
+
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
10
|
+
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
11
|
+
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
12
|
+
# See the Mulan PSL v2 for more details.
|
|
13
|
+
import os
|
|
14
|
+
import json
|
|
15
|
+
import argparse
|
|
16
|
+
|
|
17
|
+
import yaml
|
|
18
|
+
import jsonschema
|
|
19
|
+
from jsonschema import exceptions as jc
|
|
20
|
+
|
|
21
|
+
from bmcgo.logger import Logger
|
|
22
|
+
from bmcgo.bmcgo_config import BmcgoConfig
|
|
23
|
+
from bmcgo import misc
|
|
24
|
+
|
|
25
|
+
log = Logger()
|
|
26
|
+
command_info: misc.CommandInfo = misc.CommandInfo(
|
|
27
|
+
group=misc.GRP_MISC,
|
|
28
|
+
name="validate_yml",
|
|
29
|
+
description=["对指定目录下所有yaml文件或指定yaml文件进行 schema 规范检查"],
|
|
30
|
+
hidden=True
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def if_available(_: BmcgoConfig):
|
|
35
|
+
return True
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class BmcgoCommand:
|
|
39
|
+
def __init__(self, bconfig: BmcgoConfig, *args):
|
|
40
|
+
""" yaml 文件根据 schema 文件进行规则检查
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
bconfig (BmcgoConfig): bmcgo 配置
|
|
44
|
+
"""
|
|
45
|
+
self.bconfig = bconfig
|
|
46
|
+
parser = argparse.ArgumentParser(prog="bingo validate_yml", description="Validate yaml files", add_help=True,
|
|
47
|
+
formatter_class=argparse.RawTextHelpFormatter)
|
|
48
|
+
parser.add_argument("-t", "--target", help="目标文件夹或单个yaml文件,默认当前目录", default=".")
|
|
49
|
+
|
|
50
|
+
parsed_args = parser.parse_args(*args)
|
|
51
|
+
self.target = os.path.realpath(parsed_args.target)
|
|
52
|
+
|
|
53
|
+
@staticmethod
|
|
54
|
+
def schema_valid(check_file: str) -> bool:
|
|
55
|
+
""" 有效性校验
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
check_file (str): 要校验的文件名称
|
|
59
|
+
"""
|
|
60
|
+
schema_file = misc.get_decleared_schema_file(check_file)
|
|
61
|
+
if schema_file == "":
|
|
62
|
+
log.warning(f"文件 {check_file} 没有配置 schema 检查")
|
|
63
|
+
return True
|
|
64
|
+
with open(schema_file, "rb") as fp:
|
|
65
|
+
schema = json.load(fp)
|
|
66
|
+
with open(check_file, "r") as fp:
|
|
67
|
+
check_data = yaml.safe_load(fp)
|
|
68
|
+
log.info("开始校验文件: %s", check_file)
|
|
69
|
+
try:
|
|
70
|
+
jsonschema.validate(check_data, schema)
|
|
71
|
+
log.success("校验成功: %s", check_file)
|
|
72
|
+
return True
|
|
73
|
+
except (jc.ValidationError, jc.SchemaError) as e:
|
|
74
|
+
log.error(f" >>>>>> {check_file} 校验失败 <<<<<<\n{e}")
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def _is_yml_file(filename):
|
|
79
|
+
if filename.endswith((".yml", ".yaml")):
|
|
80
|
+
return True
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
def run(self):
|
|
84
|
+
""" 分析参数并启动校验
|
|
85
|
+
"""
|
|
86
|
+
check_result = []
|
|
87
|
+
|
|
88
|
+
if os.path.isfile(self.target):
|
|
89
|
+
check_result.append(self.schema_valid(self.target))
|
|
90
|
+
return 0
|
|
91
|
+
|
|
92
|
+
check_result = self._validate_yml_files()
|
|
93
|
+
|
|
94
|
+
if check_result and False in check_result:
|
|
95
|
+
log.error("请仔细阅读报错日志, 日志中会提示哪些是必要属性, 或哪个属性配置错误")
|
|
96
|
+
raise AttributeError(f"所有 .yml/.yaml 文件检查失败, 请仔细检查报错并解决问题项")
|
|
97
|
+
if not check_result:
|
|
98
|
+
log.warning("未找到yml文件")
|
|
99
|
+
return 0
|
|
100
|
+
|
|
101
|
+
def _validate_yml_files(self):
|
|
102
|
+
check_result = []
|
|
103
|
+
for root, _, files in os.walk(self.target):
|
|
104
|
+
for filename in files:
|
|
105
|
+
if not self._is_yml_file(filename):
|
|
106
|
+
continue
|
|
107
|
+
schema_file = os.path.join(root, filename)
|
|
108
|
+
check_result.append(self.schema_valid(schema_file))
|
|
109
|
+
return check_result
|
|
110
|
+
|
|
111
|
+
|