openubmc-bingo 0.6.45__py3-none-any.whl → 0.6.99__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.
Files changed (96) hide show
  1. bmcgo/__init__.py +1 -1
  2. bmcgo/bmcgo.py +9 -3
  3. bmcgo/bmcgo_config.py +16 -0
  4. bmcgo/cli/cli.py +72 -21
  5. bmcgo/codegen/__init__.py +1 -1
  6. bmcgo/codegen/lua/codegen.py +2 -2
  7. bmcgo/codegen/lua/script/check_intfs.py +1 -0
  8. bmcgo/codegen/lua/script/dto/options.py +1 -0
  9. bmcgo/codegen/lua/script/gen_db_json.py +4 -3
  10. bmcgo/codegen/lua/script/gen_rpc_msg_json.py +78 -11
  11. bmcgo/codegen/lua/script/model_consistency_check.py +1 -1
  12. bmcgo/codegen/lua/script/render_utils/db_lua.py +5 -6
  13. bmcgo/codegen/lua/script/render_utils/model_lua.py +5 -1
  14. bmcgo/codegen/lua/script/template.py +5 -0
  15. bmcgo/codegen/lua/script/utils.py +50 -8
  16. bmcgo/codegen/lua/templates/apps/Makefile +2 -2
  17. bmcgo/codegen/lua/templates/apps/client.lua.mako +1 -1
  18. bmcgo/codegen/lua/templates/apps/model.lua.mako +4 -3
  19. bmcgo/codegen/lua/templates/apps/service.lua.mako +1 -1
  20. bmcgo/codegen/lua/templates/apps/utils/mdb_intf.lua.mako +4 -0
  21. bmcgo/codegen/lua/templates/new_app_v2/CMakeLists.txt.mako +26 -0
  22. bmcgo/codegen/lua/templates/new_app_v2/conanfile.py.mako +9 -0
  23. bmcgo/codegen/lua/v1/script/render_utils/db_lua.py +5 -6
  24. bmcgo/codegen/lua/v1/script/render_utils/model_lua.py +13 -1
  25. bmcgo/codegen/lua/v1/templates/apps/client.lua.mako +1 -1
  26. bmcgo/codegen/lua/v1/templates/apps/local_db.lua.mako +0 -4
  27. bmcgo/codegen/lua/v1/templates/apps/message.lua.mako +3 -0
  28. bmcgo/codegen/lua/v1/templates/apps/model.lua.mako +3 -0
  29. bmcgo/codegen/lua/v1/templates/apps/utils/mdb_intf.lua.mako +6 -4
  30. bmcgo/component/analysis/analysis.py +9 -4
  31. bmcgo/component/analysis/dep-rules.json +20 -8
  32. bmcgo/component/analysis/dep_node.py +2 -0
  33. bmcgo/component/analysis/intf_validation.py +8 -7
  34. bmcgo/component/analysis/sr_validation.py +5 -4
  35. bmcgo/component/busctl_log_parse/busctl_log_parser.py +809 -0
  36. bmcgo/component/busctl_log_parse/mock_data_save.py +170 -0
  37. bmcgo/component/busctl_log_parse/test_data_save.py +49 -0
  38. bmcgo/component/component_helper.py +29 -0
  39. bmcgo/component/coverage/incremental_cov.py +5 -0
  40. bmcgo/component/fixture/__init__.py +29 -0
  41. bmcgo/component/fixture/auto_case_generator.py +490 -0
  42. bmcgo/component/fixture/busctl_type_converter.py +1081 -0
  43. bmcgo/component/fixture/common_config.py +15 -0
  44. bmcgo/component/fixture/dbus_gateway.py +669 -0
  45. bmcgo/component/fixture/dbus_library.py +250 -0
  46. bmcgo/component/fixture/dbus_mock_utils.py +514 -0
  47. bmcgo/component/fixture/dbus_response_handler.py +138 -0
  48. bmcgo/component/fixture/dbus_signature.py +110 -0
  49. bmcgo/component/template_v2/conanbase.py.mako +1 -5
  50. bmcgo/component/test.py +69 -10
  51. bmcgo/error_analyzer/__init__.py +0 -0
  52. bmcgo/error_analyzer/case_matcher.py +114 -0
  53. bmcgo/error_analyzer/log_parser.py +128 -0
  54. bmcgo/error_analyzer/unified_error_analyzer.py +359 -0
  55. bmcgo/error_cases/cases.yml +59 -0
  56. bmcgo/error_cases/cases_template_valid.json +71 -0
  57. bmcgo/error_cases/conanfile.py +58 -0
  58. bmcgo/frame.py +0 -4
  59. bmcgo/functional/analysis.py +18 -12
  60. bmcgo/functional/bmc_studio_action.py +21 -10
  61. bmcgo/functional/check.py +86 -42
  62. bmcgo/functional/conan_index_build.py +1 -1
  63. bmcgo/functional/config.py +22 -18
  64. bmcgo/functional/csr_build.py +63 -34
  65. bmcgo/functional/deploy.py +4 -3
  66. bmcgo/functional/diff.py +51 -34
  67. bmcgo/functional/full_component.py +16 -5
  68. bmcgo/functional/hpm_signer.py +484 -0
  69. bmcgo/functional/new.py +8 -2
  70. bmcgo/functional/schema_valid.py +111 -15
  71. bmcgo/functional/upgrade.py +6 -6
  72. bmcgo/misc.py +1 -0
  73. bmcgo/tasks/task_build_conan.py +27 -6
  74. bmcgo/tasks/task_build_rootfs_img.py +120 -83
  75. bmcgo/tasks/task_buildgppbin.py +30 -13
  76. bmcgo/tasks/task_buildhpm_ext4.py +5 -3
  77. bmcgo/tasks/task_download_buildtools.py +20 -11
  78. bmcgo/tasks/task_download_dependency.py +29 -20
  79. bmcgo/tasks/task_hpm_envir_prepare.py +32 -53
  80. bmcgo/tasks/task_packet_to_supporte.py +12 -4
  81. bmcgo/tasks/task_prepare.py +1 -1
  82. bmcgo/tasks/task_sign_and_pack_hpm.py +15 -7
  83. bmcgo/utils/component_version_check.py +4 -4
  84. bmcgo/utils/config.py +3 -0
  85. bmcgo/utils/fetch_component_code.py +148 -17
  86. bmcgo/utils/install_manager.py +2 -2
  87. bmcgo/utils/installations/base_installer.py +10 -27
  88. bmcgo/utils/installations/install_plans/studio.yml +3 -0
  89. bmcgo/utils/mapping_config_patch.py +5 -4
  90. bmcgo/utils/tools.py +49 -7
  91. {openubmc_bingo-0.6.45.dist-info → openubmc_bingo-0.6.99.dist-info}/METADATA +1 -1
  92. {openubmc_bingo-0.6.45.dist-info → openubmc_bingo-0.6.99.dist-info}/RECORD +95 -74
  93. bmcgo/tasks/download_buildtools_hm.py +0 -124
  94. {openubmc_bingo-0.6.45.dist-info → openubmc_bingo-0.6.99.dist-info}/WHEEL +0 -0
  95. {openubmc_bingo-0.6.45.dist-info → openubmc_bingo-0.6.99.dist-info}/entry_points.txt +0 -0
  96. {openubmc_bingo-0.6.45.dist-info → openubmc_bingo-0.6.99.dist-info}/top_level.txt +0 -0
