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.

Files changed (242) hide show
  1. bmcgo/__init__.py +12 -0
  2. bmcgo/bmcgo.py +22 -0
  3. bmcgo/bmcgo_config.py +176 -0
  4. bmcgo/cli/__init__.py +10 -0
  5. bmcgo/cli/cli.py +584 -0
  6. bmcgo/codegen/__init__.py +14 -0
  7. bmcgo/codegen/c/__init__.py +9 -0
  8. bmcgo/codegen/c/annotation.py +52 -0
  9. bmcgo/codegen/c/argument.py +42 -0
  10. bmcgo/codegen/c/codegen.py +153 -0
  11. bmcgo/codegen/c/comment.py +22 -0
  12. bmcgo/codegen/c/ctype_defination.py +353 -0
  13. bmcgo/codegen/c/helper.py +87 -0
  14. bmcgo/codegen/c/interface.py +63 -0
  15. bmcgo/codegen/c/method.py +82 -0
  16. bmcgo/codegen/c/property.py +180 -0
  17. bmcgo/codegen/c/renderer.py +21 -0
  18. bmcgo/codegen/c/signal.py +64 -0
  19. bmcgo/codegen/c/template/client.c.mako +145 -0
  20. bmcgo/codegen/c/template/client.h.mako +36 -0
  21. bmcgo/codegen/c/template/interface.c.mako +0 -0
  22. bmcgo/codegen/c/template/interface.introspect.xml.mako +99 -0
  23. bmcgo/codegen/c/template/micro_component.c.mako +32 -0
  24. bmcgo/codegen/c/template/public.c.mako +228 -0
  25. bmcgo/codegen/c/template/public.h.mako +128 -0
  26. bmcgo/codegen/c/template/server.c.mako +104 -0
  27. bmcgo/codegen/c/template/server.h.mako +36 -0
  28. bmcgo/codegen/lua/.lua-format +7 -0
  29. bmcgo/codegen/lua/Makefile +101 -0
  30. bmcgo/codegen/lua/__init__.py +9 -0
  31. bmcgo/codegen/lua/codegen.py +171 -0
  32. bmcgo/codegen/lua/proto/Makefile +87 -0
  33. bmcgo/codegen/lua/proto/ipmi_types.proto +17 -0
  34. bmcgo/codegen/lua/proto/types.proto +52 -0
  35. bmcgo/codegen/lua/script/check_intfs.py +161 -0
  36. bmcgo/codegen/lua/script/dto/__init__.py +11 -0
  37. bmcgo/codegen/lua/script/dto/exception.py +53 -0
  38. bmcgo/codegen/lua/script/dto/kepler_abstract.py +47 -0
  39. bmcgo/codegen/lua/script/dto/options.py +33 -0
  40. bmcgo/codegen/lua/script/dto/print_simple.py +19 -0
  41. bmcgo/codegen/lua/script/dto/redfish_api.py +241 -0
  42. bmcgo/codegen/lua/script/dto/url_route.py +195 -0
  43. bmcgo/codegen/lua/script/gen_db_json.py +444 -0
  44. bmcgo/codegen/lua/script/gen_depends.py +89 -0
  45. bmcgo/codegen/lua/script/gen_entry.py +263 -0
  46. bmcgo/codegen/lua/script/gen_feature_json.py +156 -0
  47. bmcgo/codegen/lua/script/gen_historical_local_db_json.py +88 -0
  48. bmcgo/codegen/lua/script/gen_intf_json.py +261 -0
  49. bmcgo/codegen/lua/script/gen_intf_rpc_json.py +575 -0
  50. bmcgo/codegen/lua/script/gen_ipmi_json.py +485 -0
  51. bmcgo/codegen/lua/script/gen_mdb_json.py +117 -0
  52. bmcgo/codegen/lua/script/gen_rpc_msg_json.py +487 -0
  53. bmcgo/codegen/lua/script/gen_schema.py +302 -0
  54. bmcgo/codegen/lua/script/ipmi_types_pb2.py +135 -0
  55. bmcgo/codegen/lua/script/loader/__init__.py +11 -0
  56. bmcgo/codegen/lua/script/loader/file_utils.py +33 -0
  57. bmcgo/codegen/lua/script/loader/kepler_abstract_collect.py +79 -0
  58. bmcgo/codegen/lua/script/loader/kepler_abstract_loader.py +47 -0
  59. bmcgo/codegen/lua/script/loader/redfish_loader.py +127 -0
  60. bmcgo/codegen/lua/script/lua_format.py +62 -0
  61. bmcgo/codegen/lua/script/mds_util.py +385 -0
  62. bmcgo/codegen/lua/script/merge_model.py +330 -0
  63. bmcgo/codegen/lua/script/merge_proto_algo.py +85 -0
  64. bmcgo/codegen/lua/script/proto_loader.py +47 -0
  65. bmcgo/codegen/lua/script/proto_plugin.py +140 -0
  66. bmcgo/codegen/lua/script/redfish_source_tree.py +118 -0
  67. bmcgo/codegen/lua/script/render_utils/__init__.py +38 -0
  68. bmcgo/codegen/lua/script/render_utils/base.py +25 -0
  69. bmcgo/codegen/lua/script/render_utils/client_lua.py +98 -0
  70. bmcgo/codegen/lua/script/render_utils/controller_lua.py +71 -0
  71. bmcgo/codegen/lua/script/render_utils/db_lua.py +224 -0
  72. bmcgo/codegen/lua/script/render_utils/error_lua.py +185 -0
  73. bmcgo/codegen/lua/script/render_utils/factory.py +52 -0
  74. bmcgo/codegen/lua/script/render_utils/ipmi_lua.py +159 -0
  75. bmcgo/codegen/lua/script/render_utils/ipmi_message_lua.py +24 -0
  76. bmcgo/codegen/lua/script/render_utils/mdb_lua.py +177 -0
  77. bmcgo/codegen/lua/script/render_utils/mdb_register.py +215 -0
  78. bmcgo/codegen/lua/script/render_utils/message_lua.py +26 -0
  79. bmcgo/codegen/lua/script/render_utils/messages_lua.py +156 -0
  80. bmcgo/codegen/lua/script/render_utils/model_lua.py +485 -0
  81. bmcgo/codegen/lua/script/render_utils/old_model_lua.py +429 -0
  82. bmcgo/codegen/lua/script/render_utils/plugin_lua.py +38 -0
  83. bmcgo/codegen/lua/script/render_utils/redfish_proto.py +86 -0
  84. bmcgo/codegen/lua/script/render_utils/request_lua.py +76 -0
  85. bmcgo/codegen/lua/script/render_utils/service_lua.py +130 -0
  86. bmcgo/codegen/lua/script/render_utils/utils_message_lua.py +125 -0
  87. bmcgo/codegen/lua/script/render_utils/validate_lua.py +221 -0
  88. bmcgo/codegen/lua/script/sep_ipmi_message_cmds.py +217 -0
  89. bmcgo/codegen/lua/script/template.py +166 -0
  90. bmcgo/codegen/lua/script/types_pb2.py +516 -0
  91. bmcgo/codegen/lua/script/utils.py +663 -0
  92. bmcgo/codegen/lua/script/validate.py +80 -0
  93. bmcgo/codegen/lua/script/yaml_to_json.py +73 -0
  94. bmcgo/codegen/lua/templates/Makefile +114 -0
  95. bmcgo/codegen/lua/templates/apps/Makefile +261 -0
  96. bmcgo/codegen/lua/templates/apps/Makefile.mdb.mk +64 -0
  97. bmcgo/codegen/lua/templates/apps/app.lua.mako +19 -0
  98. bmcgo/codegen/lua/templates/apps/class.lua.mako +35 -0
  99. bmcgo/codegen/lua/templates/apps/client.lua.mako +429 -0
  100. bmcgo/codegen/lua/templates/apps/controller.lua.mako +276 -0
  101. bmcgo/codegen/lua/templates/apps/datas.lua.mako +8 -0
  102. bmcgo/codegen/lua/templates/apps/db.lua.mako +89 -0
  103. bmcgo/codegen/lua/templates/apps/entry.lua.mako +128 -0
  104. bmcgo/codegen/lua/templates/apps/feature.lua.mako +37 -0
  105. bmcgo/codegen/lua/templates/apps/generate_route.mako +25 -0
  106. bmcgo/codegen/lua/templates/apps/impl_feature.lua.mako +72 -0
  107. bmcgo/codegen/lua/templates/apps/ipmi.lua.mako +97 -0
  108. bmcgo/codegen/lua/templates/apps/ipmi_cmd.lua.mako +18 -0
  109. bmcgo/codegen/lua/templates/apps/ipmi_message.lua.mako +36 -0
  110. bmcgo/codegen/lua/templates/apps/local_db.lua.mako +263 -0
  111. bmcgo/codegen/lua/templates/apps/main.lua.mako +25 -0
  112. bmcgo/codegen/lua/templates/apps/mc.lua.mako +77 -0
  113. bmcgo/codegen/lua/templates/apps/mdb.lua.mako +45 -0
  114. bmcgo/codegen/lua/templates/apps/mdb_interface.lua.mako +73 -0
  115. bmcgo/codegen/lua/templates/apps/message.lua.mako +38 -0
  116. bmcgo/codegen/lua/templates/apps/model.lua.mako +239 -0
  117. bmcgo/codegen/lua/templates/apps/orm_classes.lua.mako +16 -0
  118. bmcgo/codegen/lua/templates/apps/plugin.lua.mako +8 -0
  119. bmcgo/codegen/lua/templates/apps/redfish.proto.mako +47 -0
  120. bmcgo/codegen/lua/templates/apps/service.lua.mako +440 -0
  121. bmcgo/codegen/lua/templates/apps/signal_listen.lua.mako +19 -0
  122. bmcgo/codegen/lua/templates/apps/utils/default_intf.lua.mako +41 -0
  123. bmcgo/codegen/lua/templates/apps/utils/enum.mako +10 -0
  124. bmcgo/codegen/lua/templates/apps/utils/imports.mako +13 -0
  125. bmcgo/codegen/lua/templates/apps/utils/mdb_intf.lua.mako +25 -0
  126. bmcgo/codegen/lua/templates/apps/utils/mdb_obj.lua.mako +23 -0
  127. bmcgo/codegen/lua/templates/apps/utils/message.mako +160 -0
  128. bmcgo/codegen/lua/templates/apps/utils/request.lua.mako +59 -0
  129. bmcgo/codegen/lua/templates/apps/utils/validate.mako +83 -0
  130. bmcgo/codegen/lua/templates/errors.lua.mako +36 -0
  131. bmcgo/codegen/lua/templates/messages.lua.mako +32 -0
  132. bmcgo/codegen/lua/templates/new_app/.clang-format.mako +170 -0
  133. bmcgo/codegen/lua/templates/new_app/.gitignore.mako +26 -0
  134. bmcgo/codegen/lua/templates/new_app/CHANGELOG.md.mako +0 -0
  135. bmcgo/codegen/lua/templates/new_app/CMakeLists.txt.mako +29 -0
  136. bmcgo/codegen/lua/templates/new_app/Makefile.mako +25 -0
  137. bmcgo/codegen/lua/templates/new_app/README.md.mako +0 -0
  138. bmcgo/codegen/lua/templates/new_app/conanfile.py.mako +7 -0
  139. bmcgo/codegen/lua/templates/new_app/config.cfg.mako +6 -0
  140. bmcgo/codegen/lua/templates/new_app/mds/model.json.mako +3 -0
  141. bmcgo/codegen/lua/templates/new_app/mds/service.json.mako +21 -0
  142. bmcgo/codegen/lua/templates/new_app/permissions.ini.mako +16 -0
  143. bmcgo/codegen/lua/templates/new_app/src/lualib/${project_name}_app.lua.mako +16 -0
  144. bmcgo/codegen/lua/templates/new_app/src/service/main.lua.mako +25 -0
  145. bmcgo/codegen/lua/templates/new_app/test/integration/test_${project_name}.conf.mako +9 -0
  146. bmcgo/codegen/lua/templates/new_app/test/integration/test_${project_name}.lua.mako +47 -0
  147. bmcgo/codegen/lua/templates/new_app/test/unit/test.lua.mako +23 -0
  148. bmcgo/codegen/lua/templates/new_app/user_conf/rootfs/etc/systemd/system/${project_name}.service.mako +18 -0
  149. bmcgo/codegen/lua/templates/new_app/user_conf/rootfs/etc/systemd/system/multi-user.target.wants/${project_name}.service.link +1 -0
  150. bmcgo/component/__init__.py +10 -0
  151. bmcgo/component/analysis/analysis.py +183 -0
  152. bmcgo/component/analysis/build_deps.py +165 -0
  153. bmcgo/component/analysis/data_deps.py +333 -0
  154. bmcgo/component/analysis/dep-rules.json +912 -0
  155. bmcgo/component/analysis/dep_node.py +110 -0
  156. bmcgo/component/analysis/intf_deps.py +163 -0
  157. bmcgo/component/analysis/intf_validation.py +254 -0
  158. bmcgo/component/analysis/rule.py +211 -0
  159. bmcgo/component/analysis/smc_dfx_whitelist.json +11 -0
  160. bmcgo/component/analysis/sr_validation.py +391 -0
  161. bmcgo/component/build.py +222 -0
  162. bmcgo/component/component_dt_version_parse.py +348 -0
  163. bmcgo/component/component_helper.py +114 -0
  164. bmcgo/component/coverage/__init__.py +11 -0
  165. bmcgo/component/coverage/c_incremental_cov_report.template +53 -0
  166. bmcgo/component/coverage/incremental_cov.py +464 -0
  167. bmcgo/component/deploy.py +110 -0
  168. bmcgo/component/gen.py +169 -0
  169. bmcgo/component/package_info.py +236 -0
  170. bmcgo/component/template/conanbase.py.mako +278 -0
  171. bmcgo/component/template/conanfile.deploy.py.mako +40 -0
  172. bmcgo/component/test.py +947 -0
  173. bmcgo/errors.py +119 -0
  174. bmcgo/frame.py +217 -0
  175. bmcgo/functional/__init__.py +10 -0
  176. bmcgo/functional/analysis.py +96 -0
  177. bmcgo/functional/bmc_studio_action.py +98 -0
  178. bmcgo/functional/check.py +185 -0
  179. bmcgo/functional/conan_index_build.py +251 -0
  180. bmcgo/functional/config.py +332 -0
  181. bmcgo/functional/csr_build.py +724 -0
  182. bmcgo/functional/deploy.py +263 -0
  183. bmcgo/functional/diff.py +235 -0
  184. bmcgo/functional/fetch.py +235 -0
  185. bmcgo/functional/full_component.py +391 -0
  186. bmcgo/functional/maintain.py +381 -0
  187. bmcgo/functional/new.py +166 -0
  188. bmcgo/functional/schema_valid.py +111 -0
  189. bmcgo/functional/simple_sign.py +104 -0
  190. bmcgo/functional/upgrade.py +78 -0
  191. bmcgo/ipmigen/__init__.py +13 -0
  192. bmcgo/ipmigen/ctype_defination.py +82 -0
  193. bmcgo/ipmigen/ipmigen.py +309 -0
  194. bmcgo/ipmigen/template/cmd.c.mako +366 -0
  195. bmcgo/ipmigen/template/ipmi.c.mako +25 -0
  196. bmcgo/ipmigen/template/ipmi.h.mako +51 -0
  197. bmcgo/logger.py +176 -0
  198. bmcgo/misc.py +117 -0
  199. bmcgo/target/app.yml +17 -0
  200. bmcgo/target/install_sdk.yml +15 -0
  201. bmcgo/target/personal.yml +53 -0
  202. bmcgo/target/publish.yml +45 -0
  203. bmcgo/tasks/__init__.py +11 -0
  204. bmcgo/tasks/download_buildtools_hm.py +124 -0
  205. bmcgo/tasks/misc.py +15 -0
  206. bmcgo/tasks/task.py +354 -0
  207. bmcgo/tasks/task_build_conan.py +714 -0
  208. bmcgo/tasks/task_build_rootfs_img.py +595 -0
  209. bmcgo/tasks/task_buildgppbin.py +88 -0
  210. bmcgo/tasks/task_buildhpm_ext4.py +82 -0
  211. bmcgo/tasks/task_create_interface_config.py +122 -0
  212. bmcgo/tasks/task_download_buildtools.py +99 -0
  213. bmcgo/tasks/task_download_dependency.py +72 -0
  214. bmcgo/tasks/task_hpm_envir_prepare.py +112 -0
  215. bmcgo/tasks/task_packet_to_supporte.py +87 -0
  216. bmcgo/tasks/task_prepare.py +105 -0
  217. bmcgo/tasks/task_sign_and_pack_hpm.py +42 -0
  218. bmcgo/utils/__init__.py +10 -0
  219. bmcgo/utils/buffer.py +128 -0
  220. bmcgo/utils/combine_json_schemas.py +170 -0
  221. bmcgo/utils/component_post.py +54 -0
  222. bmcgo/utils/component_version_check.py +86 -0
  223. bmcgo/utils/config.py +1067 -0
  224. bmcgo/utils/fetch_component_code.py +232 -0
  225. bmcgo/utils/install_manager.py +61 -0
  226. bmcgo/utils/installations/__init__.py +10 -0
  227. bmcgo/utils/installations/base_installer.py +70 -0
  228. bmcgo/utils/installations/install_consts.py +30 -0
  229. bmcgo/utils/installations/install_plans/bingo.yml +11 -0
  230. bmcgo/utils/installations/install_workflow.py +50 -0
  231. bmcgo/utils/installations/installers/apt_installer.py +177 -0
  232. bmcgo/utils/installations/installers/pip_installer.py +46 -0
  233. bmcgo/utils/installations/version_util.py +100 -0
  234. bmcgo/utils/mapping_config_patch.py +443 -0
  235. bmcgo/utils/perf_analysis.py +114 -0
  236. bmcgo/utils/tools.py +704 -0
  237. bmcgo/worker.py +417 -0
  238. openubmc_bingo-0.5.240.dist-info/METADATA +30 -0
  239. openubmc_bingo-0.5.240.dist-info/RECORD +242 -0
  240. openubmc_bingo-0.5.240.dist-info/WHEEL +5 -0
  241. openubmc_bingo-0.5.240.dist-info/entry_points.txt +2 -0
  242. openubmc_bingo-0.5.240.dist-info/top_level.txt +1 -0
