lbkit 0.9.11__tar.gz → 0.9.12__tar.gz

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 (76) hide show
  1. {lbkit-0.9.11 → lbkit-0.9.12}/MANIFEST.in +1 -0
  2. {lbkit-0.9.11/lbkit.egg-info → lbkit-0.9.12}/PKG-INFO +1 -1
  3. lbkit-0.9.12/lbkit/__commit__.py +1 -0
  4. lbkit-0.9.12/lbkit/__init__.py +2 -0
  5. lbkit-0.9.12/lbkit/codegen/.clang-format +70 -0
  6. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/codegen.py +76 -24
  7. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/template/client.c.mako +0 -2
  8. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/template/public.c.mako +0 -4
  9. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/template/server.c.mako +0 -4
  10. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/component/build.py +2 -1
  11. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/component/template/deploy.mako +2 -0
  12. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/task_build_rootfs.py +0 -2
  13. {lbkit-0.9.11 → lbkit-0.9.12/lbkit.egg-info}/PKG-INFO +1 -1
  14. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit.egg-info/SOURCES.txt +1 -0
  15. {lbkit-0.9.11 → lbkit-0.9.12}/test/test_codegen.py +99 -0
  16. {lbkit-0.9.11 → lbkit-0.9.12}/test/test_permission.py +0 -8
  17. lbkit-0.9.11/lbkit/__commit__.py +0 -1
  18. lbkit-0.9.11/lbkit/__init__.py +0 -2
  19. {lbkit-0.9.11 → lbkit-0.9.12}/AUTHORS +0 -0
  20. {lbkit-0.9.11 → lbkit-0.9.12}/README.md +0 -0
  21. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/build_conan_parallel.py +0 -0
  22. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/ci_robot/__init__.py +0 -0
  23. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/cli.py +0 -0
  24. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/__init__.py +0 -0
  25. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/ctype_defination.py +0 -0
  26. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/idf_interface.py +0 -0
  27. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/renderer.py +0 -0
  28. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/template/client.h.mako +0 -0
  29. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/template/interface.introspect.xml.mako +0 -0
  30. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/template/public.h.mako +0 -0
  31. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/codegen/template/server.h.mako +0 -0
  32. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/component/__init__.py +0 -0
  33. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/component/arg_parser.py +0 -0
  34. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/component/template/conanbase.mako +0 -0
  35. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/component/test.py +0 -0
  36. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/download_cache.py +0 -0
  37. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/errors.py +0 -0
  38. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/helper.py +0 -0
  39. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/lbkit.py +0 -0
  40. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/log.py +0 -0
  41. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/misc.py +0 -0
  42. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/skill/__init__.py +0 -0
  43. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/skill/constants.py +0 -0
  44. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/skill/manager.py +0 -0
  45. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/__init__.py +0 -0
  46. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/config.py +0 -0
  47. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/executor.py +0 -0
  48. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/image_maker/__init__.py +0 -0
  49. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/image_maker/make_image.py +0 -0
  50. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/image_maker/make_qemu_image.py +0 -0
  51. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/image_maker/make_rockchip_image.py +0 -0
  52. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/task.py +0 -0
  53. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/task_build_image.py +0 -0
  54. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/task_build_manifest.py +0 -0
  55. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/task_build_prepare.py +0 -0
  56. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/task_download.py +0 -0
  57. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/template/conanfile.py.mako +0 -0
  58. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tasks/template/rootfs.py.mako +0 -0
  59. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/tools.py +0 -0
  60. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/ukr/__init__.py +0 -0
  61. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/ukr/build.py +0 -0
  62. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/utils/__init__.py +0 -0
  63. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/utils/env_detector.py +0 -0
  64. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/utils/fakeroot.py +0 -0
  65. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/utils/images/__init__.py +0 -0
  66. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit/utils/images/emmc.py +0 -0
  67. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit.egg-info/dependency_links.txt +0 -0
  68. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit.egg-info/entry_points.txt +0 -0
  69. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit.egg-info/requires.txt +0 -0
  70. {lbkit-0.9.11 → lbkit-0.9.12}/lbkit.egg-info/top_level.txt +0 -0
  71. {lbkit-0.9.11 → lbkit-0.9.12}/setup.cfg +0 -0
  72. {lbkit-0.9.11 → lbkit-0.9.12}/setup.py +0 -0
  73. {lbkit-0.9.11 → lbkit-0.9.12}/test/__init__.py +0 -0
  74. {lbkit-0.9.11 → lbkit-0.9.12}/test/test_config.py +0 -0
  75. {lbkit-0.9.11 → lbkit-0.9.12}/test/test_helper.py +0 -0
  76. {lbkit-0.9.11 → lbkit-0.9.12}/test/test_skill.py +0 -0