@@ -10,14 +10,15 @@
10
10
  # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
11
11
  # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
12
12
  # See the Mulan PSL v2 for more details.
13
+ import json
13
14
  import os
14
15
  import re
15
16
  import shutil
16
17
  import subprocess
17
- from multiprocessing import Pool
18
+ from multiprocessing import Pool, Manager
18
19
  import patch_ng
19
20
  import yaml
20
- from git import Repo
21
+ from git import Repo, exc
21
22
 
22
23
  from bmcgo import errors
23
24
  from bmcgo import misc
@@ -47,6 +48,7 @@ class FetchComponentCode:
47
48
  f" -r {misc.conan_remote()} --only None 2>/dev/null"
48
49
  if misc.conan_v2():
49
50
  cmd = f"conan graph info --requires='{version_range}' --filter {component_name}"
51
+
50
52
  ret, output = subprocess.getstatusoutput(cmd)
51
53
  output = output.strip()
52
54
  if ret != 0 or not output:
@@ -113,15 +115,17 @@ class FetchComponentCode:
113
115
  log.info(f"{code_dir} 开始应用源码补丁{patch_file}")
114
116
  try:
115
117
  FetchComponentCode._apply_patches_direct(real_patch, patch_file, changed_files)
116
- except errors.BmcGoException:
117
- # 尝试还原文件修改
118
+ except errors.BmcGoException as e:
118
119
  for a_file, b_file in changed_files.items():