@@ -0,0 +1,232 @@
1
+ #!/usr/bin/env python3
2
+ # encoding=utf-8
3
+ # 描述:根据conan包拉取组件代码
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 re
15
+ import shutil
16
+ import subprocess
17
+ from multiprocessing import Pool
18
+ import patch_ng
19
+ import yaml
20
+ from git import Repo
21
+
22
+ from bmcgo.misc import errors
23
+ from bmcgo import misc
24
+ from bmcgo.utils.tools import Tools
25
+
26
+ tools = Tools("fetch_component_code")
27
+ log = tools.log
28
+
29
+
30
+ def process_err_cb(err):
31
+ log.error("!!!!!!!!!!!!!!!!!!!!!!!!!!! 拉取代码失败, 错误: %s", err)
32
+
33
+
34
+ class FetchComponentCode:
35
+ def __init__(self, packages, target_dir, conan_remote, include_open_source=True):
36
+ self.conan = shutil.which(misc.CONAN)
37
+ if self.conan is None:
38
+ raise RuntimeError("找不到 conan 工具")
39
+ self.packages = packages
40
+ self.target_dir = target_dir
41
+ self.remote = conan_remote
42
+ self.include_open_source = include_open_source
43
+
44
+ @staticmethod
45
+ def resolve_version_range(component_name, version_range):
46
+ cmd = f"conan info '{version_range}' --package-filter={component_name}/*" \
47
+ f" -r {misc.CONAN_REPO} --only None 2>/dev/null"
48
+ ret, output = subprocess.getstatusoutput(cmd)
49
+ output = output.strip()
50
+ if ret != 0 or not output:
51
+ return None
52
+ return output.split("\n")[-1]
53
+
54
+ @staticmethod
55
+ def patch(patch_file=None):
56
+ patchset = patch_ng.fromfile(patch_file)
57
+ if not patchset:
58
+ raise errors.BmcGoException("Failed to parse patch: %s" % (patch_file))
59
+ if not patchset.apply(strip=0, root="./", fuzz=False):
60
+ raise errors.BmcGoException("Failed to apply patch: %s" % patch_file)
61
+
62
+ @staticmethod
63
+ def _get_patch_changed_files(patch_file):
64
+ files = {}
65
+ for line in open(patch_file):
66
+ if not line.startswith("diff --git"):
67
+ continue
68
+ line = line.strip()
69
+ chunk = line.split()
70
+ a_file = chunk[-2][2:]
71
+ b_file = chunk[-1][2:]
72
+ files[a_file] = b_file
73
+ return files
74
+
75
+ @staticmethod
76
+ def _apply_patches_direct(real_patch, patch_file, changed_files):
77
+ FetchComponentCode.patch(patch_file=real_patch)
78
+ for a_file, b_file in changed_files.items():
79
+ if a_file != b_file:
80
+ if a_file != "/dev/null" and b_file != "/dev/null":
81
+ os.rename(a_file, b_file)
82
+ cmd = f"git rm -f {a_file}"
83
+ tools.run_command(cmd)
84
+ elif a_file != "/dev/null":
85
+ cmd = f"git rm -f {a_file}"
86
+ tools.run_command(cmd)
87
+ continue
88
+ cmd = f"git add {b_file}"
89
+ tools.run_command(cmd)
90
+ cmd = f"git commit -m \"{patch_file}\""
91
+ tools.run_command(cmd)
92
+
93
+ @staticmethod
94
+ def __apply_patches(conandata_file, patches, code_dir):
95
+ cwd = os.getcwd()
96
+ recipe_folder = os.path.join(os.path.dirname(conandata_file), "..", "export_source")
97
+ recipe_folder = os.path.realpath(recipe_folder)
98
+ os.chdir(os.path.join(cwd, code_dir))
99
+ for patch in patches:
100
+ patch_file = patch.get("patch_file")
101
+ if not patch_file:
102
+ log.warning(f"{code_dir} 组件的conandata.yml文件缺少patch_file,跳过git apply操作")
103
+ real_patch = os.path.join(recipe_folder, patch_file)
104
+ if not os.path.isfile(real_patch):
105
+ log.error(f"{code_dir} 组件申明的补丁文件{real_patch}不存在,可能产生错误,请人工处理")
106
+ continue
107
+ changed_files = FetchComponentCode._get_patch_changed_files(real_patch)
108
+ log.info(f"{code_dir} 开始应用源码补丁{patch_file}")
109
+ try:
110
+ FetchComponentCode._apply_patches_direct(real_patch, patch_file, changed_files)
111
+ except errors.BmcGoException:
112
+ # 尝试还原文件修改
113
+ for a_file, b_file in changed_files.items():
114
+ cmd = f"git checkout -- {a_file}"
115
+ tools.run_command(cmd, ignore_error=True)
116
+ cmd = f"git checkout -- {b_file}"
117
+ tools.run_command(cmd, ignore_error=True)
118
+ cmd = "git am " + real_patch
119
+ tools.run_command(cmd)
120
+ log.info(f"{code_dir} 应用源码补丁{patch_file}")
121
+ os.chdir(cwd)
122
+
123
+ @staticmethod
124
+ def __update_code_by_commit_id(code_dir, url, commit_id):
125
+ if os.path.exists(code_dir):
126
+ repo = Repo(code_dir)
127
+ repo.git.fetch('origin')
128
+ else:
129
+ Repo.clone_from(url, to_path=code_dir)
130
+ repo = Repo(code_dir)
131
+
132
+ repo.index.reset(commit=commit_id, head=True, working_tree=True)
133
+ repo.git.clean('-dfx')
134
+ log.info("更新代码(组件: %s, 地址: %s, 提交节点: %s)", code_dir, url, commit_id)
135
+
136
+ @staticmethod
137
+ def __update_code_by_branch(code_dir, deps):
138
+ url = deps['url']
139
+ branch = deps['branch'].split('/')[-1]
140
+
141
+ if os.path.exists(code_dir):
142
+ repo = Repo(code_dir)
143
+ repo.git.fetch('origin', branch)
144
+ repo.git.pull('origin', branch)
145
+ repo.git.checkout(branch)
146
+ else:
147
+ Repo.clone_from(url, to_path=code_dir, branch=branch)
148
+ repo = Repo(code_dir)
149
+ log.info("更新代码(组件: %s, 地址: %s, 分支: %s)", code_dir, url, branch)
150
+
151
+ @staticmethod
152
+ def __update_component_code_by_conandata(name, version, conandata_file):
153
+ with open(conandata_file, 'r') as f_:
154
+ conandata = yaml.safe_load(f_)
155
+ deps = conandata.get("sources", {}).get(version, {})
156
+ if 'url' in deps:
157
+ FetchComponentCode.__update_code_by_branch(name, deps)
158
+ patches = conandata.get("patches", {}).get(version)
159
+ if patches:
160
+ FetchComponentCode.__apply_patches(conandata_file, patches, name)
161
+ else:
162
+ for comp, deps in deps.items():
163
+ FetchComponentCode.__update_code_by_branch(comp, deps)
164
+
165
+ @staticmethod
166
+ def __getinfo_from_conanfile(conanfile):
167
+ with open(conanfile, "r") as file:
168
+ lines = file.readlines()
169
+ for idx, line in enumerate(lines):
170
+ if line.find('scm = {"revision":') > 0:
171
+ revision = re.split(r'["]', line)[-2]
172
+ url = re.split(r'["]', lines[idx + 2])[-2]
173
+ break
174
+ else:
175
+ raise RuntimeError("无法找到版本(revision)和地址(url)字段")
176
+
177
+ return revision, url
178
+
179
+ def run(self):
180
+ packages_to_fetch = dict()
181
+ for component_name, package in self.packages.items():
182
+ version_str = re.split("/|@", package)[1]
183
+ if "[" not in version_str:
184
+ if self.include_open_source or re.fullmatch("\d+\.\d+\.\d+", version_str) is not None:
185
+ packages_to_fetch[component_name] = package
186
+ continue
187
+ resolved_package = self.resolve_version_range(component_name, package)
188
+ if resolved_package is None:
189
+ log.warning("查找不到与 %s 范围匹配的版本", package)
190
+ else:
191
+ packages_to_fetch[component_name] = resolved_package
192
+ log.info("查找到与 %s 范围匹配的版本 %s", package, resolved_package)
193
+
194
+ process_count = min(len(packages_to_fetch), os.cpu_count())
195
+ log.info("创建 %u 个进程拉取代码", process_count)
196
+ pool = Pool(processes=process_count)
197
+ for component_name, conan_version in packages_to_fetch.items():
198
+ pool.apply_async(func=self.update_component_code, args=(component_name, conan_version),
199
+ error_callback=process_err_cb)
200
+ pool.close()
201
+ pool.join()
202
+
203
+ def update_component_code(self, component_name, conan_version):
204
+ """
205
+ update component code by conan version
206
+ """
207
+ try:
208
+ os.chdir(self.target_dir)
209
+ log.info("更新 %s 组件代码到 %s 开始", component_name, conan_version)
210
+
211
+ version_split = re.split(r'[/, @]', conan_version)
212
+ conan_dir = os.path.join(os.path.expanduser('~'), '.conan/data/', *version_split, 'export')
213
+ conandata = os.path.join(conan_dir, 'conandata.yml')
214
+ if not os.path.exists(conan_dir):
215
+ conan_remote_list = tools.get_conan_remote_list(self.remote)
216
+ tools.download_conan_recipes(conan_version, conan_remote_list)
217
+ if os.path.exists(conandata):
218
+ FetchComponentCode.__update_component_code_by_conandata(version_split[0], version_split[1], conandata)
219
+ return
220
+
221
+ conanfile = os.path.join(conan_dir, 'conanfile.py')
222
+ if os.path.exists(conanfile):
223
+ revision, url = FetchComponentCode.__getinfo_from_conanfile(conanfile)
224
+ FetchComponentCode.__update_code_by_commit_id(component_name, url, revision)
225
+ return
226
+
227
+ log.error("conandata(%s) 和 conanfile(%s) 都没有找到", conandata, conanfile)
228
+ log.info("更新组件 %s 代码到 %s 失败, 无法获取到 conan 信息", component_name,
229
+ conan_version)
230
+ except Exception as exp:
231
+ log.error("工作状态错误: %s", exp)
232
+ log.error("更新组件代码到 %s 失败", conan_version)
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env python3
2
+ # encoding=utf-8
3
+ # 描述:安装管理器
4
+ # Copyright (c) 2025 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
+
14
+ from pathlib import Path
15
+ from bmcgo.utils.tools import Logger
16
+ from bmcgo.utils.installations import install_consts
17
+ from bmcgo.utils.installations.install_workflow import InstallWorkflow
18
+ from bmcgo.utils.installations.base_installer import BaseInstaller
19
+
20
+ logger = Logger(name="upgrade", log_file="/usr/share/bmcgo/install.log")
21
+ InstallWorkflow.logger = logger
22
+ BaseInstaller.logger = logger
23
+
24
+
25
+ class InstallManager:
26
+ def __init__(self):
27
+ self._custom_path = None
28
+
29
+ @property
30
+ def custom_installer_path(self):
31
+ return self._custom_path / install_consts.PLUGIN_INSTALLER_PATH
32
+
33
+ @property
34
+ def custom_install_plan_path(self):
35
+ return self._custom_path / install_consts.PLUGIN_INSTALL_PLAN_PATH
36
+
37
+ def install(self, app_name, operator, version, custom_path):
38
+ self._set_custom_path(custom_path)
39
+ BaseInstaller.discover_installers()
40
+ InstallWorkflow.discover_workflows()
41
+
42
+ workflows = []
43
+ if app_name == install_consts.INSTALL_ALL:
44
+ workflows = list(InstallWorkflow.get_all_plans())
45
+ else:
46
+ workflows = [app_name]
47
+
48
+ for wname in workflows:
49
+ logger.info(f"安装{wname}...")
50
+ plans = InstallWorkflow.parse(wname)
51
+ for plan in plans.get(install_consts.PLAN_STEPS, []):
52
+ inst_type = plan.get(install_consts.PLAN_INSTALL_TYPE)
53
+ BaseInstaller.get_installer(inst_type).install(plan, operator, version)
54
+
55
+ def _set_custom_path(self, custom_path: str):
56
+ self._custom_path = Path(custom_path).resolve()
57
+ if not self._custom_path.exists() or not self._custom_path.is_dir():
58
+ logger.warning(f"无效的地址: {self._custom_path}")
59
+ return
60
+ BaseInstaller.add_installer_dir(self.custom_installer_path)
61
+ InstallWorkflow.add_plan_dir(self.custom_install_plan_path)
@@ -0,0 +1,10 @@
1
+ # coding: utf-8
2
+ # Copyright (c) 2024 Huawei Technologies Co., Ltd.
3
+ # openUBMC is licensed under Mulan PSL v2.
4
+ # You can use this software according to the terms and conditions of the Mulan PSL v2.
5
+ # You may obtain a copy of Mulan PSL v2 at:
6
+ # http://license.coscl.org.cn/MulanPSL2
7
+ # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
8
+ # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
9
+ # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
10
+ # See the Mulan PSL v2 for more details.
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env python3
2
+ # encoding=utf-8
3
+ # 描述:安装工具工厂类
4
+ # Copyright (c) 2025 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 abc
14
+ import sys
15
+ import importlib.util
16
+ from pathlib import Path
17
+ from typing import Dict, List, Type
18
+ from bmcgo.utils.installations import install_consts
19
+
20
+
21
+ class BaseInstaller(abc.ABC):
22
+ logger = None
23
+ _intallers: Dict[str, Type["BaseInstaller"]] = {}
24
+ search_paths: List[Path] = [Path(__file__).resolve().parent / install_consts.PLUGIN_INSTALLER_PATH]
25
+
26
+ def __init_subclass__(cls, installer_type: str, **kwargs):
27
+ super.__init_subclass__(**kwargs)
28
+
29
+ key = installer_type or cls.__name__.lower()
30
+ if key in cls._intallers:
31
+ cls.logger and cls.logger.warning(f"{installer_type}({cls._intallers[key]} 被替换为: {cls})")
32
+ cls._intallers[installer_type] = cls
33
+
34
+ @classmethod
35
+ def add_installer_dir(cls, directory: Path):
36
+ if directory not in cls.search_paths:
37
+ cls.search_paths.append(directory)
38
+
39
+ @classmethod
40
+ def discover_installers(cls):
41
+ for path in cls.search_paths:
42
+ if not path.exists():
43
+ cls.logger and cls.logger.warning(f"未知安装工具路径:: {str(path)},跳过")
44
+ continue
45
+
46
+ for inst in path.glob("*.py"):
47
+ if inst.name == "__init__.py":
48
+ continue
49
+
50
+ module_name = inst.stem
51
+ spec = importlib.util.spec_from_file_location(f"installer_{module_name}", inst)
52
+ if spec and spec.loader:
53
+ module = importlib.util.module_from_spec(spec)
54
+ try:
55
+ sys.modules[module.__name__] = module
56
+ spec.loader.exec_module(module)
57
+ except Exception as e:
58
+ cls.logger and cls.logger.exception(f"加载安装器 {inst} 失败: {str(e)}")
59
+ continue
60
+
61
+ @classmethod
62
+ def get_installer(cls, installer_type: str) -> "BaseInstaller":
63
+ installer_cls = cls._intallers.get(installer_type)
64
+ if not installer_cls:
65
+ raise ValueError(f"未定义的安装方法:{installer_type}")
66
+ return installer_cls()
67
+
68
+ @abc.abstractmethod
69
+ def install(self, plan: Dict[str, List[str]], operator: str, version: str):
70
+ """ 安装入口 """
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env python3
2
+ # encoding=utf-8
3
+ # 描述:安装工具集常量
4
+ # Copyright (c) 2025 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
+
14
+ INSTALLATION_PATH = "instllations"
15
+
16
+ PLUGIN_INSTALLER_PATH = "installers"
17
+ PLUGIN_INSTALL_PLAN_PATH = "install_plans"
18
+
19
+ INSTALL_ALL = "all"
20
+ INSTALL_LATEST = "latest"
21
+ INSTALL_DEFAULT = f"{INSTALL_ALL}={INSTALL_LATEST}"
22
+
23
+ PLAN_STEPS = "install_steps"
24
+ PLAN_INSTALL_TYPE = "type"
25
+ PLAN_PACKAGE_NAME = "package_name"
26
+ PLAN_MODULE_NAME = "module_name"
27
+ PLAN_REPO_URL = "url"
28
+ PLAN_GPG = "gpg"
29
+ PLAN_CONFIG_FILE = "config_file"
30
+ PLAN_PUBLIC_KEY = "public_key"
@@ -0,0 +1,11 @@
1
+ install_steps:
2
+ - type: pip
3
+ package_name: openubmc-bingo
4
+ module_name: bingo
5
+ - type: apt
6
+ package_name: openubmc-bingo
7
+ config_file: bingo.list
8
+ url: https://openubmc-apt-repo.obs.cn-north-4.myhuaweicloud.com/bingo_test_2
9
+ gpg: bingo.gpg
10
+ public_key: gpg_key.public
11
+
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env python3
2
+ # encoding=utf-8
3
+ # 描述:安装流程配置
4
+ # Copyright (c) 2025 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
+
14
+ from typing import Dict, List
15
+ from pathlib import Path
16
+ import yaml
17
+ from bmcgo.utils.installations import install_consts
18
+
19
+
20
+ class InstallWorkflow:
21
+ logger = None
22
+ _workflows: Dict[str, List[str]] = {}
23
+ search_paths: List[Path] = [Path(__file__).resolve().parent / install_consts.PLUGIN_INSTALL_PLAN_PATH]
24
+
25
+ @classmethod
26
+ def discover_workflows(cls):
27
+ for path in cls.search_paths:
28
+ if not path.exists():
29
+ cls.logger and cls.logger.warning(f"未找到安装配置路径:w{str(path)}")
30
+ continue
31
+
32
+ for yml_file in path.glob("*.yml"):
33
+ with open(yml_file) as conf:
34
+ cls._workflows[yml_file.stem] = yaml.safe_load(conf)
35
+
36
+ @classmethod
37
+ def parse(cls, name: str) -> List[str]:
38
+ workflow = cls._workflows.get(name)
39
+ if not workflow:
40
+ raise ValueError(f"未找到安装配置:{str(workflow)}")
41
+ return workflow
42
+
43
+ @classmethod
44
+ def add_plan_dir(cls, directory: Path):
45
+ if directory not in cls.search_paths:
46
+ cls.search_paths.append(directory)
47
+
48
+ @classmethod
49
+ def get_all_plans(cls):
50
+ return cls._workflows.keys()
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env python3
2
+ # encoding=utf-8
3
+ # 描述:apt安装工具
4
+ # Copyright (c) 2025 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 base64
15
+ import tempfile
16
+ import requests
17
+ from typing import Dict, List
18
+ from pathlib import Path
19
+ from bmcgo.utils.tools import Tools
20
+ from bmcgo.utils.installations import install_consts
21
+ from bmcgo.utils.installations.version_util import PkgVersion
22
+ from bmcgo.utils.installations.base_installer import BaseInstaller
23
+
24
+
25
+ tool = Tools("apt_install")
26
+
27
+
28
+ class AptInstaller(BaseInstaller, installer_type="apt"):
29
+ def __init__(self):
30
+ self._repo_url = None
31
+ self._gpg_file = None
32
+ self._config_file = None
33
+ self._repo_public_key = None
34
+ self._pkg_name = None
35
+ self._pkg_version = None
36
+
37
+ def install(self, plan: Dict[str, List[str]], operator: str, version: str):
38
+ self._parse_plan(plan)
39
+ self._install_key()
40
+
41
+ if not self._check_repo():
42
+ self.logger and self.logger.info("未检测到仓库配置,开始配置")
43
+ self._config_repo()
44
+
45
+ self._update_cache()
46
+
47
+ target = [self._pkg_name]
48
+ if operator and version:
49
+ ver = self._resolve_constraint(operator, version)
50
+ if ver:
51
+ target.append(ver)
52
+ pkg = "=".join(target)
53
+ self._install_package(pkg)
54
+ self.logger and self.logger.info(f"安装{pkg}完成!")
55
+
56
+ def _get_versions(self) -> List[PkgVersion]:
57
+ result = tool.run_command(["apt-cache", "madison", self._pkg_name], capture_output=True)
58
+ if not result.stdout:
59
+ return []
60
+ return [PkgVersion(line.split("|")[1].strip()) for line in result.stdout.splitlines()]
61
+
62
+ def _resolve_constraint(self, opt: str, ver: str) -> str:
63
+ versions = self._get_versions()
64
+ if not versions:
65
+ self.logger and self.logger.warning("当前没有可下载版本!")
66
+ return None
67
+
68
+ if ver == install_consts.INSTALL_LATEST or not opt:
69
+ return versions[0].origin
70
+
71
+ pkg_ver = PkgVersion(ver)
72
+ for v in versions:
73
+ if opt == ">=" and v >= pkg_ver:
74
+ return v.origin
75
+ elif opt == "<=" and v <= pkg_ver:
76
+ return v.origin
77
+ elif opt == "!=" and v != pkg_ver:
78
+ return v.origin
79
+ elif opt == "<" and v < pkg_ver:
80
+ return v.origin
81
+ elif opt == ">" and v > pkg_ver:
82
+ return v.origin
83
+ elif opt == "=" and v == pkg_ver:
84
+ return v.origin
85
+
86
+ raise ValueError(f"没有找到匹配的版本:{opt}{ver}")
87
+
88
+ def _parse_plan(self, plan: Dict[str, List[str]]):
89
+ repo_url = plan.get(install_consts.PLAN_REPO_URL)
90
+ repo_public_key = plan.get(install_consts.PLAN_PUBLIC_KEY)
91
+ gpg_file = plan.get(install_consts.PLAN_GPG)
92
+ config_file = plan.get(install_consts.PLAN_CONFIG_FILE)
93
+ pkg_name = plan.get(install_consts.PLAN_PACKAGE_NAME)
94
+
95
+ if not all(val for key, val in locals().items() if key not in ["self", "plan"]):
96
+ values = [
97
+ f"{install_consts.PLAN_REPO_URL}: {repo_url}",
98
+ f"{install_consts.PLAN_PUBLIC_KEY}: {repo_public_key}",
99
+ f"{install_consts.PLAN_GPG}: {gpg_file}",
100
+ f"{install_consts.PLAN_CONFIG_FILE}: {config_file}",
101
+ f"{install_consts.PLAN_PACKAGE_NAME}: {pkg_name}"
102
+ ]
103
+ raise ValueError(f"请检查安装配置文件:\n{"\n\t".join(values)}\n")
104
+
105
+ self._repo_url = repo_url
106
+ self._repo_public_key = f"{self._repo_url}{repo_public_key}"
107
+ self._gpg_file = Path("/usr/share/keyrings") / gpg_file
108
+ self._config_file = Path("/etc/apt/sources.list.d/") / config_file
109
+ self._pkg_name = pkg_name
110
+
111
+ def _install_key(self):
112
+ self.logger and self.logger.info("下载公钥")
113
+ try:
114
+ key_data = requests.get(self._repo_public_key).content
115
+ except Exception as e:
116
+ raise RuntimeError("下载公钥失败")
117
+
118
+ lines = key_data.splitlines()
119
+ in_block = False
120
+ b64data = []
121
+
122
+ for line in lines:
123
+ if line.startswith(b"-----BEGIN PGP"):
124
+ in_block = True
125
+ continue
126
+ if line.startswith(b"-----END PGP"):
127
+ in_block = False
128
+ continue
129
+ if in_block and line.strip() and not line.startswith(b"="):
130
+ b64data.append(line.strip())
131
+
132
+ if not b64data:
133
+ raise ValueError("公钥出错")
134
+
135
+ dearmor = base64.b64decode(b"".join(b64data))
136
+
137
+ with open(self._gpg_file, "wb") as f:
138
+ f.write(dearmor)
139
+ os.chmod(self._gpg_file, 0o644)
140
+
141
+ def _check_repo(self):
142
+ if not self._config_file.exists():
143
+ return False
144
+
145
+ expect_line = f"deb [signed-by={self._gpg_file}] {self._repo_url} stable main\n"
146
+ with open(self._config_file) as f:
147
+ return any(line.strip() == expect_line.strip() for line in f)
148
+
149
+ def _config_repo(self):
150
+ repo_line = f"deb [signed-by={self._gpg_file}] {self._repo_url} stable main\n"
151
+
152
+ self.logger and self.logger.info("配置仓资源")
153
+ with tempfile.NamedTemporaryFile("w", delete=False) as tmp:
154
+ tmp.write(repo_line)
155
+ tmp_path = tmp.name
156
+
157
+ try:
158
+ tool.run_command(["mv", tmp_path, str(self._config_file)], sudo=True)
159
+ tool.run_command(["chmod", "644", str(self._config_file)], sudo=True)
160
+ except Exception as e:
161
+ os.remove(tmp_path)
162
+ raise RuntimeError(f"写入仓库配置失败: {str(e)}")
163
+
164
+ def _update_cache(self):
165
+ self.logger and self.logger.info("更新 apt 缓存")
166
+ try:
167
+ tool.run_command(["apt-get", "update"], sudo=True)
168
+ except Exception as e:
169
+ raise RuntimeError(f"安装失败: {str(e)}")
170
+
171
+ def _install_package(self, pkg: str):
172
+ self.logger and self.logger.info(f"安装: {pkg}")
173
+ try:
174
+ tool.run_command(["apt-get", "install", "-y", "--allow-downgrades", pkg], sudo=True)
175
+ except Exception as e:
176
+ raise RuntimeError(f"安装失败: {str(e)}")
177
+