@@ -1,3 +1,4 @@
1
1
  recursive-include lbkit/codegen/template *.mako
2
+ include lbkit/codegen/.clang-format
2
3
  recursive-include lbkit/tasks/template *.mako
3
4
  recursive-include lbkit/component/template *.mako
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lbkit
3
- Version: 0.9.11
3
+ Version: 0.9.12
4
4
  Summary: Tools provided by litebmc.com
5
5
  Home-page: https://www.litebmc.com
6
6
  Author: xuhj@litebmc.com
@@ -0,0 +1 @@
1
+ __commit__ = 'e5ea324'
@@ -0,0 +1,2 @@
1
+
2
+ __version__ = '0.9.12'
@@ -0,0 +1,70 @@
1
+ ---
2
+ # LiteBMC 代码生成默认格式化配置
3
+ # 参考 Linux 内核风格, 适配 GLib/C 项目
4
+ # BasedOnStyle: LLVM
5
+
6
+ AccessModifierOffset: -4
7
+ AlignAfterOpenBracket: Align
8
+ AlignConsecutiveAssignments: false
9
+ AlignConsecutiveDeclarations: false
10
+ AlignEscapedNewlines: Left
11
+ AlignOperands: true
12
+ AlignTrailingComments: false
13
+ AllowAllParametersOfDeclarationOnNextLine: false
14
+ AllowShortBlocksOnASingleLine: false
15
+ AllowShortCaseLabelsOnASingleLine: false
16
+ AllowShortFunctionsOnASingleLine: None
17
+ AllowShortIfStatementsOnASingleLine: false
18
+ AllowShortLoopsOnASingleLine: false
19
+ AlwaysBreakAfterDefinitionReturnType: None
20
+ AlwaysBreakAfterReturnType: None
21
+ AlwaysBreakBeforeMultilineStrings: false
22
+ BinPackArguments: true
23
+ BinPackParameters: true
24
+ BraceWrapping:
25
+ AfterControlStatement: false
26
+ AfterEnum: false
27
+ AfterFunction: true
28
+ AfterStruct: false
29
+ BeforeCatch: false
30
+ BeforeElse: false
31
+ IndentBraces: false
32
+ BreakBeforeBinaryOperators: None
33
+ BreakBeforeBraces: Custom
34
+ BreakBeforeTernaryOperators: false
35
+ BreakStringLiterals: false
36
+ ColumnLimit: 120
37
+ CommentPragmas: '^ IWYU pragma:'
38
+ ConstructorInitializerIndentWidth: 4
39
+ ContinuationIndentWidth: 4
40
+ Cpp11BracedListStyle: false
41
+ DerivePointerAlignment: false
42
+ FixNamespaceComments: false
43
+ IndentCaseLabels: false
44
+ IndentGotoLabels: false
45
+ IndentPPDirectives: None
46
+ IndentWidth: 4
47
+ IndentWrappedFunctionNames: false
48
+ KeepEmptyLinesAtTheStartOfBlocks: false
49
+ MaxEmptyLinesToKeep: 1
50
+ PointerAlignment: Right
51
+ ReflowComments: false
52
+ SortIncludes: false
53
+ SpaceAfterCStyleCast: false
54
+ SpaceBeforeAssignmentOperators: true
55
+ SpaceBeforeParens: ControlStatementsExceptForEachMacros
56
+ SpacesBeforeTrailingComments: 1
57
+ SpacesInAngles: false
58
+ SpacesInContainerLiterals: false
59
+ SpacesInCStyleCastParentheses: false
60
+ SpacesInParentheses: false
61
+ SpacesInSquareBrackets: false
62
+ TabWidth: 4
63
+ UseTab: Never
64
+ PenaltyBreakAssignment: 10
65
+ PenaltyBreakBeforeFirstCallParameter: 30
66
+ PenaltyBreakComment: 10
67
+ PenaltyBreakFirstLessLess: 0
68
+ PenaltyBreakString: 10
69
+ PenaltyExcessCharacter: 100
70
+ PenaltyReturnTypeOnItsOwnLine: 60
@@ -13,6 +13,8 @@ import re
13
13
  import json