119
120
  cmd = f"git checkout -- {a_file}"
120
121
  tools.run_command(cmd, ignore_error=True)
121
122
  cmd = f"git checkout -- {b_file}"
122
123
  tools.run_command(cmd, ignore_error=True)
123
- cmd = "git am " + real_patch
124
- tools.run_command(cmd)
124
+ try:
125
+ cmd = "git am " + real_patch
126
+ tools.run_command(cmd)
127
+ except Exception as am_e:
128
+ raise RuntimeError(f"git am 恢复补丁 {patch_file} 失败") from am_e
125
129
  log.info(f"{code_dir} 应用源码补丁{patch_file}")
126
130
  os.chdir(cwd)
127
131
 
@@ -184,6 +188,88 @@ class FetchComponentCode:
184
188
 
185
189
  return revision, url
186
190
 
191
+ # --- 新增:MDS修补方案 1 (Install) ---
192
+ @staticmethod
193
+ def _try_mds_install_plan(conan_version, component_name):
194
+ """
195
+ 尝试使用 'conan install' 来获取 package_folder
196
+ """
197
+ log.info(f"MDS修补 (方案1: install): 正在尝试 {conan_version}...")
198
+ cmd_install = f"conan install --requires={conan_version} -r openubmc_dev\
199
+ --build=missing -pr profile.ini --format=json --output-folder=tmp"
200
+
201
+ command_result = tools.run_command(cmd_install, capture_output=True, ignore_error=True)
202
+ stdout = command_result.stdout.strip()
203
+ stderr = command_result.stderr.strip()
204
+
205
+ if command_result.returncode != 0 or not stdout:
206
+ log.warning(f"MDS修补 (方案1: install) 失败: 命令执行失败。 STDERR: {stderr}")
207
+ raise RuntimeError(f"Install plan failed (command error). stderr: {stderr}")
208
+
209
+ try:
210
+ result = json.loads(stdout)
211
+ nodes = result.get("graph", {}).get("nodes", {})
212
+ package_folder = None
213
+ for node in nodes.values():
214
+ if node.get("ref") and node.get("ref").startswith(conan_version):
215
+ package_folder = node.get("package_folder")
216
+ if package_folder:
217
+ break
218
+
219
+ if not package_folder:
220
+ log.warning(f"MDS修补 (方案1: install) 失败: 未在JSON中找到 package_folder。")
221
+ raise RuntimeError("Install plan failed (JSON parse).")
222
+
223
+ log.info(f"MDS修补 (方案1: install) 成功。 找到 package_folder: {package_folder}")
224
+ return package_folder # 成功
225
+ except Exception as json_err:
226
+ log.warning(f"MDS修补 (方案1: install) 失败: JSON解析错误。 {json_err}")
227
+ raise RuntimeError(f"Install plan failed (JSON parse).") from json_err
228
+
229
+ # --- 新增:MDS修补方案 2 (Download) ---
230
+ @staticmethod
231
+ def _try_mds_download_plan(conan_version, component_name):
232
+ """
233
+ 尝试使用 'conan download' (不带profile) 来获取 package_folder
234
+ """
235
+ log.warning(f"MDS修补 (方案1: install) 失败。 切换到 (方案2: download)...")
236
+ try:
237
+ cmd_download = f"conan download {conan_version} -r openubmc_dev --format=json"
238
+ log.info(f"MDS修补 (方案2: download): 执行: {cmd_download}")
239
+ command_result = tools.run_command(cmd_download, capture_output=True, ignore_error=True)
240
+ stdout = command_result.stdout.strip()
241
+ stderr = command_result.stderr.strip()
242
+
243
+ if command_result.returncode != 0 or not stdout:
244
+ log.error(f"MDS修补 (方案2: download) 失败: 命令执行失败。 STDERR: {stderr}")
245
+ raise RuntimeError(f"Download command failed. STDERR: {stderr}")
246
+
247
+ result = json.loads(stdout)
248
+ local_cache = result.get("Local Cache")
249
+ component_info = local_cache.get(conan_version)
250
+ revisions = component_info.get("revisions")
251
+ first_revision_id = next(iter(revisions))
252
+ first_revision_data = revisions[first_revision_id]
253
+ packages = first_revision_data.get("packages")
254
+ first_package_id = next(iter(packages))
255
+ full_pref = f"{conan_version}#{first_revision_id}:{first_package_id}"
256
+
257
+ cmd_cache_path = f"conan cache path {full_pref}"
258
+ log.info(f"MDS修补 (方案2: download): 执行: {cmd_cache_path}")
259
+ path_cmd_info = tools.run_command(cmd_cache_path, capture_output=True, ignore_error=True)
260
+
261
+ if path_cmd_info.returncode != 0 or not path_cmd_info.stdout:
262
+ log.error(f"MDS修补 (方案2: download) 失败: 'conan cache path' 失败。 STDERR: {path_cmd_info.stderr.strip()}")
263
+ raise RuntimeError(f"'conan cache path' 失败. STDERR: {path_cmd_info.stderr.strip()}")
264
+
265
+ package_folder = path_cmd_info.stdout.strip()
266
+ log.info(f"MDS修补 (方案2: download) 成功。 找到 package_folder: {package_folder}")
267
+ return package_folder # 成功
268
+
269
+ except Exception as download_e:
270
+ log.error(f"MDS修补 (方案2: download) 失败: {download_e}")
271
+ raise RuntimeError("Download plan failed.") from download_e
272
+
187
273
  def run(self):
