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,11 @@
1
+ #!/usr/bin/python3
2
+ # coding: utf-8
3
+ # Copyright (c) 2025 Huawei Technologies Co., Ltd.
4
+ # openUBMC is licensed under Mulan PSL v2.
5
+ # You can use this software according to the terms and conditions of the Mulan PSL v2.
6
+ # You may obtain a copy of Mulan PSL v2 at:
7
+ # http://license.coscl.org.cn/MulanPSL2
8
+ # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9
+ # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10
+ # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11
+ # See the Mulan PSL v2 for more details.
@@ -0,0 +1,53 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html lang="en">
4
+
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
7
+ <title>coverage report</title>
8
+ </head>
9
+
10
+ <body>
11
+
12
+ <table width="100%%" border=0 cellspacing=0 cellpadding=0>
13
+ <tr><td class="title">BMC - incremental code coverage report</td></tr>
14
+ <tr><td class="ruler"><img src="glass.png" width=3 height=6 alt=""></td></tr>
15
+
16
+ <tr>
17
+ <td width="100%%">
18
+ <table cellpadding=1 border=0 width="100%%">
19
+ <tr>
20
+ <td></td>
21
+ <td width="33%%" class="headerCovTableHead">UT covered</td>
22
+ <td width="33%%" class="headerCovTableHead">Total</td>
23
+ <td width="33%%" class="headerCovTableHead">Coverage</td>
24
+ </tr>
25
+ <tr>
26
+ <td class="headerItem">Incremental Lines:</td>
27
+ <td class="incrementalCoveredLines">%(cov_lines)s</td>
28
+ <td class="incrementalTotalLines">%(change_linenum)s</td>
29
+ <td class="incrementalLineCoverageRate">%(coverage)s %%</td>
30
+ </tr>
31
+ <tr><td><img src="glass.png" width=3 height=3 alt=""></td></tr>
32
+ </table>
33
+ </td>
34
+ </tr>
35
+
36
+ <tr><td class="ruler"><img src="glass.png" width=3 height=3 alt=""></td></tr>
37
+ </table>
38
+
39
+ <center>
40
+ <br>
41
+ <table width="100%%" cellpadding=1 cellspacing=1 border=0>
42
+ <tr>
43
+ <td width="60%%" class="tableHead">File </td>
44
+ <td width="40%%" class="tableHead">Uncovered Lines </td>
45
+ </tr>
46
+ %(uncover_trs)s
47
+ </table>
48
+ </center>
49
+ <br>
50
+
51
+
52
+ </body>
53
+ </html>
@@ -0,0 +1,464 @@
1
+ #!/usr/bin/python3
2
+ # coding: utf-8
3
+ # Copyright (c) 2025 Huawei Technologies Co., Ltd.
4
+ # openUBMC is licensed under Mulan PSL v2.
5
+ # You can use this software according to the terms and conditions of the Mulan PSL v2.
6
+ # You may obtain a copy of Mulan PSL v2 at:
7
+ # http://license.coscl.org.cn/MulanPSL2
8
+ # THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
9
+ # EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
10
+ # MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
11
+ # See the Mulan PSL v2 for more details.
12
+ import sys
13
+ import os
14
+ import re
15
+ import json
16
+ from html.parser import HTMLParser
17
+ import argparse
18
+ import functools
19
+ import fnmatch
20
+
21
+ from bmcgo.utils.tools import Tools
22
+
23
+ DOC_STRING = """
24
+ PURPOSE:
25
+ Calculate incremental coverage of git commits
26
+
27
+ USAGE:
28
+ ./incremental_cov.py <since>..<until> <monitor_c_files> <lcov_dir> <thresholdold>
29
+ example:
30
+ ./incremental_cov.py "227b032..79196ba" '["src/file"]' "coverage" 0.6 LTX--
31
+
32
+ WORK PROCESS:
33
+ get changed file list between <since> and <until> , filter by <monitor_c_files> options;
34
+ get changed lines per changed file;
35
+ based on <lcov_dir>, search .gcov.html per file, and get uncover lines;
36
+ create report file:ut_incremental_check_report.html and check <thresholdold> (cover lines/new lines).
37
+
38
+ coverage_exclude.json example:
39
+ {
40
+ "xxx": {
41
+ "LUA_EXCLUDED": [],
42
+ "C_EXCLUDED": []
43
+ }
44
+ }
45
+ """
46
+
47
+ tools = Tools()
48
+ log = tools.log
49
+
50
+ OUTPUT_DATA = "dt_result.json"
51
+
52
+ # 组件里需要解析mds获取component名字
53
+ FILE_WHITE_LIST = ["src"]
54
+
55
+
56
+ def open_file(file_name, mode="r", encoding=None, **kwargs):
57
+ # 尝试用不同编码方式解码该文件内容并打开
58
+ with open(file_name, "rb") as f:
59
+ context = f.read()
60
+ for encoding_item in ["UTF-8", "GBK", "ISO-8859-1", "GB2312"]:
61
+ try:
62
+ context.decode(encoding=encoding_item)
63
+ encoding = encoding_item
64
+ return open(file_name, mode=mode, encoding=encoding, **kwargs)
65
+ except UnicodeDecodeError as e:
66
+ pass
67
+ return open(file_name, mode=mode, encoding=encoding, **kwargs)
68
+
69
+
70
+ def num_to_percentage(num):
71
+ percentage = num * 100
72
+ return f"{percentage:.1f}%"
73
+
74
+
75
+ class GcovHTMLParser(HTMLParser):
76
+ def __init__(self):
77
+ super().__init__()
78
+ self.uncovers = []
79
+ self.covers = []
80
+ self.is_line_num = False
81
+ self.line_num = 0
82
+
83
+ def handle_starttag(self, tag, attrs):
84
+ if tag == "span":
85
+ for a in attrs:
86
+ if a == ("class", "lineNum"):
87
+ self.is_line_num = True
88
+ if a == ("class", "lineNoCov"):
89
+ self.uncovers.append(self.line_num)
90
+ if a == ("class", "lineCov"):
91
+ self.covers.append(self.line_num)
92
+
93
+ def handle_data(self, data):
94
+ if self.is_line_num:
95
+ try:
96
+ self.line_num = int(data)
97
+ except Exception as e:
98
+ self.line_num = -1
99
+
100
+ def handle_endtag(self, tag):
101
+ if tag == "span":
102
+ self.is_line_num = False
103
+
104
+
105
+ class IncrementalCov(object):
106
+ def __init__(self, since_until, component_name, lcov_dir, threshold, coverage_exclude):
107
+ self.since, self.until = since_until.split("..")
108
+ self.component_name = component_name
109
+ self.lcov_dir = lcov_dir
110
+ self.threshold = float(threshold)
111
+ self.coverage_exclude = coverage_exclude
112
+ if not os.path.exists(self.lcov_dir):
113
+ os.makedirs(self.lcov_dir)
114
+
115
+ @functools.cached_property
116
+ def src_root_dir(self):
117
+ ret = tools.run_command("git rev-parse --show-toplevel", capture_output=True, command_echo=False)
118
+ if ret.returncode != 0:
119
+ return os.getcwd()
120
+
121
+ return ret.stdout.strip()
122
+
123
+ def is_file_matched(self, file_name, suffix_list):
124
+ # 校验传入的文件参数是否在设定的匹配路径下
125
+ for f in FILE_WHITE_LIST:
126
+ if file_name.startswith(f) and os.path.splitext(file_name)[1][1:] in suffix_list:
127
+ return True
128
+ return False
129
+
130
+ def get_lua_cov_map(self, path_list):
131
+ # 获取lua代码的校验字典
132
+ covers = {}
133
+ uncovers = {}
134
+ # 如果未覆盖到lua文件则返回空字典,path_list[1]为.out文件路径
135
+ if not os.path.exists(path_list[1]):
136
+ return covers, uncovers
137
+ whole_lines = self.parse_data(path_list[0])
138
+ check_list = self.parse_check_data(path_list[1])
139
+ for key, value_list in whole_lines.items():
140
+ value_check_list = check_list[key]
141
+ temp_uncovers = []
142
+ temp_covers = []
143
+ index = 0
144
+ for _ in value_list:
145
+ if value_list[index] == 0 and value_check_list[index] == 1:
146
+ temp_uncovers.append(index + 1)
147
+ elif value_list[index] != 0 and value_check_list[index] == 1:
148
+ temp_covers.append(index + 1)
149
+ index = index + 1
150
+ covers[key] = temp_covers
151
+ uncovers[key] = temp_uncovers
152
+
153
+ return covers, uncovers
154
+
155
+ def parse_data(self, file_path):
156
+ # 解析lua覆盖率的统计文件
157
+ lines = []
158
+ whole_lines = {}
159
+ with open(file_path, "r") as file:
160
+ for line in file:
161
+ lines.append(line.strip())
162
+ num_calculate = 1
163
+ file_locator = "init"
164
+ for line in lines:
165
+ if num_calculate % 2 == 1:
166
+ file_start = line.find("src")
167
+ file_locator = line[file_start:]
168
+ num_calculate += 1
169
+ else:
170
+ lines_cov = [int(num) for num in line.split() if num.isdigit()]
171
+ whole_lines[file_locator] = lines_cov
172
+ num_calculate += 1
173
+ return whole_lines
174
+
175
+ def parse_check_data(self, file_path):
176
+ # 解析lua覆盖率的过滤文件
177
+ lines = []
178
+ check_list = {}
179
+ with open(file_path, "r") as file:
180
+ for line in file:
181
+ lines.append(line.strip())
182
+ num_calculate = 1
183
+ file_locator = "init"
184
+ for line in lines:
185
+ if num_calculate % 2 == 1:
186
+ file_start = line.find("src")
187
+ file_locator = line[file_start:]
188
+ num_calculate += 1
189
+ else:
190
+ lines_cov = [int(num) for num in line.split() if num.isdigit()]
191
+ check_list[file_locator] = lines_cov
192
+ num_calculate += 1
193
+ return check_list
194
+
195
+ def get_excluded_files(self):
196
+ if not os.path.isfile(self.coverage_exclude):
197
+ return []
198
+
199
+ try:
200
+ with open(self.coverage_exclude, "r") as file:
201
+ excluded_data = json.load(file)
202
+ except json.JSONDecodeError:
203
+ log.info(f"Failed to decode JSON from file: {self.coverage_exclude}")
204
+ return []
205
+
206
+ # 展平排除文件列表
207
+ excluded_files = []
208
+ if self.component_name in excluded_data:
209
+
210
+ for file_list in excluded_data[self.component_name].values():
211
+ excluded_files.extend(file_list)
212
+ return excluded_files
213
+
214
+ def get_src(self, suffix_list):
215
+ # 获取节点间的变动文件
216
+ ret = tools.run_command(
217
+ f"git diff --name-only {self.since} {self.until}", capture_output=True, command_echo=False
218
+ )
219
+
220
+ if ret.returncode != 0:
221
+ log.info(f"error: git diff failed! err={ret.stderr}")
222
+
223
+ file_list = ret.stdout.split("\n")
224
+ src_files = []
225
+ for f in file_list:
226
+ if self.is_file_matched(f, suffix_list):
227
+ src_files.append(f)
228
+
229
+ # 获取需要排除的文件
230
+ excluded_list = self.get_excluded_files()
231
+
232
+ # 过滤掉排除的文件
233
+ filtered_files = [f for f in src_files if f not in excluded_list]
234
+
235
+ return filtered_files
236
+
237
+ def get_change(self, src_files):
238
+ # self.since, self.until
239
+ # 获取变动文件的change行
240
+ changes = {}
241
+ for f in src_files:
242
+ # commit中已删除文件不做统计
243
+ file_path = os.path.join(self.src_root_dir, f)
244
+ if not os.path.isfile(file_path):
245
+ continue
246
+ output, _ = tools.pipe_command(
247
+ [f"git log --oneline {self.since}..{self.until} {f}", "awk '{print $1}'"],
248
+ capture_output=True,
249
+ command_echo=False,
250
+ )
251
+ commits = [commit for commit in output.split("\n") if commit]
252
+
253
+ cmds = [f"git blame -f {f}"]
254
+ for commit in commits:
255
+ cmds.append(f"grep -E '({commit})'")
256
+ cmds.append("awk -F' *|)' '{print $7}'")
257
+
258
+ output, _ = tools.pipe_command(cmds, capture_output=True, command_echo=False)
259
+ changes[f] = [int(i) for i in output.split("\n") if i.isdigit()]
260
+
261
+ return changes
262
+
263
+ def get_ghp(self, f):
264
+ f = os.path.basename(f)
265
+ located_file = f + ".gcov.html"
266
+ # 以下是为了能通过点击行号跳转到对应的代码行,为原html文件的未覆盖的代码行添加一个tag
267
+ gcovfile = self.find_and_return_file_path(located_file)
268
+ if not os.path.exists(gcovfile):
269
+ log.info("*.gcov.html does not exits!")
270
+ return None
271
+
272
+ ghp = GcovHTMLParser()
273
+ ghp.feed(open_file(gcovfile, "r").read())
274
+
275
+ return ghp
276
+
277
+ def get_lcov_data(self, changes):
278
+ # self.lcov_dir
279
+ uncovers = {}
280
+ lcov_changes = {}
281
+ for f, lines in changes.items():
282
+ ghp = self.get_ghp(f)
283
+ if not ghp:
284
+ uncovers[f] = lines
285
+ lcov_changes[f] = lines
286
+ continue
287
+
288
+ # set创造一个不重复的集合
289
+ lcov_changes[f] = sorted(list(set(ghp.uncovers + ghp.covers) & set(lines)))
290
+ uncov_lines = list(set(ghp.uncovers) & set(lines))
291
+ if len(uncov_lines) != 0:
292
+ uncovers[f] = sorted(uncov_lines)
293
+ ghp.close()
294
+
295
+ return lcov_changes, uncovers
296
+
297
+ def get_lua_cov_data(self, changes, path):
298
+ path_list = [
299
+ os.path.join(path, "luacov.stats.out"),
300
+ os.path.join(path, "luacov.stats.filter"),
301
+ ]
302
+ lua_covers_map, lua_uncovers_map = self.get_lua_cov_map(path_list)
303
+ uncovers = {}
304
+ lua_changes = {}
305
+ for f, lines in changes.items():
306
+ if f not in lua_covers_map and f not in lua_uncovers_map:
307
+ lua_changes[f] = lines
308
+ uncovers[f] = lines
309
+ continue
310
+ lua_changes[f] = sorted(list(set(lua_uncovers_map[f] + lua_covers_map[f]) & set(lines)))
311
+ uncov_lines = list(set(lua_uncovers_map[f]) & set(lines))
312
+ if len(uncov_lines) != 0:
313
+ uncovers[f] = sorted(uncov_lines)
314
+ return lua_changes, uncovers
315
+
316
+ def find_and_return_file_path(self, filename):
317
+ for root, _, files in os.walk(self.lcov_dir, topdown=True):
318
+ for name in files:
319
+ if fnmatch.fnmatch(name, filename):
320
+ file_path = os.path.join(root, name)
321
+ return file_path
322
+ return ""
323
+
324
+ def prepare_uncover_trs(self, path):
325
+ if os.path.exists(path):
326
+ s = ""
327
+ p = re.compile(r'^<span class="lineNum">\s*(?P<num>\d+)\s*</span>')
328
+ for line in open_file(path, "r").readlines():
329
+ ps = p.search(line)
330
+ if ps:
331
+ s += '<a name="%s">' % ps.group("num") + line + "</a>"
332
+ else:
333
+ s += line
334
+ open(path, "w").write(s)
335
+
336
+ def create_uncover_trs(self, uncovers):
337
+ """
338
+ 返回:tr_format格式的 html table
339
+ 通过对全量报告生成的gcov.html文件解析,生成html格式的增量覆盖率的table
340
+ """
341
+
342
+ tr_format = """
343
+ <tr>
344
+ <td class="coverFile"><a href="%(f_ref_path)s.gcov.html">%(file)s</a></td>
345
+ <td class="coverFile">%(uncov_lines)s </td>
346
+ </tr>
347
+
348
+ """
349
+ trs = ""
350
+ for f, v in uncovers.items():
351
+ f = os.path.basename(f)
352
+ located_file = f + ".gcov.html"
353
+ # 以下是为了能通过点击行号跳转到对应的代码行,为原html文件的未覆盖的代码行添加一个tag
354
+ gcovfile = self.find_and_return_file_path(located_file)
355
+ self.prepare_uncover_trs(gcovfile)
356
+
357
+ data = {
358
+ "file": f,
359
+ "uncov_lines": ", ".join([f'<a href="{f}.gcov.html#{i}">{i}</a>' for i in v]),
360
+ "f_ref_path": f,
361
+ }
362
+ trs += tr_format % data
363
+
364
+ return trs
365
+
366
+ def create_report(self, changes, uncovers, type_name):
367
+ change_linenum, uncov_linenum = 0, 0
368
+ for _, v in changes.items():
369
+ change_linenum += len(v)
370
+ for _, v in uncovers.items():
371
+ uncov_linenum += len(v)
372
+
373
+ cov_linenum = change_linenum - uncov_linenum
374
+ coverage = round(cov_linenum * 1.0 / change_linenum if change_linenum > 0 else 1, 4)
375
+ script_dir = os.path.split(os.path.realpath(__file__))[0]
376
+ if type_name == "c":
377
+ template = open(os.path.join(script_dir, "c_incremental_cov_report.template"), "r").read()
378
+ data = {
379
+ "cov_lines": cov_linenum,
380
+ "change_linenum": change_linenum,
381
+ "coverage": coverage * 100,
382
+ "uncover_trs": self.create_uncover_trs(uncovers),
383
+ }
384
+ with open(os.path.join(self.lcov_dir, "c_incremental_coverage_report.html"), "w+") as f:
385
+ f.write(template % data)
386
+ if coverage < self.threshold:
387
+ log.info(f"{type_name} incremental coverage less than {num_to_percentage(self.threshold)}")
388
+ return coverage, change_linenum, cov_linenum
389
+
390
+ def calculate_cov(self):
391
+ # main function
392
+ result_path = os.path.join(self.lcov_dir, OUTPUT_DATA)
393
+
394
+ c_cov_match = ["c", "cpp"]
395
+ lua_cov_match = ["lua"]
396
+
397
+ c_src_files = self.get_src(c_cov_match)
398
+ lua_src_files = self.get_src(lua_cov_match)
399
+
400
+ c_changes = self.get_change(c_src_files)
401
+ lua_changes = self.get_change(lua_src_files)
402
+
403
+ c_lcov_changes, c_uncovered_lines = self.get_lcov_data(c_changes)
404
+ lua_lcov_changes, lua_uncovered_lines = self.get_lua_cov_data(lua_changes, self.lcov_dir)
405
+
406
+ c_cov_rate, c_change_linenum, c_cov_linenum = self.create_report(c_lcov_changes, c_uncovered_lines, "c")
407
+ lua_cov_rate, lua_change_linenum, lua_cov_linenum = self.create_report(
408
+ lua_lcov_changes, lua_uncovered_lines, "lua"
409
+ )
410
+
411
+ if c_change_linenum + lua_change_linenum == 0:
412
+ total_rate = 1
413
+ else:
414
+ total_rate = (c_cov_linenum + lua_cov_linenum) / (c_change_linenum + lua_change_linenum)
415
+ coverage_data = {
416
+ "incremental_coverage": num_to_percentage(total_rate),
417
+ "incremental_coverage_detail": {
418
+ "c_incremental_coverage": num_to_percentage(c_cov_rate),
419
+ "lua_incremental_coverage": num_to_percentage(lua_cov_rate),
420
+ "total_incremental_coverage": num_to_percentage(total_rate),
421
+ "c_change_lines": c_lcov_changes,
422
+ "c_uncovered_lines": c_uncovered_lines,
423
+ "lua_change_lines": lua_lcov_changes,
424
+ "lua_uncovered_lines": lua_uncovered_lines,
425
+ },
426
+ }
427
+ with open(result_path, "r", encoding="utf-8") as file:
428
+ data = json.load(file)
429
+ data[self.component_name].update(coverage_data)
430
+ with open(result_path, "w", encoding="utf-8") as file:
431
+ json.dump(data, file, indent=4)
432
+ return (
433
+ num_to_percentage(total_rate),
434
+ num_to_percentage(c_cov_rate),
435
+ num_to_percentage(lua_cov_rate),
436
+ )
437
+
438
+
439
+ if __name__ == "__main__":
440
+ if len(sys.argv) == 1:
441
+ log.info(__doc__)
442
+ sys.exit(0)
443
+ parser = argparse.ArgumentParser(description="manual to this script")
444
+ # 默认统计HEAD和HEAD~之间的增量覆盖率
445
+ parser.add_argument("--since_until", type=str, default="HEAD~..HEAD")
446
+ parser.add_argument("--module", type=str, default=None)
447
+ parser.add_argument("--lcov_dir", type=str, default=None)
448
+ parser.add_argument("--threshold", type=float, default=0.8)
449
+ parser.add_argument("--coverage_exclude", type=str, default="coverage_exclude.json")
450
+ args = parser.parse_args()
451
+ log.info(f"args.since_until={args.since_until}")
452
+ log.info(f"args.module={args.module}")
453
+ log.info(f"args.lcov_dir={args.lcov_dir}")
454
+ log.info(f"args.threshold={args.threshold}")
455
+ log.info(f"args.coverage_exclude={args.coverage_exclude}")
456
+ total_coverage, c_coverage, lua_coverage = IncrementalCov(
457
+ args.since_until,
458
+ args.module,
459
+ args.lcov_dir,
460
+ args.threshold,
461
+ args.coverage_exclude,
462
+ ).calculate_cov()
463
+
464
+ log.info(f"incremental coverage is {total_coverage, c_coverage, lua_coverage}.")
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/python3
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
+ import os
13
+ import shutil
14
+ import stat
15
+
16
+ from mako.lookup import TemplateLookup
17
+
18
+ from bmcgo.component.package_info import InfoComp
19
+ from bmcgo.component.component_helper import ComponentHelper
20
+ from bmcgo.codegen.c.helper import Helper
21
+ from bmcgo.logger import Logger
22
+ from bmcgo.bmcgo_config import BmcgoConfig
23
+ from bmcgo import misc
24
+
25
+ log = Logger("deploy")
26
+
27
+ cwd_script = os.path.split(os.path.realpath(__file__))[0]
28
+ DT_DEPENDENCIES = {
29
+ "dtframeforlua": "dtframeforlua", # 目前定义在部分组件的service.json
30
+ "luaunit": "luaunit/3.2",
31
+ "luacov": "luacov/[>=0.16.2]",
32
+ "luafilesystem": "luafilesystem/1.8.0.B022",
33
+ }
34
+
35
+
36
+ class DeployComp():
37
+ def __init__(self, bconfig: BmcgoConfig, info: InfoComp = None):
38
+ self.info: InfoComp = info
39
+ self.bconfig = bconfig
40
+ self.folder = bconfig.component.folder
41
+ os.chdir(self.folder)
42
+ self.temp_path = os.path.join(self.folder, "temp")
43
+
44
+ def get_dt_dependencies(self):
45
+ user_channel = ComponentHelper.get_user_channel(self.info.stage)
46
+ # DT专用的依赖,只在部署时添加
47
+ dependencies = []
48
+ lua_run_deps = [DT_DEPENDENCIES.get("luaunit")]
49
+ # 只有lua需要添加依赖
50
+ if not os.path.isdir("test_package") and self.info.coverage:
51
+ lua_run_deps.append(DT_DEPENDENCIES.get("luacov"))
52
+ lua_run_deps.append(DT_DEPENDENCIES.get("luafilesystem"))
53
+ for dep in lua_run_deps:
54
+ for build_dep in self.info.build_dependencies:
55
+ if build_dep.startswith(dep.split("/", -1)[0]):
56
+ dep = build_dep
57
+ break
58
+ if "@" not in dep:
59
+ dep += user_channel
60
+ dependencies.append(dep)
61
+
62
+ dependencies += self.info.test_dependencies
63
+ return dependencies
64
+
65
+ def gen_conanfile(self):
66
+ dependencies = [f"{self.info.name}/{self.info.version}{self.info.channel}"]
67
+ if self.info.build_type == "dt":
68
+ dependencies += self.get_dt_dependencies()
69
+
70
+ # 构建虚拟deploy组件,生成conanfile.py文件
71
+ lookup = TemplateLookup(directories=os.path.join(cwd_script, "template"))
72
+ template = lookup.get_template("conanfile.deploy.py.mako")
73
+ conanfile = template.render(lookup=lookup, pkg=self.info, dependencies=dependencies)
74
+ file_handler = os.fdopen(os.open("conanfile.py", os.O_WRONLY | os.O_CREAT | os.O_TRUNC,
75
+ stat.S_IWUSR | stat.S_IRUSR), 'w')
76
+ file_handler.write(conanfile)
77
+ file_handler.close()
78
+
79
+ def run(self):
80
+ # 生成虚拟deploy组件,仅用于安装
81
+ deploy_conan = os.path.join(self.temp_path, ".deploy")
82
+ os.makedirs(deploy_conan, exist_ok=True)
83
+ os.chdir(deploy_conan)
84
+ self.gen_conanfile()
85
+
86
+ # 安装依赖制品到install目录
87
+ install_path = os.path.join(self.temp_path, ".deploy", ".install")
88
+ log.info("安装所有依赖到目录 %s", install_path)
89
+ shutil.rmtree(install_path, ignore_errors=True)
90
+ cmd = [misc.CONAN, "install"]
91
+ append_cmd = ("%s -if=%s -g deploy" % (self.info.cmd_base, install_path))
92
+ append_cmd = append_cmd.replace(self.info.package, self.info.channel)
93
+ cmd += append_cmd.split()
94
+ cmd.append("--build=missing")
95
+ log.success("运行部署命令: %s", " ".join(cmd))
96
+ Helper.run(cmd)
97
+ # 复制制品到rootfs目录
98
+ rootfs_path = self.temp_path
99
+ log.info("复制所有依赖到目录 %s", rootfs_path)
100
+ os.makedirs(rootfs_path, exist_ok=True)
101
+ for sub_dir in os.listdir(install_path):
102
+ dir_path = os.path.join(install_path, sub_dir)
103
+ if os.path.isfile(dir_path):
104
+ os.unlink(dir_path)
105
+ continue
106
+ for file in os.listdir(dir_path):
107
+ source = os.path.join(dir_path, file)
108
+ cmd = ["/usr/bin/cp", "-arf", source, rootfs_path]
109
+ Helper.run(cmd)
110
+ shutil.rmtree(install_path, ignore_errors=True)