14
14
  import yaml
15
15
  import argparse
16
+ import shutil
17
+ import subprocess
16
18
  from concurrent.futures import ProcessPoolExecutor, as_completed
17
19
  from lbkit.codegen.idf_interface import IdfInterface
18
20
 
@@ -68,45 +70,93 @@ class Version():
68
70
  return True
69
71
  return False
70
72
 
71
- # 历史自动生成版本号,计划用于用于生成代码稳定性测试
72
- # TODO: 支持生成代码稳定性测试,确保生成的代码一致性
73
+ # 历史自动生成版本号,用于管理代码生成版本与lb_base的兼容性
74
+ # 新增兼容性变更时添加条目,格式:"版本号": CodeGenHistory("lb_base依赖范围", "变更描述", "compatible_required值")
73
75
  history_versions = {
74
- "5.3": CodeGenHistory("lb_base/[>=0.8.5 <0.9.0]", "支持32位操作系统", "8004"),
75
76
  "5.4": CodeGenHistory("lb_base/[>=0.9.0 <0.10.0]", "LBInterface增加alias", "9000"),
76
77
  }
78
+
79
+ # 最新的版本号
77
80
  __version__=Version("5.4")
78
81
 
79
82
 
80
83
  def version_check(ver_str: str):
81
84
  if not re.match("^([0-9]|([1-9][0-9]*))\\.([0-9]|([1-9][0-9]*))$", ver_str):
82
85
  raise Exception(f"Version string {ver_str} not match with regex ^([0-9]|([1-9][0-9]*))\\.([0-9]|([1-9][0-9]*))$")
83
- if "x" not in ver_str:
86
+ if history_versions.get(ver_str):
87
+ return ver_str
88
+ if not history_versions:
84
89
  return ver_str
85
- if not history_versions.get(ver_str):
86
- log.error(f"Unkonw codegen version {ver_str}, supported versions:")
87
- for ver, msg in history_versions.items():
88
- log.error(f" {ver}: {msg}")
89
- raise Exception(f"Can't found the valid version for {ver_str}")
90
-
91
- def codegen_version_max():
92
- max_v = __version__
93
- for ver_str, _ in history_versions.items():
94
- next_ver = Version(ver_str)
95
- if next_ver.bt(max_v.str):
96
- max_v = next_ver
97
- return max_v.str
90
+ log.error(f"Unkonw codegen version {ver_str}, supported versions:")
91
+ for ver, msg in history_versions.items():
92
+ log.error(f" {ver}: {msg}")
93
+ raise Exception(f"Can't found the valid version for {ver_str}")
98
94
 
99
95
  def codegen_version_arg(parser: argparse.ArgumentParser, default=__version__.str, short_arg="-cv", full_arg="--codegen_version"):
100
- # 默认的自动生成工具版本号为2
101
- help=f'''must less than or equal to {codegen_version_max()}, default: {default}
102
-
103
- codegen versions:
104
- '''
96
+ help=f'''default: {default}'''
105
97
  for ver, detail in history_versions.items():
106
- help += f"- {ver}: compatible with {detail.lb_base}, {detail.description}\n"
98
+ help += f"\n - {ver}: compatible with {detail.lb_base}, {detail.description}"
107
99
  parser.add_argument(short_arg, full_arg, help=help, type=str, default=__version__.str)
108
100
 
109
101
 