188
274
  packages_to_fetch = dict()
189
275
  for component_name, package in self.packages.items():
@@ -201,14 +287,19 @@ class FetchComponentCode:
201
287
 
202
288
  process_count = min(len(packages_to_fetch), os.cpu_count())
203
289
  log.info("创建 %u 个进程拉取代码", process_count)
290
+
291
+ manager = Manager()
292
+ conan_lock = manager.Lock()
293
+
204
294
  pool = Pool(processes=process_count)
205
295
  for component_name, conan_version in packages_to_fetch.items():
206
- pool.apply_async(func=self.update_component_code, args=(component_name, conan_version),
296
+ pool.apply_async(func=self.update_component_code,
297
+ args=(component_name, conan_version, conan_lock),
207
298
  error_callback=process_err_cb)
208
299
  pool.close()
209
300
  pool.join()
210
301
 
211
- def update_component_code(self, component_name, conan_version):
302
+ def update_component_code(self, component_name, conan_version, conan_lock):
212
303
  """
213
304
  update component code by conan version
214
305
  """
@@ -219,9 +310,12 @@ class FetchComponentCode:
219
310
  version_split = re.split(r'[/, @]', conan_version)
220
311
  conan_dir = os.path.join(os.path.expanduser('~'), '.conan/data/', *version_split, 'export')
221
312
  conandata = os.path.join(conan_dir, 'conandata.yml')
222
- if not os.path.exists(conan_dir):
223
- conan_remote_list = tools.get_conan_remote_list(self.remote)
224
- tools.download_conan_recipes(conan_version, conan_remote_list)
313
+
314
+ with conan_lock:
315
+ if not os.path.exists(conan_dir):
316
+ conan_remote_list = tools.get_conan_remote_list(self.remote)
317
+ tools.download_conan_recipes(conan_version, conan_remote_list)
318
+
225
319
  if os.path.exists(conandata):
226
320
  self.__update_component_code_by_conandata(version_split[0], version_split[1], conandata)
227
321
  return
@@ -233,10 +327,12 @@ class FetchComponentCode:
233
327
  return
234
328
  log.error("conandata(%s) 和 conanfile(%s) 都没有找到", conandata, conanfile)
235
329
  else:
236
- conan_remote_list = tools.get_conan_remote_list(self.remote)
237
- tools.download_conan_recipes(conan_version, conan_remote_list)
238
- path_cmd = f"conan cache path {conan_version}"
239
- path_cmd_info = Tools().run_command(path_cmd, capture_output=True)
330
+ path_cmd_info = None
331
+ with conan_lock:
332
+ conan_remote_list = tools.get_conan_remote_list(self.remote)
333
+ tools.download_conan_recipes(conan_version, conan_remote_list)
334
+ path_cmd = f"conan cache path {conan_version}"
335
+ path_cmd_info = Tools().run_command(path_cmd, capture_output=True)
240
336
 
241
337
  version_split = re.split(r'[/, @]', conan_version)
242
338
  conan_dir = path_cmd_info.stdout.strip()
@@ -248,6 +344,41 @@ class FetchComponentCode:
248
344
  log.error("conandata(%s) 没有找到", conandata)
249
345
  log.info("更新组件 %s 代码到 %s 失败, 无法获取到 conan 信息", component_name,
250
346
  conan_version)
347
+ except exc.GitError as exp:
348
+ log.warning("Git 操作失败 (组件: %s): %s。 尝试MDS修补...", component_name, exp)
349
+ package_folder = None
350
+
351
+ with conan_lock:
352
+ try:
353
+ # --- 方案 1: install (优先) ---
354
+ package_folder = FetchComponentCode._try_mds_install_plan(conan_version, component_name)
355
+ except Exception as install_e:
356
+ # --- 方案 2: download (后备) ---
357
+ try:
358
+ package_folder = FetchComponentCode._try_mds_download_plan(conan_version, component_name)
359
+ except Exception as download_e:
360
+ # --- 两个方案都失败了 ---
361
+ log.error(f"MDS修补: 方案1 和 方案2 均失败 (组件: {component_name})。")
362
+ raise RuntimeError(f"MDS修补方案 'install' 和 'download' 均失败 (组件: {component_name})") from exp
363
+
364
+ # --- 复制步骤 (锁外) ---
365
+ if package_folder:
366
+ mds_src_path = f"{package_folder}/include"
367
+ if os.path.exists(mds_src_path):
368
+ src = mds_src_path
369
+ dest = os.path.abspath(f"{component_name}")
370
+ shutil.copytree(src, dest, dirs_exist_ok=True)
371
+ log.info(f"将组件 {component_name} 复制到 {dest}.")
372
+ else:
373
+ log.warning(f"MDS修补: 在 {package_folder} 中未找到 'include/mds'。")
374
+ else:
375
+ # 这种情况不应该发生,因为如果两个方案都失败了,上面会抛出异常
376
+ log.error(f"MDS修补失败 (组件: {component_name}): 未能获取 package_folder。")
377
+ raise exp # 重新抛出原始 GitError
378
+
379
+ # 清理 'install' 方案(如果成功)创建的 'tmp' 目录
380
+ shutil.rmtree(f"{self.target_dir}/tmp", ignore_errors=True)
381
+
251
382
  except Exception as exp:
252
- log.error("工作状态错误: %s", exp)
253
- log.error("更新组件代码到 %s 失败", conan_version)
383
+ log.error("工作状态错误 (组件: %s): %s", component_name, exp)
384
+ log.error("更新组件 %s 代码到 %s 失败", component_name, conan_version)
@@ -38,7 +38,7 @@ class InstallManager:
38
38
  def custom_install_plan_path(self):
39
39
  return self._custom_path / install_consts.PLUGIN_INSTALL_PLAN_PATH
40
40
 
41
- def init(self, app_name, operator, version, custom_path):
41
+ def init(self, app_name, version_range, custom_path):
42
42
  self._set_custom_path(custom_path)
43
43
 
44
44
  if app_name == install_consts.INSTALL_ALL:
@@ -54,7 +54,7 @@ class InstallManager:
54
54
  if not inst_type:
55
55
  raise ValueError(f"未配置 {wname}/{install_consts.PLAN_STEPS}/{install_consts.PLAN_INSTALL_TYPE}")
56
56
  inst = BaseInstaller.get_installer(inst_type)
57
- inst.init(plan, operator, version)
57
+ inst.init(plan, version_range)
58
58
  self._installers.setdefault(wname, []).append(inst)
59
59
 
60
60
  def show_versions(self):
@@ -86,11 +86,11 @@ class BaseInstaller(abc.ABC):
86
86
  raise ValueError(f"未定义的安装方法:{installer_type}")
87
87
  return installer_cls()
88
88
 
89
- def init(self, plan, operator, version):
89
+ def init(self, plan, version_range):
90
90
  self.parse_plan(plan)
91
91
 
92
92
  versions = self.get_versions()
93
- self.resolve_constraint(versions, operator, version)
93
+ self.resolve_constraint(versions, version_range)
94
94
 
95
95
  self.get_current_version()
96
96
 
@@ -113,39 +113,22 @@ class BaseInstaller(abc.ABC):
113
113
  return
114
114
  self.parse_custom_plan(plan)
115
115
 
116
- def resolve_constraint(self, versions, opt, ver):
116
+ def resolve_constraint(self, versions, version_range):
117
117
  if not versions:
118
118
  self.warning("当前没有可下载版本!")
119
119
  return
120
120
 
121
- if ver == install_consts.INSTALL_LATEST or not opt:
121
+ if install_consts.INSTALL_LATEST in version_range or not version_range:
122
122
  self._target_ver = versions[0]
123
123
  return
124
-
125
- pkg_ver = PkgVersion(ver)
124
+
125
+ import semver
126
126
  for avl_ver in versions:
127
- v = PkgVersion(avl_ver)
128
- if opt == ">=" and v >= pkg_ver:
129
- self._target_ver = v.origin
130
- break
131
- elif opt == "<=" and v <= pkg_ver:
132
- self._target_ver = v.origin
133
- break
134
- elif opt == "!=" and v != pkg_ver:
135
- self._target_ver = v.origin
127
+ if semver.satisfies(avl_ver, version_range):
128
+ self._target_ver = avl_ver
136
129
  break
137
- elif opt == "<" and v < pkg_ver:
138
- self._target_ver = v.origin
139
- break
140
- elif opt == ">" and v > pkg_ver:
141
- self._target_ver = v.origin
142
- break
143
- elif opt == "=" and v == pkg_ver:
144
- self._target_ver = v.origin
145
- break
146
- else:
147
- self.warning(f"没有找到匹配的版本:{self._pkg_name}{opt}{ver}")
148
- return
130
+ if not self._target_ver:
131
+ raise ValueError(f"没有找到匹配的版本:{self._pkg_name}{version_range}")
149
132
 
150
133
  def info(self, msg):
151
134
  self.logger and self.logger.info(f"[{self.type_name}] {msg}")
@@ -3,4 +3,7 @@ install_steps:
3
3
  - type: apt
4
4
  package_name: bmc-studio
5
5
  doc: https://www.openubmc.cn/marketplace/BMC%20Studio
6
+ - type: apt
7
+ package_name: cangjie-runtime
8
+ doc: https://cangjie-lang.cn/docs
6
9
 
@@ -128,7 +128,7 @@ def rename_json_prop(obj, array, depth, new_key):
128
128
  elif isinstance(obj, list) and array[depth] < len(obj):
129
129
  node = obj[array[depth]]
130
130
  if node is not None:
131
- remove_json_prop(node, array, depth + 1, new_key)
131
+ rename_json_prop(node, array, depth + 1, new_key)
132
132
 
133
133
 
134
134
  class MappingConfigPatch(Task):
@@ -351,7 +351,7 @@ class MappingConfigPatch(Task):
351
351
  target_uri = action.get("Uri")
352
352
  target_method = action.get("Method")
353
353
  if target is None or target_uri is None or target_method is None:
354
- log.error(f"属性变更场景,Target、Uri、Method参数必须存在")
354
+ log.info(f"属性变更场景,Target、Uri、Method参数必须存在")
355
355
  continue
356
356
  target_path = os.path.join(self.config_path, target)
357
357
  if not is_valid_path(target_path, self.config_path, True):
@@ -367,7 +367,7 @@ class MappingConfigPatch(Task):
367
367
  if flag:
368
368
  save_json_file(target_path, target_object)
369
369
  else:
370
- log.error(f"属性变更场景,没有找到Uri({target_uri})指定的配置")
370
+ log.info(f"属性变更场景,没有找到Uri({target_uri})指定的配置")
371
371
 
372
372
 
373
373
  def global_variables(self, global_variable):
@@ -411,7 +411,8 @@ class MappingConfigPatch(Task):
411
411
 
412
412
 
413
413
  def run(self):
414
- if not os.path.isdir(self.config_patch_path):
414
+ ret = self.tools.run_command(f"test -d {self.config_patch_path}", ignore_error=True, sudo=True)
415
+ if ret.returncode != 0:
415
416
  return
416
417
 
417
418
  # 给予权限方便对文件做变更
bmcgo/utils/tools.py CHANGED
@@ -67,7 +67,6 @@ class Tools():
67
67
  print_cnt = 0
68
68
 
69
69
  def __init__(self, log_name="bingo", log_file=None):
70
- os.makedirs(misc.CACHE_DIR, exist_ok=True)
71
70
  self.lock_file = os.path.join(misc.CACHE_DIR, "frame_lock")
72
71
  if log_file is None:
73
72
  self.log_name = os.path.join(misc.CACHE_DIR, f"{log_name}.log")
@@ -104,6 +103,8 @@ class Tools():
104
103
 
105
104
  @property
106
105
  def conan_data(self):
106
+ if misc.conan_v2():
107
+ return os.path.join(self.conan_home, "p")
107
108
  return os.path.join(self.conan_home, "data")
108
109
 
109
110
  @staticmethod
@@ -245,16 +246,19 @@ class Tools():
245
246
  pkg_name = pkg_info[0]
246
247
  has_version = len(pkg_info) > 1
247
248
  for sub in base_manifest.get(dependency_type, {}):
249
+ overwrite = sub.get("overwrite", False)
248
250
  sub_name = sub.get(misc.CONAN)
249
251
  sub_pkg_name = sub_name.split("/")[0]
250
252
  # 上下层具有相同组件名的组件
251
253
  if pkg_name == sub_pkg_name:
252
- if has_version:
254
+ if not has_version:
255
+ com_package[misc.CONAN] = sub_name
256
+ elif overwrite:
257
+ com_package[misc.CONAN] = name
258
+ else:
253
259
  raise errors.BmcGoException(
254
260
  "配置错误: 不允许删除平台组件或定制平台组件版本号{}".format(name)
255
261
  )
256
- else:
257
- com_package[misc.CONAN] = sub_name
258
262
  break
259
263
 
260
264
  @staticmethod
@@ -630,7 +634,7 @@ class Tools():
630
634
  self.run_command(f"chown {user_group} {img_path}", sudo=True)
631
635
 
632
636
  def get_studio_path(self):
633
- ret = self.run_command("whereis bmc_studio", sudo=True, ignore_error=True,
637
+ ret = self.run_command("whereis bmc_studio", sudo=False, ignore_error=True,
634
638
  command_echo=False, capture_output=True).stdout
635
639
  if not ret:
636
640
  return ""
@@ -676,7 +680,45 @@ class Tools():
676
680
  try:
677
681
  check = False if ignore_error else True
678
682
  if show_log:
679
- ret = subprocess.run(command, check=check, timeout=timeout)
683
+ # 使用Popen来同时处理实时输出和日志文件写入
684
+ process = subprocess.Popen(
685
+ command,
686
+ stdout=subprocess.PIPE,
687
+ stderr=subprocess.STDOUT, # 将stderr合并到stdout
688
+ universal_newlines=True,
689
+ bufsize=1 # 行缓冲
690
+ )
691
+
692
+ # 实时读取输出并同时显示和写入日志
693
+ output_lines = []
694
+ while True:
695
+ line = process.stdout.readline()
696
+ if not line and process.poll() is not None:
697
+ break
698
+ if line:
699
+ # 实时显示到控制台
700
+ self.log.info(line.strip())
701
+ # 同时写入日志文件
702
+ log_fd.write(line)
703
+ log_fd.flush()
704
+ output_lines.append(line)
705
+
706
+ # 等待进程结束
707
+ returncode = process.wait()
708
+ stdout_str = ''.join(output_lines)
709
+
710
+ # 创建类似subprocess.run的返回对象
711
+ ret = subprocess.CompletedProcess(
712
+ args=command,
713
+ returncode=returncode,
714
+ stdout=stdout_str,
715
+ stderr='' # 因为stderr合并到stdout了
716
+ )
717
+
718
+ # 检查返回码
719
+ if check and returncode != 0:
720
+ raise subprocess.CalledProcessError(returncode, command, output=stdout_str)
721
+
680
722
  elif capture_output:
681
723
  ret = subprocess.run(command, capture_output=capture_output, check=check, timeout=timeout, text=True)
682
724
  if ret.stdout:
@@ -786,7 +828,7 @@ class Tools():
786
828
  graph_file = os.path.join(tmpdir.name, "package.json")
787
829
  cmd = f"conan install --requires='{package}' {install_args}"
788
830
  cmd += f" -f json --out-file={graph_file} -of temp"
789
- self.run_command(cmd, ignore_error=False)
831
+ _ = self.run_command(cmd, show_log=True)
790
832
  return self.get_package_folder_from_graph_file(graph_file, package)
791
833
 
792
834
  def install_conan_package_to(self, package, install_args, outdir):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openubmc-bingo
3
- Version: 0.6.45
3
+ Version: 0.6.99
4
4
  Summary: Tools provided by openubmc
5
5
  Home-page: https://openubmc.cn
6
6
  Classifier: Programming Language :: Python :: 3