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
bmcgo/utils/tools.py
ADDED
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding: utf-8
|
|
3
|
+
# Copyright (c) 2024 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
|
+
|
|
13
|
+
import os
|
|
14
|
+
import argparse
|
|
15
|
+
import json
|
|
16
|
+
import time
|
|
17
|
+
import re
|
|
18
|
+
import subprocess
|
|
19
|
+
import shutil
|
|
20
|
+
import tarfile
|
|
21
|
+
import hashlib
|
|
22
|
+
import shlex
|
|
23
|
+
import fcntl
|
|
24
|
+
import stat
|
|
25
|
+
import functools
|
|
26
|
+
import inspect
|
|
27
|
+
import configparser
|
|
28
|
+
from typing import Callable
|
|
29
|
+
from tempfile import TemporaryFile
|
|
30
|
+
from string import Template
|
|
31
|
+
from subprocess import Popen, PIPE
|
|
32
|
+
from collections import OrderedDict
|
|
33
|
+
|
|
34
|
+
import jsonschema
|
|
35
|
+
import yaml
|
|
36
|
+
from conans.model.profile import Profile
|
|
37
|
+
from conans.client.profile_loader import read_profile
|
|
38
|
+
|
|
39
|
+
from bmcgo.logger import Logger
|
|
40
|
+
from bmcgo.errors import BmcGoException, EnvironmentException
|
|
41
|
+
from bmcgo import misc
|
|
42
|
+
from bmcgo import errors
|
|
43
|
+
from bmcgo.logger import Logger
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Tools():
|
|
47
|
+
"""
|
|
48
|
+
功能描述:公共类定义全局变量,公共函数
|
|
49
|
+
接口:无
|
|
50
|
+
"""
|
|
51
|
+
print_cnt = 0
|
|
52
|
+
|
|
53
|
+
def __init__(self, log_name="bingo", log_file=None):
|
|
54
|
+
os.makedirs(misc.CACHE_DIR, exist_ok=True)
|
|
55
|
+
self.lock_file = os.path.join(misc.CACHE_DIR, "frame_lock")
|
|
56
|
+
if log_file is None:
|
|
57
|
+
self.log_name = os.path.join(misc.CACHE_DIR, f"{log_name}.log")
|
|
58
|
+
else:
|
|
59
|
+
self.log_name = log_file
|
|
60
|
+
self.log = Logger(log_name, log_file=self.log_name)
|
|
61
|
+
file_handle = os.fdopen(os.open(self.lock_file, os.O_WRONLY | os.O_CREAT,
|
|
62
|
+
stat.S_IWUSR | stat.S_IRUSR), 'a')
|
|
63
|
+
file_handle.close()
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def user_home(self):
|
|
67
|
+
return os.environ["HOME"]
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def conan_home(self):
|
|
71
|
+
return os.path.expanduser("~/.conan")
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def conan_profiles_dir(self):
|
|
75
|
+
return os.path.join(self.conan_home, "profiles")
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def conan_profiles(self):
|
|
79
|
+
profiles = []
|
|
80
|
+
for profile in os.listdir(self.conan_profiles_dir):
|
|
81
|
+
if os.path.isfile(os.path.join(self.conan_profiles_dir, profile)):
|
|
82
|
+
profiles.append(profile)
|
|
83
|
+
return profiles
|
|
84
|
+
|
|
85
|
+
@property
|
|
86
|
+
def conan_data(self):
|
|
87
|
+
return os.path.join(self.conan_home, "data")
|
|
88
|
+
|
|
89
|
+
@staticmethod
|
|
90
|
+
def format_command(command, sudo=False):
|
|
91
|
+
cmd_args: list[str] = []
|
|
92
|
+
if isinstance(command, list):
|
|
93
|
+
cmd_args = command
|
|
94
|
+
elif isinstance(command, str):
|
|
95
|
+
cmd_args = shlex.split(command)
|
|
96
|
+
cmd = shutil.which(cmd_args[0])
|
|
97
|
+
if cmd is None:
|
|
98
|
+
raise EnvironmentException(f"{cmd_args[0]}不存在, 请检查命令或环境配置")
|
|
99
|
+
cmd_args[0] = cmd
|
|
100
|
+
else:
|
|
101
|
+
raise BmcGoException(f"不支持的命令参数格式: {command}, 请检查命令格式")
|
|
102
|
+
sudo_cmd = shutil.which("sudo")
|
|
103
|
+
if sudo and sudo_cmd and cmd_args[0] != sudo_cmd:
|
|
104
|
+
cmd_args.insert(0, sudo_cmd)
|
|
105
|
+
return cmd_args
|
|
106
|
+
|
|
107
|
+
@staticmethod
|
|
108
|
+
def check_path(path):
|
|
109
|
+
"""
|
|
110
|
+
功能描述:检查目录是否存在,没有就创建
|
|
111
|
+
参数:path 要检查的目录
|
|
112
|
+
返回值:无
|
|
113
|
+
"""
|
|
114
|
+
if not os.path.exists(path) and not os.path.islink(path):
|
|
115
|
+
os.makedirs(path, exist_ok=True)
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def copy(source, target):
|
|
119
|
+
"""
|
|
120
|
+
功能描述:拷贝文件优化,如果存在目标文件先删除后拷贝
|
|
121
|
+
参数:source 源文件 target 目标文件
|
|
122
|
+
返回值:无
|
|
123
|
+
"""
|
|
124
|
+
if os.path.exists(source):
|
|
125
|
+
if os.path.exists(target):
|
|
126
|
+
os.unlink(target)
|
|
127
|
+
shutil.copy(source, target)
|
|
128
|
+
|
|
129
|
+
@staticmethod
|
|
130
|
+
def sha256sum(file_path: str):
|
|
131
|
+
# 为提高性能, 每次读取64KB数据
|
|
132
|
+
data_block_size = 1024 * 64
|
|
133
|
+
sha256hasher = hashlib.sha256()
|
|
134
|
+
with open(file_path, 'rb') as fp:
|
|
135
|
+
while True:
|
|
136
|
+
data = fp.read(data_block_size)
|
|
137
|
+
if not data:
|
|
138
|
+
break
|
|
139
|
+
sha256hasher.update(data)
|
|
140
|
+
sha256 = sha256hasher.hexdigest()
|
|
141
|
+
return sha256
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def find_key_in_dict(f_dict: dict, key: str):
|
|
145
|
+
results = []
|
|
146
|
+
for k, v in f_dict.items():
|
|
147
|
+
if k == key:
|
|
148
|
+
results.append(v)
|
|
149
|
+
elif isinstance(v, dict):
|
|
150
|
+
results.extend(Tools.find_key_in_dict(v, k))
|
|
151
|
+
return results
|
|
152
|
+
|
|
153
|
+
@staticmethod
|
|
154
|
+
def remove_path(path):
|
|
155
|
+
"""
|
|
156
|
+
功能描述:删除指定的目录
|
|
157
|
+
参数:path 要删除的目录
|
|
158
|
+
返回值:无
|
|
159
|
+
"""
|
|
160
|
+
if os.path.isdir(path):
|
|
161
|
+
shutil.rmtree(path, ignore_errors=True)
|
|
162
|
+
|
|
163
|
+
@staticmethod
|
|
164
|
+
def has_kwargs(func: Callable):
|
|
165
|
+
"""
|
|
166
|
+
功能描述: 检查function是否有可变的关键字参数**kwargs
|
|
167
|
+
参数: 需要检查的function
|
|
168
|
+
返回值: bool
|
|
169
|
+
"""
|
|
170
|
+
signature = inspect.signature(func)
|
|
171
|
+
parameters = signature.parameters
|
|
172
|
+
for param in parameters.values():
|
|
173
|
+
if param.kind == param.VAR_KEYWORD:
|
|
174
|
+
return True
|
|
175
|
+
return False
|
|
176
|
+
|
|
177
|
+
@staticmethod
|
|
178
|
+
def get_profile_arg_help():
|
|
179
|
+
tools = Tools()
|
|
180
|
+
profile_help_text = "显式指定conan构建使用的profile文件 (~/.conan/profiles目录下)别名, 默认为: 空\n可选值: "
|
|
181
|
+
profile_help_text += ", ".join(tools.conan_profiles)
|
|
182
|
+
return profile_help_text
|
|
183
|
+
|
|
184
|
+
@staticmethod
|
|
185
|
+
def get_conan_profile(profile: str, build_type: str, enable_luajit=False):
|
|
186
|
+
"""
|
|
187
|
+
根据参数与配置获取conan构建使用的profile文件名。
|
|
188
|
+
"""
|
|
189
|
+
if profile:
|
|
190
|
+
return str(profile)
|
|
191
|
+
|
|
192
|
+
if build_type == "dt":
|
|
193
|
+
return "profile.dt.ini"
|
|
194
|
+
|
|
195
|
+
return "profile.luajit.ini"
|
|
196
|
+
|
|
197
|
+
@staticmethod
|
|
198
|
+
def check_product_dependencies(top, base):
|
|
199
|
+
for key, value in top.items():
|
|
200
|
+
if (
|
|
201
|
+
key == "dependencies"
|
|
202
|
+
or key == "dt_dependencies"
|
|
203
|
+
or key == "debug_dependencies"
|
|
204
|
+
):
|
|
205
|
+
for com_package in value:
|
|
206
|
+
Tools().check_base_dependencies(base, com_package, key)
|
|
207
|
+
|
|
208
|
+
@staticmethod
|
|
209
|
+
def check_base_dependencies(base_manifest, com_package, dependency_type):
|
|
210
|
+
name = com_package.get(misc.CONAN)
|
|
211
|
+
action = com_package.get("action", "")
|
|
212
|
+
pkg_info = name.split("/")
|
|
213
|
+
pkg_name = pkg_info[0]
|
|
214
|
+
has_version = len(pkg_info) > 1
|
|
215
|
+
for sub in base_manifest.get(dependency_type, {}):
|
|
216
|
+
sub_name = sub.get(misc.CONAN)
|
|
217
|
+
sub_pkg_name = sub_name.split("/")[0]
|
|
218
|
+
# 上下层具有相同组件名的组件
|
|
219
|
+
if pkg_name == sub_pkg_name:
|
|
220
|
+
if has_version or action:
|
|
221
|
+
raise errors.BmcGoException(
|
|
222
|
+
"配置错误: 不允许删除平台组件或定制平台组件版本号{}".format(name)
|
|
223
|
+
)
|
|
224
|
+
else:
|
|
225
|
+
com_package[misc.CONAN] = sub_name
|
|
226
|
+
break
|
|
227
|
+
|
|
228
|
+
@staticmethod
|
|
229
|
+
def merge_dependencies(top, base):
|
|
230
|
+
ret = []
|
|
231
|
+
for conan in top:
|
|
232
|
+
name = conan.get(misc.CONAN)
|
|
233
|
+
pkg_name = name.split("/")[0]
|
|
234
|
+
found = False
|
|
235
|
+
for sub in base:
|
|
236
|
+
sub_name = sub.get(misc.CONAN)
|
|
237
|
+
sub_pkg_name = sub_name.split("/")[0]
|
|
238
|
+
# 上下层具有相同组件名的组件
|
|
239
|
+
if pkg_name == sub_pkg_name:
|
|
240
|
+
found = True
|
|
241
|
+
break
|
|
242
|
+
# 上下层具有相同组件名的组件
|
|
243
|
+
if found:
|
|
244
|
+
action = conan.get("action")
|
|
245
|
+
if action and action == "delete":
|
|
246
|
+
# 但如果上层配置了delete的
|
|
247
|
+
continue
|
|
248
|
+
else:
|
|
249
|
+
ret.append(conan)
|
|
250
|
+
else:
|
|
251
|
+
# 未找到下层组件时
|
|
252
|
+
ret.append(conan)
|
|
253
|
+
for sub in base:
|
|
254
|
+
sub_name = sub.get(misc.CONAN)
|
|
255
|
+
sub_pkg_name = sub_name.split("/")[0]
|
|
256
|
+
found = False
|
|
257
|
+
for conan in top:
|
|
258
|
+
name = conan.get(misc.CONAN)
|
|
259
|
+
pkg_name = name.split("/")[0]
|
|
260
|
+
# 上下层具有相同组件名的组件
|
|
261
|
+
if pkg_name == sub_pkg_name:
|
|
262
|
+
found = True
|
|
263
|
+
break
|
|
264
|
+
# 当下层组件未在上层配置时,使用下层组件
|
|
265
|
+
if not found:
|
|
266
|
+
ret.append(sub)
|
|
267
|
+
return ret
|
|
268
|
+
|
|
269
|
+
@staticmethod
|
|
270
|
+
def fix_platform(package, stage):
|
|
271
|
+
version_split = re.split(r"[/, @]", package[misc.CONAN])
|
|
272
|
+
if stage == misc.StageEnum.STAGE_DEV.value:
|
|
273
|
+
# 开发者测试模式
|
|
274
|
+
stage = misc.StageEnum.STAGE_RC.value
|
|
275
|
+
# else: rc和stable模式
|
|
276
|
+
channel = f"@{Tools().conan_user}/{stage}"
|
|
277
|
+
|
|
278
|
+
if len(version_split) == 2:
|
|
279
|
+
package[misc.CONAN] += channel
|
|
280
|
+
|
|
281
|
+
@staticmethod
|
|
282
|
+
def install_platform(platform_package, stage, remote):
|
|
283
|
+
Tools().fix_platform(platform_package, stage)
|
|
284
|
+
rtos_version = platform_package.get("options", {}).get(
|
|
285
|
+
"rtos_version", "rtos_v2"
|
|
286
|
+
)
|
|
287
|
+
append_cmd = f"-r {remote}" if remote else ""
|
|
288
|
+
Tools().run_command(
|
|
289
|
+
f"conan install {platform_package[misc.CONAN]} {append_cmd} -o rtos_version={rtos_version}"
|
|
290
|
+
)
|
|
291
|
+
version_split = re.split(r"[/, @]", platform_package[misc.CONAN])
|
|
292
|
+
package_conan_dir = os.path.join(
|
|
293
|
+
os.path.expanduser("~"), ".conan/data/", *version_split
|
|
294
|
+
)
|
|
295
|
+
cmd = f"conan info {platform_package[misc.CONAN]} {append_cmd} -o rtos_version={rtos_version} -j"
|
|
296
|
+
cmd_info = Tools().run_command(
|
|
297
|
+
cmd,
|
|
298
|
+
capture_output=True,
|
|
299
|
+
)
|
|
300
|
+
info = json.loads(cmd_info.stdout)
|
|
301
|
+
for i in info:
|
|
302
|
+
package_conan_dir = os.path.join(
|
|
303
|
+
package_conan_dir, "package", i["id"], rtos_version
|
|
304
|
+
)
|
|
305
|
+
return package_conan_dir
|
|
306
|
+
|
|
307
|
+
@staticmethod
|
|
308
|
+
def get_manifest_dependencies(manifest_build_dir, file_path, stage, remote):
|
|
309
|
+
with open(file_path, "r") as f_:
|
|
310
|
+
base_manifest = yaml.safe_load(f_)
|
|
311
|
+
top_dependencies = base_manifest[misc.CONAN_DEPDENCIES_KEY]
|
|
312
|
+
platform_package = base_manifest.get("platform", {})
|
|
313
|
+
if platform_package:
|
|
314
|
+
package_conan_dir = Tools.install_platform(platform_package, stage, remote)
|
|
315
|
+
top_dependencies.append(platform_package)
|
|
316
|
+
platform_src = os.path.join(package_conan_dir, "manifest.yml")
|
|
317
|
+
with open(platform_src, "r") as f_:
|
|
318
|
+
platform_manifest = yaml.safe_load(f_)
|
|
319
|
+
Tools.check_product_dependencies(base_manifest, platform_manifest)
|
|
320
|
+
top_dependencies = Tools.merge_dependencies(
|
|
321
|
+
top_dependencies, platform_manifest[misc.CONAN_DEPDENCIES_KEY]
|
|
322
|
+
)
|
|
323
|
+
inc_filename = base_manifest.get("include")
|
|
324
|
+
if not inc_filename:
|
|
325
|
+
return top_dependencies
|
|
326
|
+
file_path = inc_filename.replace(
|
|
327
|
+
"${product}", os.path.join(manifest_build_dir, "product")
|
|
328
|
+
)
|
|
329
|
+
base_dependencies = Tools.get_manifest_dependencies(manifest_build_dir, file_path, stage, remote)
|
|
330
|
+
dep = Tools.merge_dependencies(top_dependencies, base_dependencies)
|
|
331
|
+
return dep
|
|
332
|
+
|
|
333
|
+
@staticmethod
|
|
334
|
+
def create_common_parser(description):
|
|
335
|
+
parser = argparse.ArgumentParser(description=description)
|
|
336
|
+
parser.add_argument("-cp", "--conan_package", help="软件包名, 示例: kmc/24.0.0.B020", default="")
|
|
337
|
+
parser.add_argument("-uci", "--upload_package", help="是否上传软件包", action=misc.STORE_TRUE)
|
|
338
|
+
parser.add_argument("-o", "--options", help="组件特性配置, 示例: -o skynet:enable_luajit=True",
|
|
339
|
+
action='append')
|
|
340
|
+
parser.add_argument("-r", "--remote", help="指定conan远端")
|
|
341
|
+
parser.add_argument("-bt", "--build_type", help="构建类型,可选:debug(调试包), release(正式包), dt(开发者测试包)",
|
|
342
|
+
default="debug")
|
|
343
|
+
parser.add_argument("--stage", help="包类型,可选值为: dev(调试包), rc(预发布包), stable(发布包)\n默认:dev",
|
|
344
|
+
default="dev")
|
|
345
|
+
parser.add_argument("-jit", "--enable_luajit", help="Enable luajit", action=misc.STORE_TRUE)
|
|
346
|
+
parser.add_argument("-s", "--from_source", help="使能源码构建", action=misc.STORE_TRUE)
|
|
347
|
+
parser.add_argument("-as", "--asan", help="Enable address sanitizer", action=misc.STORE_TRUE)
|
|
348
|
+
parser.add_argument(
|
|
349
|
+
"-pr",
|
|
350
|
+
"--profile",
|
|
351
|
+
help=Tools.get_profile_arg_help(),
|
|
352
|
+
default="",
|
|
353
|
+
)
|
|
354
|
+
return parser
|
|
355
|
+
|
|
356
|
+
@staticmethod
|
|
357
|
+
def get_module_symver_option(module_symver_path: str):
|
|
358
|
+
sha256 = Tools.sha256sum(module_symver_path)
|
|
359
|
+
return ("module_symver", sha256)
|
|
360
|
+
|
|
361
|
+
@staticmethod
|
|
362
|
+
def clean_conan_bin(conan_bin):
|
|
363
|
+
if os.path.isdir(conan_bin):
|
|
364
|
+
for file in os.listdir(conan_bin):
|
|
365
|
+
file_path = os.path.join(conan_bin, file)
|
|
366
|
+
if os.path.isfile(file_path):
|
|
367
|
+
os.remove(file_path)
|
|
368
|
+
else:
|
|
369
|
+
os.makedirs(conan_bin)
|
|
370
|
+
|
|
371
|
+
@functools.cached_property
|
|
372
|
+
def is_ubuntu(self):
|
|
373
|
+
"""
|
|
374
|
+
功能描述: 判断当前环境是否为Ubuntu
|
|
375
|
+
返回值: bool
|
|
376
|
+
"""
|
|
377
|
+
if os.path.isfile("/etc/issue"):
|
|
378
|
+
fp = open("/etc/issue", "r")
|
|
379
|
+
issue = fp.read()
|
|
380
|
+
fp.close()
|
|
381
|
+
if issue.startswith("Ubuntu"):
|
|
382
|
+
return True
|
|
383
|
+
return False
|
|
384
|
+
|
|
385
|
+
@functools.cached_property
|
|
386
|
+
def conan_user(self):
|
|
387
|
+
if os.access(misc.GLOBAL_CFG_FILE, os.R_OK):
|
|
388
|
+
try:
|
|
389
|
+
conf = configparser.ConfigParser()
|
|
390
|
+
conf.read(misc.GLOBAL_CFG_FILE)
|
|
391
|
+
return conf.get(misc.CONAN, "user")
|
|
392
|
+
except (configparser.NoSectionError, configparser.NoOptionError):
|
|
393
|
+
pass
|
|
394
|
+
|
|
395
|
+
return misc.ConanUserEnum.CONAN_USER_RELEASE.value
|
|
396
|
+
|
|
397
|
+
def get_conan_remote_list(self, remote):
|
|
398
|
+
conan_remote_list = []
|
|
399
|
+
if remote:
|
|
400
|
+
conan_remote_list.append(remote)
|
|
401
|
+
else:
|
|
402
|
+
remote_list = self.run_command("conan remote list", capture_output=True).stdout.split("\n")
|
|
403
|
+
conan_remote_list = [remote.split(":")[0] for remote in remote_list if remote]
|
|
404
|
+
return conan_remote_list
|
|
405
|
+
|
|
406
|
+
def download_conan_recipes(self, conan_version, conan_remote_list):
|
|
407
|
+
download_flag = False
|
|
408
|
+
for remote in conan_remote_list:
|
|
409
|
+
try:
|
|
410
|
+
self.run_command(f"conan download {conan_version} -r {remote} -re", show_error_log=False)
|
|
411
|
+
download_flag = True
|
|
412
|
+
break
|
|
413
|
+
except Exception as e:
|
|
414
|
+
self.log.info(f"Recipe not fount in {remote}: {conan_version}")
|
|
415
|
+
if not download_flag:
|
|
416
|
+
raise BmcGoException(f"Download {conan_version} failed")
|
|
417
|
+
|
|
418
|
+
def yaml_load_template(self, yaml_name: str, template: dict, need_validate=True):
|
|
419
|
+
with open(yaml_name, "r", encoding="utf-8") as fp:
|
|
420
|
+
yaml_string = fp.read()
|
|
421
|
+
yaml_string = Template(yaml_string)
|
|
422
|
+
yaml_conf = yaml_string.safe_substitute(template)
|
|
423
|
+
yaml_obj = yaml.full_load(yaml_conf)
|
|
424
|
+
if need_validate:
|
|
425
|
+
schema_file = misc.get_decleared_schema_file(yaml_name)
|
|
426
|
+
if schema_file == "":
|
|
427
|
+
return yaml_obj
|
|
428
|
+
with open(schema_file, "rb") as fp:
|
|
429
|
+
schema = json.load(fp)
|
|
430
|
+
self.log.debug("开始校验 %s", yaml_name)
|
|
431
|
+
try:
|
|
432
|
+
jsonschema.validate(yaml_obj, schema)
|
|
433
|
+
except jsonschema.exceptions.ValidationError as e:
|
|
434
|
+
raise OSError('文件 {} 无法通过schema文件 {} 的校验\n {}'.format(yaml_name, schema_file, str(e))) from e
|
|
435
|
+
return yaml_obj
|
|
436
|
+
|
|
437
|
+
def get_file_permission(self, path):
|
|
438
|
+
with Popen(self.format_command(f"stat -c '%a' {path}", sudo=True), stdout=PIPE) as proc:
|
|
439
|
+
data, _ = proc.communicate(timeout=50)
|
|
440
|
+
return data.decode('utf-8')
|
|
441
|
+
|
|
442
|
+
def copy_all(self, source_path, target_path):
|
|
443
|
+
"""
|
|
444
|
+
功能描述:将 source_path 目录下所有文件全部复制到 target_path 下
|
|
445
|
+
如果要复制 source_path 文件夹,需指定 target_path 下同名文件夹
|
|
446
|
+
参数:source_path 源目录 target_path 目标目录
|
|
447
|
+
返回值:无
|
|
448
|
+
"""
|
|
449
|
+
if not os.path.exists(source_path):
|
|
450
|
+
raise OSError(f"源目录 ({source_path}) 不存在, 请检查源文件")
|
|
451
|
+
for root, dirs, files in os.walk(source_path, topdown=True):
|
|
452
|
+
for dirname in dirs:
|
|
453
|
+
dest_dir_t = f"{target_path}/{root[len(source_path) + 1:]}/{dirname}"
|
|
454
|
+
self.check_path(dest_dir_t)
|
|
455
|
+
for file in files:
|
|
456
|
+
src_file = os.path.join(root, file)
|
|
457
|
+
dest_dir = os.path.join(target_path, root[len(source_path) + 1:])
|
|
458
|
+
self.check_path(dest_dir)
|
|
459
|
+
dest_file = os.path.join(dest_dir, os.path.basename(src_file))
|
|
460
|
+
if os.path.isfile(dest_file):
|
|
461
|
+
os.unlink(dest_file)
|
|
462
|
+
if os.path.islink(src_file):
|
|
463
|
+
shutil.copy2(src_file, dest_dir, follow_symlinks=False)
|
|
464
|
+
else:
|
|
465
|
+
shutil.copy2(src_file, dest_dir)
|
|
466
|
+
|
|
467
|
+
def untar_to_dir(self, targz_source, dst_dir="."):
|
|
468
|
+
"""
|
|
469
|
+
功能描述:解压tar包到指定目录
|
|
470
|
+
参数:targz_source tar包 ,dst_dir 目标目录
|
|
471
|
+
返回值:无
|
|
472
|
+
"""
|
|
473
|
+
self.log.info("解压 - 源文件: {}, 目标文件: {}".format(targz_source, dst_dir))
|
|
474
|
+
tar_temp = tarfile.open(targz_source)
|
|
475
|
+
tar_temp.extractall(dst_dir)
|
|
476
|
+
tar_temp.close()
|
|
477
|
+
|
|
478
|
+
def list_all_file(self, regular_exp, dir_path, recursive=False):
|
|
479
|
+
"""
|
|
480
|
+
功能描述:在 dir_path 列表中,找出符合正则表达式的值路径,并返回列表
|
|
481
|
+
参数: regular_exp: 正则表达式
|
|
482
|
+
dir_path: 需要查找的路径
|
|
483
|
+
recursive: 是否递归查询(查询所有子文件夹)
|
|
484
|
+
返回值:无
|
|
485
|
+
"""
|
|
486
|
+
dir_match_list = []
|
|
487
|
+
dir_list = os.listdir(dir_path)
|
|
488
|
+
for element in dir_list:
|
|
489
|
+
if recursive and os.path.isdir(f"{dir_path}/{element}"):
|
|
490
|
+
dir_match_list.append(f"{dir_path}/{element}")
|
|
491
|
+
dir_match_list += self.list_all_file(regular_exp, f"{dir_path}/{element}", recursive)
|
|
492
|
+
else:
|
|
493
|
+
ret = re.fullmatch(regular_exp, element)
|
|
494
|
+
if ret is not None:
|
|
495
|
+
dir_match_list.append(f"{dir_path}/{element}")
|
|
496
|
+
return dir_match_list
|
|
497
|
+
|
|
498
|
+
def py_sed(self, src_file, regular_exp, instead_text, def_line="l"):
|
|
499
|
+
self.log.info(f"要被替换文件: {src_file} -- 匹配正则表达式为: {regular_exp}")
|
|
500
|
+
shutil.copy(src_file, f"{src_file}_bak")
|
|
501
|
+
with open(src_file, "r", encoding="utf-8") as fp_r:
|
|
502
|
+
lines = fp_r.readlines()
|
|
503
|
+
fp_w = os.fdopen(os.open(src_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
504
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w')
|
|
505
|
+
line_num = 0
|
|
506
|
+
if def_line == "l":
|
|
507
|
+
for line in lines:
|
|
508
|
+
ret = re.search(regular_exp, line)
|
|
509
|
+
if ret is None:
|
|
510
|
+
fp_w.write(line)
|
|
511
|
+
line_num = line_num + 1
|
|
512
|
+
else:
|
|
513
|
+
self.log.info(f"字符串: {ret.group(0)}")
|
|
514
|
+
line = line.replace(ret.group(0), instead_text)
|
|
515
|
+
fp_w.write(line)
|
|
516
|
+
line_num = line_num + 1
|
|
517
|
+
break
|
|
518
|
+
for i in range(line_num, len(lines)):
|
|
519
|
+
fp_w.write(lines[i])
|
|
520
|
+
elif def_line == "g":
|
|
521
|
+
for line in lines:
|
|
522
|
+
ret = re.search(regular_exp, line)
|
|
523
|
+
if ret is not None:
|
|
524
|
+
line = line.replace(ret.group(0), instead_text)
|
|
525
|
+
fp_w.write(line)
|
|
526
|
+
fp_w.close()
|
|
527
|
+
os.remove(f"{src_file}_bak")
|
|
528
|
+
|
|
529
|
+
def create_image_and_mount_datafs(self, img_path, mnt_datafs):
|
|
530
|
+
"""
|
|
531
|
+
文件格式化为ext4分区,随后挂载到self.mnt_datafs目录
|
|
532
|
+
"""
|
|
533
|
+
self.log.info(f"挂载 datafs, 目录: {mnt_datafs}, 镜像文件: {img_path}")
|
|
534
|
+
os.makedirs(mnt_datafs, exist_ok=True)
|
|
535
|
+
self.run_command(f"umount {mnt_datafs}", ignore_error=True, sudo=True)
|
|
536
|
+
self.run_command(f"/sbin/mkfs.ext4 -O ^64bit,^metadata_csum {img_path}")
|
|
537
|
+
# 直接挂载,挂载成功则直接退出
|
|
538
|
+
ret = self.run_command(f"mount -t ext4 {img_path} {mnt_datafs}", ignore_error=True, sudo=True)
|
|
539
|
+
if ret and ret.returncode == 0:
|
|
540
|
+
return
|
|
541
|
+
# 挂载设备进行16次尝试
|
|
542
|
+
for attempt_times in range(0, 64):
|
|
543
|
+
loop_id = attempt_times % 16
|
|
544
|
+
self.run_command(f"mknod -m 0660 /dev/loop{loop_id} b 7 {loop_id}", ignore_error=True, sudo=True)
|
|
545
|
+
ret = self.run_command(f"mount -o loop=/dev/loop{loop_id} -t ext4 {img_path} {mnt_datafs}",
|
|
546
|
+
ignore_error=True, sudo=True)
|
|
547
|
+
if ret is None or ret.returncode != 0:
|
|
548
|
+
# 创建设备,允许不成功,其他进程可能创建过相同的设备
|
|
549
|
+
self.log.info(f"挂载 {img_path} 失败, 尝试第 {loop_id} 次, 返回值为: {ret}")
|
|
550
|
+
else:
|
|
551
|
+
# 挂载成功退出
|
|
552
|
+
break
|
|
553
|
+
time.sleep(10)
|
|
554
|
+
else:
|
|
555
|
+
# 16次均失败,报错退出
|
|
556
|
+
self.run_command(f"umount {mnt_datafs}", ignore_error=True, sudo=True)
|
|
557
|
+
raise errors.BmcGoException(
|
|
558
|
+
f"挂载 {img_path} 失败, 请使用 df -hl 检查设备是否被占用"
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
def umount_datafs(self, mnt_datafs):
|
|
562
|
+
self.log.info(f"卸载 datafs, 目录: {mnt_datafs}")
|
|
563
|
+
self.run_command(f"umount {mnt_datafs}", ignore_error=True, sudo=True)
|
|
564
|
+
|
|
565
|
+
def get_studio_path(self):
|
|
566
|
+
ret = self.run_command("whereis bmc_studio", sudo=True, ignore_error=True,
|
|
567
|
+
command_echo=False, capture_output=True).stdout
|
|
568
|
+
if not ret:
|
|
569
|
+
return ""
|
|
570
|
+
|
|
571
|
+
ret = ret.replace(" ", "").replace("\n", "")
|
|
572
|
+
studio_split = ret.split(":")
|
|
573
|
+
if len(studio_split) <= 1:
|
|
574
|
+
return ""
|
|
575
|
+
|
|
576
|
+
return studio_split[1]
|
|
577
|
+
|
|
578
|
+
def run_command(self, command, ignore_error=False, sudo=False, **kwargs):
|
|
579
|
+
"""
|
|
580
|
+
如果ignore_error为False,命令返回码非0时则打印堆栈和日志并触发异常,中断构建
|
|
581
|
+
"""
|
|
582
|
+
# 如果run_command在同一行多次调用则无法区分执行的命令,command_key用于在日志中指示当前正在执行的命令关键字
|
|
583
|
+
command_key = kwargs.get("command_key", None)
|
|
584
|
+
command_echo = kwargs.get("command_echo", True)
|
|
585
|
+
show_log = kwargs.get("show_log", False)
|
|
586
|
+
uptrace = kwargs.get("uptrace", 0) + 1
|
|
587
|
+
error_log = kwargs.get("error_log")
|
|
588
|
+
warn_log = kwargs.get("warn_log")
|
|
589
|
+
timeout = kwargs.get("timeout", 1200)
|
|
590
|
+
capture_output = kwargs.get("capture_output", False)
|
|
591
|
+
if command_key:
|
|
592
|
+
key = command_key + ":"
|
|
593
|
+
else:
|
|
594
|
+
key = ""
|
|
595
|
+
if command_echo and not self.log.is_debug:
|
|
596
|
+
self.log.info(f">> {key}{command}", uptrace=uptrace)
|
|
597
|
+
command = self.format_command(command, sudo)
|
|
598
|
+
ret = None
|
|
599
|
+
log_fd = os.fdopen(os.open(self.log_name, os.O_RDWR | os.O_CREAT | os.O_APPEND,
|
|
600
|
+
stat.S_IWUSR | stat.S_IRUSR), 'a+')
|
|
601
|
+
try:
|
|
602
|
+
check = False if ignore_error else True
|
|
603
|
+
if show_log:
|
|
604
|
+
ret = subprocess.run(command, check=check, timeout=timeout)
|
|
605
|
+
elif capture_output:
|
|
606
|
+
ret = subprocess.run(command, capture_output=capture_output, check=check, timeout=timeout, text=True)
|
|
607
|
+
if ret.stdout:
|
|
608
|
+
log_fd.write(ret.stdout)
|
|
609
|
+
if ret.stderr:
|
|
610
|
+
log_fd.write(ret.stderr)
|
|
611
|
+
else:
|
|
612
|
+
ret = subprocess.run(command, stdout=log_fd, stderr=log_fd, check=check, timeout=timeout)
|
|
613
|
+
except Exception as e:
|
|
614
|
+
if error_log:
|
|
615
|
+
self.log.error(error_log, uptrace=uptrace)
|
|
616
|
+
elif warn_log:
|
|
617
|
+
self.log.warning(warn_log, uptrace=uptrace)
|
|
618
|
+
else:
|
|
619
|
+
self.log.error(f"执行命令 {key}{command} 错误, 日志: {self.log_name}", uptrace=uptrace)
|
|
620
|
+
log_fd.flush()
|
|
621
|
+
log_fd.close()
|
|
622
|
+
raise e
|
|
623
|
+
log_fd.close()
|
|
624
|
+
return ret
|
|
625
|
+
|
|
626
|
+
def pipe_command(self, commands, out_file=None, **kwargs):
|
|
627
|
+
if not isinstance(commands, list):
|
|
628
|
+
raise BmcGoException("命令必须为列表")
|
|
629
|
+
# 创建一个空的文件
|
|
630
|
+
flag = "w+b"
|
|
631
|
+
if out_file:
|
|
632
|
+
fp = os.fdopen(os.open(out_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
633
|
+
stat.S_IWUSR | stat.S_IRUSR), flag)
|
|
634
|
+
fp.close()
|
|
635
|
+
stdin = None
|
|
636
|
+
command_echo = kwargs.get("command_echo", True)
|
|
637
|
+
uptrace = kwargs.get("uptrace", 0) + 1
|
|
638
|
+
ignore_error = kwargs.get('ignore_error', False)
|
|
639
|
+
capture_output = kwargs.get('capture_output', False)
|
|
640
|
+
if command_echo and not self.log.is_debug:
|
|
641
|
+
self.log.info(f">> " + ' | '.join(commands), uptrace=uptrace)
|
|
642
|
+
for command in commands:
|
|
643
|
+
stdout = TemporaryFile(flag)
|
|
644
|
+
cmd = self.format_command(command, False)
|
|
645
|
+
ret = subprocess.Popen(cmd, stdout=stdout, stdin=stdin)
|
|
646
|
+
ret.wait()
|
|
647
|
+
if ret.returncode != 0:
|
|
648
|
+
if ignore_error:
|
|
649
|
+
return None, ret.returncode
|
|
650
|
+
raise BmcGoException(f"运行命令 {command} 失败, 请分析执行的命令返回日志")
|
|
651
|
+
if stdin is not None:
|
|
652
|
+
stdin.close()
|
|
653
|
+
stdin = stdout
|
|
654
|
+
stdin.seek(0)
|
|
655
|
+
if stdin:
|
|
656
|
+
context = stdin.read()
|
|
657
|
+
if out_file:
|
|
658
|
+
with os.fdopen(os.open(out_file, os.O_WRONLY | os.O_CREAT,
|
|
659
|
+
stat.S_IWUSR | stat.S_IRUSR), flag) as fp:
|
|
660
|
+
fp.write(context)
|
|
661
|
+
stdin.close()
|
|
662
|
+
if capture_output:
|
|
663
|
+
return context.decode("utf-8"), 0
|
|
664
|
+
return None, ret.returncode
|
|
665
|
+
|
|
666
|
+
def sudo_passwd_check(self):
|
|
667
|
+
self.log.info("测试sudo是否正常执行")
|
|
668
|
+
try:
|
|
669
|
+
self.run_command("ls .", sudo=True)
|
|
670
|
+
except Exception as e:
|
|
671
|
+
self.log.error("sudo命令无法正常执行")
|
|
672
|
+
raise e
|
|
673
|
+
else:
|
|
674
|
+
self.log.info("sudo命令正常执行")
|
|
675
|
+
|
|
676
|
+
def clean_locks(self):
|
|
677
|
+
self.log.info("尝试清理conan组件锁")
|
|
678
|
+
if not os.path.isdir(self.conan_data):
|
|
679
|
+
return
|
|
680
|
+
cmd = [f"find {self.conan_data} -maxdepth 4 -mindepth 4 -type f -name *.count*", "xargs rm -f"]
|
|
681
|
+
_, _ = self.pipe_command(cmd, out_file=None)
|
|
682
|
+
|
|
683
|
+
def get_profile_config(self, profile_name) -> (Profile, OrderedDict):
|
|
684
|
+
"""根据profile文件名获取~/.conan/profiles对应文件的配置内容"""
|
|
685
|
+
if not profile_name:
|
|
686
|
+
return None, None
|
|
687
|
+
profile_file = os.path.join(self.conan_profiles_dir, profile_name)
|
|
688
|
+
if not os.path.isfile(profile_file):
|
|
689
|
+
raise BmcGoException(f"{profile_file} 文件不存在")
|
|
690
|
+
|
|
691
|
+
profile, profile_vars = read_profile(profile_name, os.getcwd(), self.conan_profiles_dir)
|
|
692
|
+
return profile, profile_vars
|
|
693
|
+
|
|
694
|
+
def _save_tempfile_safety(self, temp_fd, target_file, show_log=False):
|
|
695
|
+
lock_fd = open(self.lock_file, "r")
|
|
696
|
+
temp_fd.seek(0)
|
|
697
|
+
log_conent = temp_fd.read()
|
|
698
|
+
if show_log:
|
|
699
|
+
self.log.info(log_conent, uptrace=1)
|
|
700
|
+
fcntl.flock(lock_fd.fileno(), fcntl.LOCK_EX)
|
|
701
|
+
with os.fdopen(os.open(target_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
|
|
702
|
+
stat.S_IWUSR | stat.S_IRUSR), 'w+') as log_fd:
|
|
703
|
+
log_fd.write(log_conent)
|
|
704
|
+
fcntl.flock(lock_fd.fileno(), fcntl.LOCK_UN)
|