102
+ def _find_clang_format_config(idf_file):
103
+ """查找 .clang-format 配置文件,优先级:IDF目录 > 组件目录 > toolkit默认"""
104
+ # 优先级1:IDF文件所在目录(接口仓库级配置)
105
+ idf_dir = os.path.dirname(os.path.realpath(idf_file))
106
+ candidate = os.path.join(idf_dir, ".clang-format")
107
+ if os.path.isfile(candidate):
108
+ return candidate
109
+ # 优先级2:组件源码目录(组件仓库级配置)
110
+ candidate = os.path.join(os.getcwd(), ".clang-format")
111
+ if os.path.isfile(candidate):
112
+ return candidate
113
+ # 优先级3:toolkit自带的默认配置
114
+ candidate = os.path.join(lb_cwd, ".clang-format")
115
+ if os.path.isfile(candidate):
116
+ return candidate
117
+ return None
118
+
119
+
120
+ def _format_generated_files(idf_file, directory, interface_alias):
121
+ """使用 clang-format 格式化生成的 .c 和 .h 文件"""
122
+ clang_format_bin = shutil.which("clang-format")
123
+ if not clang_format_bin:
124
+ log.warn("clang-format not found, skipping auto-formatting of generated files")
125
+ return
126
+
127
+ style_file = _find_clang_format_config(idf_file)
128
+ if not style_file:
129
+ log.warn("No .clang-format config found, skipping auto-formatting")
130
+ return
131
+
132
+ files_to_format = []
133
+ for ct in ["server", "client", "public"]:
134
+ ct_dir = os.path.join(directory, ct)
135
+ if not os.path.isdir(ct_dir):
136
+ continue
137
+ for ext in [".c", ".h"]:
138
+ fpath = os.path.join(ct_dir, interface_alias + ext)
139
+ if os.path.isfile(fpath):
140
+ files_to_format.append(fpath)
141
+
142
+ if not files_to_format:
143
+ return
144
+
145
+ log.debug(f"Formatting {len(files_to_format)} generated files with clang-format (style: {style_file})")
146
+ for fpath in files_to_format:
147
+ try:
148
+ subprocess.run(
149
+ [clang_format_bin, f"--style=file:{style_file}", "-i", fpath],
150
+ check=True, capture_output=True, timeout=30
151
+ )
152
+ except subprocess.TimeoutExpired:
153
+ log.warn(f"clang-format timed out on {fpath}, skipping")
154
+ except subprocess.CalledProcessError as e:
155
+ log.warn(f"clang-format failed on {fpath}: {e.stderr.strip() if e.stderr else 'unknown error'}")
156
+ except Exception as e:
157
+ log.warn(f"clang-format error on {fpath}: {str(e)}")
158
+
159
+
110
160
  def _gen_interface(idf_file, directory=".", code_type="all", codegen_version_str="5.4", log_level="NOTSET"):
111
161
  """模块级函数,供多进程调用"""
112
162
  directory = os.path.realpath(directory)
@@ -143,6 +193,8 @@ def _gen_interface(idf_file, directory=".", code_type="all", codegen_version_str
143
193
  with open(json_file, "w", encoding="utf-8") as fp:
144
194
  yaml.dump(data, fp, encoding='utf-8', allow_unicode=True)
145
195
 
196
+ _format_generated_files(idf_file, directory, interface.alias)
197
+
146
198
 
147
199
  class CodeGen(object):
148
200
  def __init__(self, args):
@@ -221,7 +273,7 @@ class CodeGen(object):
221
273
  raise ArgException(f"argument error, arguments -c/--cdf_file and -i/--idf_file are not set")
222
274
  if not os.path.isfile(intf_file):
223
275
  raise ArgException(f"argument -i/--idf_file: {args.idf_file} not exist")
224
- if self.codegen_version.bt(codegen_version_max()):
276
+ if self.codegen_version.bt(__version__.str):
225
277
  raise ArgException(f"argument -cv/--codegen_version: validate failed, must less than or equal to {__version__.str}")
226
278
  out_dir = os.path.join(os.getcwd(), args.directory)
227
279
  if not intf_file.endswith(".yaml"):
@@ -91,10 +91,8 @@ static LBInterface _${class_name}_interface = {
91
91
  .name = "${intf.name}",
92
92
  .properties = (LBProperty *)&${properties},
93
93
  .interface = NULL, /* load from usr/share/dbus-1/interfaces/${intf.name}.xml by lb_init */
94
- #ifdef LB_CODEGEN_BE_5_4
95
94
  .alias = "${class_name}",
96
95
  .object_template = "${intf.object_path}",
97
- #endif
98
96
  };
99
97
 
100
98
  static LBBase *_get_real_object(LBO *obj)
@@ -1045,7 +1045,6 @@ static LBBase *_get_real_object(LBO *obj)
1045
1045
  % endif
1046
1046
  <% prop_idx = 0 %>\
1047
1047
  % for prop in intf.properties:
1048
- #ifdef LB_CODEGEN_BE_5_2
1049
1048
  % if (prop.signature in ["b", "y", "n", "q", "i", "u", "x", "t", "d", "o", "s", "g", "ab", "ay", "an", "aq", "ai", "au", "ax", "at", "ad", "as", "ao", "ag"] and prop.val_validate()):
1050
1049
  static gboolean ${class_name}_check_${prop.name}_variant(LBO *obj, GVariant *value, GError **error)
1051
1050
  {
@@ -1080,7 +1079,6 @@ static gboolean ${class_name}_check_${prop.name}_variant(LBO *obj, GVariant *val
1080
1079
  }
1081
1080
 
1082
1081
  % endif
1083
- #endif
1084
1082
  static void ${class_name}_set_${prop.name}_variant(LBO *obj, GVariant *value)
1085
1083
  {
1086
1084
  g_assert(value && obj);
@@ -1126,7 +1124,6 @@ static ${class_name}_Properties _${class_name}_properties =
1126
1124
  .flags = ${prop.desc_flags},
1127
1125
  .set = ${class_name}_set_${prop.name}_variant,
1128
1126
  .get = _${class_name}_get_${prop.name}_variant,
1129
- #ifdef LB_CODEGEN_BE_5_2
1130
1127
  % if (prop.signature in ["b", "y", "n", "q", "i", "u", "x", "t", "d", "o", "s", "g", "ab", "ay", "an", "aq", "ai", "au", "ax", "at", "ad", "as", "ao", "ag"] and prop.val_validate()):
1131
1128
  .check = ${class_name}_check_${prop.name}_variant,
1132
1129
  % else:
@@ -1152,7 +1149,6 @@ static ${class_name}_Properties _${class_name}_properties =
1152
1149
  % endif
1153
1150
  % endif
1154
1151
  % endif
1155
- #endif
1156
1152
  },
1157
1153
  <% id = id + 1 %>\
1158
1154
  <% prop_idx = prop_idx + 1 %>\
@@ -93,17 +93,13 @@ static LBInterface _${class_name}_interface = {
93
93
  .name = "${intf.name}",
94
94
  .properties = (LBProperty *)&${properties},
95
95
  .interface = NULL, /* load from usr/share/dbus-1/interfaces/${intf.name} by lb_init */
96
- #ifdef LB_CODEGEN_BE_5_2
97
96
  % if intf.plugin.install_dir:
98
97
  .plugin_dir = "${intf.plugin.install_dir}",
99
98
  % else:
100
99
  .plugin_dir = "/opt/litebmc/plugins/${class_name}",
101
100
  % endif
102
- #endif
103
- #ifdef LB_CODEGEN_BE_5_4
104
101
  .alias = "${class_name}",
105
102
  .object_template = "${intf.object_path}",
106
- #endif
107
103
  };
108
104
 
109
105
  <% prop_idx = 0 %>\
@@ -105,7 +105,8 @@ class BuildComponent():
105
105
  for pkg_option in self.options.pkg_options:
106
106
  self.base_cmd += " -o " + pkg_option
107
107
  self.base_cmd += f" -o */*:codegen_version={self.options.codegen_version}"
108
- self.base_cmd += f" -o */*:compatible_required={self.codegen_version.info.lb_base_compatible_required}"
108
+ if self.codegen_version.info:
109
+ self.base_cmd += f" -o */*:compatible_required={self.codegen_version.info.lb_base_compatible_required}"
109
110
 
110
111
  @staticmethod
111
112
  def _check_conanfile_if_tracked():
@@ -66,7 +66,9 @@ class DeployConan(ConanFile):
66
66
  pass
67
67
 
68
68
  def configure(self):
69
+ % if codegen_version.info:
69
70
  self.options["lb_base"].compatible_required = "${codegen_version.info.lb_base_compatible_required}"
71
+ % endif
70
72
  % if len(pkg.get("requires", {})) > 0:
71
73
  % for conan in pkg["requires"].get("compile", []):
72
74
  % if conan.get("option") is not None:
@@ -65,8 +65,6 @@ class TaskClass(Task):
65
65
  chunk = line.split()
66
66
  if len(chunk) < 5:
67
67
  raise errors.PermissionFormatError(f"Permission format with error, line: {line}")
68
- if not chunk[0].startswith("/"):
69
- raise errors.PermissionFormatError(f"Permission file error, must begin with \"/\", get: {chunk[0]}")
70
68
  if (chunk[2] != "-" and not chunk[2].isnumeric()):
71
69
  raise errors.PermissionFormatError(f"Permission mode error, must is numeric or '-', get({chunk[2]})")
72
70
  if (chunk[3] != "-" and not chunk[3].isnumeric()) or (chunk[4] != "-" and not chunk[4].isnumeric()):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lbkit
3
- Version: 0.9.11
3
+ Version: 0.9.12
4
4
  Summary: Tools provided by litebmc.com
5
5
  Home-page: https://www.litebmc.com
6
6
  Author: xuhj@litebmc.com
@@ -20,6 +20,7 @@ lbkit.egg-info/entry_points.txt
20
20
  lbkit.egg-info/requires.txt
21
21
  lbkit.egg-info/top_level.txt
22
22
  lbkit/ci_robot/__init__.py
23
+ lbkit/codegen/.clang-format
23
24
  lbkit/codegen/__init__.py
24
25
  lbkit/codegen/codegen.py
25
26
  lbkit/codegen/ctype_defination.py
@@ -18,6 +18,7 @@ from lbkit import errors
18
18
  from lbkit.codegen.codegen import __version__ as codegen_version
19
19
  from lbkit.codegen.codegen import history_versions as codegen_history
20
20
  from lbkit.codegen.codegen import Version, CodeGen
21
+ from lbkit.codegen.codegen import _find_clang_format_config
21
22
  from lbkit.misc import load_json_schema
22
23
  from jsonschema import validate, ValidationError
23
24
 
@@ -977,5 +978,103 @@ class TestServerGetterClass(unittest.TestCase):
977
978
  body = self._assert_getter_in_source(server_h, "path")
978
979
  self.assertIn("g_variant_get_string", body)
979
980
 
981
+
982
+ class TestClangFormatClass(unittest.TestCase):
983
+ """测试代码生成后的 clang-format 自动格式化"""
984
+ intf_yaml = None
985
+ intf_out = None
986
+ tmp_dir = None
987
+
988
+ @classmethod
989
+ def setUpClass(cls) -> None:
990
+ cls.tmp_dir = tempfile.mktemp(prefix="clang_format_test", suffix=".output")
991
+ cls.intf_yaml = os.path.join(cls.tmp_dir, "test.yaml")
992
+ cls.intf_out = os.path.join(cls.tmp_dir, "output")
993
+ return super().setUpClass()
994
+
995
+ @classmethod
996
+ def tearDownClass(cls) -> None:
997
+ shutil.rmtree(cls.tmp_dir)
998
+ return super().tearDownClass()
999
+
1000
+ def setUp(self):
1001
+ shutil.rmtree(self.tmp_dir, ignore_errors=True)
1002
+ os.makedirs(self.tmp_dir)
1003
+ os.makedirs(self.intf_out)
1004
+ return super().setUp()
1005
+
1006
+ def _mk_interface(self):
1007
+ with open(self.intf_yaml, mode="w+") as fp:
1008
+ fp.write(f"# yaml-language-server: $schema={schema_dir}/idf.v2.json\n")
1009
+ fp.write("version: 1\n")
1010
+ fp.write("description: 测试clang-format格式化\n")
1011
+ fp.write("interface: com.litebmc.FormatTest\n")
1012
+ fp.write("properties:\n")
1013
+ fp.write(" - name: count\n")
1014
+ fp.write(" description: count\n")
1015
+ fp.write(" type: int32\n")
1016
+
1017
+ def test_clang_format_applied(self):
1018
+ """验证代码生成后文件存在且格式化正常(若 clang-format 可用)"""
1019
+ self._mk_interface()
1020
+ args = ["-d", self.intf_out, "-i", self.intf_yaml]
1021
+ gen = CodeGen(args)
1022
+ gen.run()
1023
+ for ct in ["server", "client", "public"]:
1024
+ h_file = os.path.join(self.intf_out, ct, "test.h")
1025
+ c_file = os.path.join(self.intf_out, ct, "test.c")
1026
+ self.assertTrue(os.path.isfile(h_file), f"{ct}/test.h should exist")
1027
+ self.assertTrue(os.path.isfile(c_file), f"{ct}/test.c should exist")
1028
+
1029
+ def test_config_lookup_idf_priority(self):
1030
+ """验证 .clang-format 查找优先级:IDF目录 > 组件目录 > toolkit默认"""
1031
+ self._mk_interface()
1032
+ # 在IDF目录创建 .clang-format
1033
+ idf_clang = os.path.join(self.tmp_dir, ".clang-format")
1034
+ with open(idf_clang, "w") as f:
1035
+ f.write("---\nBasedOnStyle: LLVM\n")
1036
+ result = _find_clang_format_config(self.intf_yaml)
1037
+ self.assertEqual(result, idf_clang)
1038
+
1039
+ def test_config_lookup_component_priority(self):
1040
+ """验证无IDF目录配置时回退到组件目录"""
1041
+ self._mk_interface()
1042
+ # 不在IDF目录创建,只在当前目录(组件目录)创建
1043
+ import unittest.mock
1044
+ comp_dir = os.path.join(self.tmp_dir, "component")
1045
+ os.makedirs(comp_dir)
1046
+ comp_clang = os.path.join(comp_dir, ".clang-format")
1047
+ with open(comp_clang, "w") as f:
1048
+ f.write("---\nBasedOnStyle: LLVM\n")
1049
+ with unittest.mock.patch("os.getcwd", return_value=comp_dir):
1050
+ result = _find_clang_format_config(self.intf_yaml)
1051
+ self.assertEqual(result, comp_clang)
1052
+
1053
+ def test_config_lookup_toolkit_default(self):
1054
+ """验证无任何自定义配置时回退到toolkit默认"""
1055
+ self._mk_interface()
1056
+ import unittest.mock
1057
+ # 使用空目录作为 CWD,确保没有 .clang-format
1058
+ empty_dir = os.path.join(self.tmp_dir, "empty")
1059
+ os.makedirs(empty_dir)
1060
+ with unittest.mock.patch("os.getcwd", return_value=empty_dir):
1061
+ result = _find_clang_format_config(self.intf_yaml)
1062
+ # toolkit 默认 .clang-format 应该存在
1063
+ self.assertIsNotNone(result)
1064
+ self.assertTrue(os.path.isfile(result))
1065
+
1066
+ def test_missing_clang_format_graceful(self):
1067
+ """验证 clang-format 不可用时 codegen 正常完成"""
1068
+ self._mk_interface()
1069
+ import unittest.mock
1070
+ with unittest.mock.patch("shutil.which", return_value=None):
1071
+ args = ["-d", self.intf_out, "-i", self.intf_yaml]
1072
+ gen = CodeGen(args)
1073
+ gen.run()
1074
+ for ct in ["server", "client", "public"]:
1075
+ h_file = os.path.join(self.intf_out, ct, "test.h")
1076
+ self.assertTrue(os.path.isfile(h_file), f"{ct}/test.h should exist even without clang-format")
1077
+
1078
+
980
1079
  if __name__ == "__main__":
981
1080
  unittest.main()
@@ -60,14 +60,6 @@ class TestDoPermissionBasic(unittest.TestCase):
60
60
  with self.assertRaises(errors.PermissionFormatError):
61
61
  task.do_permission(per)
62
62
 
63
- def test_path_not_absolute(self):
64
- """路径不以 / 开头应抛出 PermissionFormatError"""
65
- with tempfile.TemporaryDirectory() as tmpdir:
66
- per = _write_perm(tmpdir, ["lib/libfoo.so f 555 0 0 - - - - -"])
67
- task = _make_task()
68
- with self.assertRaises(errors.PermissionFormatError):
69
- task.do_permission(per)
70
-
71
63
  def test_invalid_mode(self):
72
64
  """mode 字段不合法应抛出 PermissionFormatError"""
73
65
  with tempfile.TemporaryDirectory() as tmpdir:
@@ -1 +0,0 @@
1
- __commit__ = '1f8eb04'
@@ -1,2 +0,0 @@
1
-
2
- __version__ = '0.9.11'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes