lbkit 0.8.5__tar.gz → 0.8.7__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.
- {lbkit-0.8.5/lbkit.egg-info → lbkit-0.8.7}/PKG-INFO +4 -2
- lbkit-0.8.7/lbkit/__init__.py +2 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/cli.py +6 -2
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/codegen.py +2 -1
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/ctype_defination.py +14 -14
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/public.c.mako +3 -3
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/build.py +9 -9
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/test.py +3 -3
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/misc.py +41 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/config.py +62 -6
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/executor.py +19 -4
- lbkit-0.8.7/lbkit/tasks/image_maker/make_image.py +17 -0
- lbkit-0.8.7/lbkit/tasks/image_maker/make_qemu_image.py +75 -0
- lbkit-0.8.7/lbkit/tasks/image_maker/make_rockchip_image.py +78 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/task.py +21 -3
- lbkit-0.8.7/lbkit/tasks/task_build_image.py +29 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/task_build_manifest.py +2 -24
- lbkit-0.8.7/lbkit/tasks/task_build_prepare.py +109 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/task_build_rootfs.py +117 -14
- lbkit-0.8.7/lbkit/tasks/task_download.py +143 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tools.py +8 -4
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/utils/env_detector.py +1 -1
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/utils/images/emmc.py +11 -6
- {lbkit-0.8.5 → lbkit-0.8.7/lbkit.egg-info}/PKG-INFO +4 -2
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit.egg-info/SOURCES.txt +6 -2
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit.egg-info/requires.txt +1 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/setup.py +1 -1
- lbkit-0.8.7/test/__init__.py +0 -0
- lbkit-0.8.7/test/test_config.py +66 -0
- lbkit-0.8.5/lbkit/__init__.py +0 -2
- lbkit-0.8.5/lbkit/tasks/task_build_image.py +0 -45
- lbkit-0.8.5/lbkit/tasks/task_build_prepare.py +0 -59
- lbkit-0.8.5/lbkit/tasks/task_test.py +0 -29
- lbkit-0.8.5/lbkit/tasks/test.py +0 -40
- {lbkit-0.8.5 → lbkit-0.8.7}/AUTHORS +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/LICENSE +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/MANIFEST.in +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/README.md +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/build_conan_parallel.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/ci_robot/__init__.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/ci_robot/gitee.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/__init__.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/idf_interface.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/renderer.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/client.c.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/client.h.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/interface.c.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/interface.introspect.xml.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/public.h.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/server.c.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/server.h.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/__init__.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/arg_parser.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/template/conanbase.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/template/deploy.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/errors.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/helper.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/lbkit.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/log.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/__init__.py +0 -0
- {lbkit-0.8.5/test → lbkit-0.8.7/lbkit/tasks/image_maker}/__init__.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/template/conanfile.py.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/template/rootfs.py.mako +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/utils/__init__.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/utils/images/__init__.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit.egg-info/dependency_links.txt +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit.egg-info/entry_points.txt +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/lbkit.egg-info/top_level.txt +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/setup.cfg +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/test/test_codegen.py +0 -0
- {lbkit-0.8.5 → lbkit-0.8.7}/test/test_helper.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: lbkit
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.7
|
|
4
4
|
Summary: Tools provided by litebmc.com
|
|
5
5
|
Home-page: https://www.litebmc.com
|
|
6
6
|
Author: xuhj@litebmc.com
|
|
@@ -21,12 +21,14 @@ Requires-Dist: requests
|
|
|
21
21
|
Requires-Dist: gitpython
|
|
22
22
|
Requires-Dist: inflection
|
|
23
23
|
Requires-Dist: meson>=1.4.0
|
|
24
|
+
Requires-Dist: psutil
|
|
24
25
|
Dynamic: author
|
|
25
26
|
Dynamic: author-email
|
|
26
27
|
Dynamic: classifier
|
|
27
28
|
Dynamic: description
|
|
28
29
|
Dynamic: description-content-type
|
|
29
30
|
Dynamic: home-page
|
|
31
|
+
Dynamic: license-file
|
|
30
32
|
Dynamic: requires-dist
|
|
31
33
|
Dynamic: summary
|
|
32
34
|
|
|
@@ -79,6 +79,8 @@ class Command(object):
|
|
|
79
79
|
"""
|
|
80
80
|
env = EnvDetector()
|
|
81
81
|
if env.component:
|
|
82
|
+
os.chdir(env.component.folder)
|
|
83
|
+
print(os.getcwd())
|
|
82
84
|
arg_parser = ArgParser.new()
|
|
83
85
|
build = BuildComponent(arg_parser, sys.argv[2:])
|
|
84
86
|
build.run()
|
|
@@ -101,6 +103,10 @@ class Command(object):
|
|
|
101
103
|
|
|
102
104
|
组件DT用例执行
|
|
103
105
|
"""
|
|
106
|
+
env = EnvDetector()
|
|
107
|
+
if not env.component:
|
|
108
|
+
raise Exception("The metadata/package.yml file was not detected, not a valid litebmc component.")
|
|
109
|
+
os.chdir(env.component.folder)
|
|
104
110
|
argv = sys.argv[2:]
|
|
105
111
|
build = TestComponent(argv)
|
|
106
112
|
build.run()
|
|
@@ -239,11 +245,9 @@ def main(args):
|
|
|
239
245
|
shutil.rmtree(misc.LOG_DIR, ignore_errors=True)
|
|
240
246
|
os.makedirs(misc.LOG_DIR, exist_ok=True)
|
|
241
247
|
def ctrl_c_handler(_, __):
|
|
242
|
-
print('You pressed Ctrl+C!')
|
|
243
248
|
sys.exit(-3)
|
|
244
249
|
|
|
245
250
|
def sigterm_handler(_, __):
|
|
246
|
-
print('Received SIGTERM!')
|
|
247
251
|
sys.exit(-4)
|
|
248
252
|
|
|
249
253
|
signal.signal(signal.SIGINT, ctrl_c_handler)
|
|
@@ -67,8 +67,9 @@ history_versions = {
|
|
|
67
67
|
"5.0": CodeGenHistory("lb_base/[>=0.8.1 <0.9.0]", "简化接口类名定义;简化枚举变量在接口间传递时的字符串定义", "0"),
|
|
68
68
|
"5.1": CodeGenHistory("lb_base/[>=0.8.3 <0.9.0]", "方法和信号添加保留字段用于功能扩展,同时设置请求和响应为空标志位", "8002"),
|
|
69
69
|
"5.2": CodeGenHistory("lb_base/[>=0.8.4 <0.9.0]", "支持校验数值边界、字符串正则以及数组匹配等规则", "8004"),
|
|
70
|
+
"5.3": CodeGenHistory("lb_base/[>=0.8.5 <0.9.0]", "支持32位操作系统", "8004"),
|
|
70
71
|
}
|
|
71
|
-
__version__=Version("5.
|
|
72
|
+
__version__=Version("5.3")
|
|
72
73
|
|
|
73
74
|
|
|
74
75
|
def version_check(ver_str: str):
|
|
@@ -93,9 +93,9 @@ class IdfValidator():
|
|
|
93
93
|
val_str = f"static const gchar *_items[] = {{"
|
|
94
94
|
val_str += '"' + '", "'.join(self.matches) + '", NULL'
|
|
95
95
|
else:
|
|
96
|
-
if self.ctype in ["int16", "int32", "int64"]:
|
|
96
|
+
if self.ctype in ["int16", "int32", "int64", "ssize"]:
|
|
97
97
|
val_str = f"static gint64 _items[] = {{"
|
|
98
|
-
elif self.ctype in ["uint8", "uint16", "uint32", "uint64"]:
|
|
98
|
+
elif self.ctype in ["uint8", "uint16", "uint32", "uint64", "size"]:
|
|
99
99
|
val_str = f"static guint64 _items[] = {{"
|
|
100
100
|
elif self.ctype in ["double"]:
|
|
101
101
|
val_str = f"static gdouble _items[] = {{"
|
|
@@ -784,17 +784,17 @@ CTYPE_OBJS = {
|
|
|
784
784
|
["gsize <arg_name>"],
|
|
785
785
|
["gsize *<arg_name>"],
|
|
786
786
|
[],
|
|
787
|
-
["<arg_out> =
|
|
788
|
-
["<arg_in> =
|
|
789
|
-
IntegerValidator("
|
|
787
|
+
["<arg_out> = g_variant_new_tsize(<arg_name>)"],
|
|
788
|
+
["<arg_in> = g_variant_get_tsize(<arg_name>)"],
|
|
789
|
+
IntegerValidator("size", 0xffff_ffff_ffff_ffff, 0)
|
|
790
790
|
),
|
|
791
791
|
"ssize": CTypeBase(
|
|
792
792
|
["gssize <arg_name>"],
|
|
793
793
|
["gssize *<arg_name>"],
|
|
794
794
|
[],
|
|
795
|
-
["<arg_out> =
|
|
796
|
-
["<arg_in> =
|
|
797
|
-
IntegerValidator("
|
|
795
|
+
["<arg_out> = g_variant_new_tssize(<arg_name>)"],
|
|
796
|
+
["<arg_in> = g_variant_get_tssize(<arg_name>)"],
|
|
797
|
+
IntegerValidator("ssize", 0x7fff_ffff_ffff_ffff, -(0x8000_0000_0000_0000), True)
|
|
798
798
|
),
|
|
799
799
|
"double": CTypeBase(
|
|
800
800
|
["gdouble <arg_name>"],
|
|
@@ -921,17 +921,17 @@ CTYPE_OBJS = {
|
|
|
921
921
|
["gsize n_<arg_name>" ,"<const>gssize *<arg_name>"],
|
|
922
922
|
["gsize *n_<arg_name>" ,"gssize **<arg_name>"],
|
|
923
923
|
["lb_free_p((void **)&<arg_name>)"],
|
|
924
|
-
["<arg_out> =
|
|
925
|
-
["<arg_in> =
|
|
926
|
-
IntegerArrayValidator("
|
|
924
|
+
["<arg_out> = lb_array_ssize_encode(<arg_name>, n_<arg_name>)"],
|
|
925
|
+
["<arg_in> = lb_array_ssize_decode(<arg_name>, &n_<arg_in>)"],
|
|
926
|
+
IntegerArrayValidator("ssize",0x7fff_ffff_ffff_ffff, -(0x8000_0000_0000_0000), True)
|
|
927
927
|
),
|
|
928
928
|
"array[size]": CTypeBase(
|
|
929
929
|
["gsize n_<arg_name>" ,"<const>gsize *<arg_name>"],
|
|
930
930
|
["gsize *n_<arg_name>" ,"gsize **<arg_name>"],
|
|
931
931
|
["lb_free_p((void **)&<arg_name>)"],
|
|
932
|
-
["<arg_out> =
|
|
933
|
-
["<arg_in> =
|
|
934
|
-
IntegerArrayValidator("
|
|
932
|
+
["<arg_out> = lb_array_size_encode(<arg_name>, n_<arg_name>)"],
|
|
933
|
+
["<arg_in> = lb_array_size_decode(<arg_name>, &n_<arg_in>)"],
|
|
934
|
+
IntegerArrayValidator("size", 0xffff_ffff_ffff_ffff, 0)
|
|
935
935
|
),
|
|
936
936
|
"array[double]": CTypeBase(
|
|
937
937
|
["gsize n_<arg_name>" ,"<const>gdouble *<arg_name>"],
|
|
@@ -526,7 +526,7 @@ static ${name}${dictionary.key} *${name}_lookup(const ${name} *dict, ${key_decla
|
|
|
526
526
|
}
|
|
527
527
|
|
|
528
528
|
const ${name}Real *dict_real = CONTAINER_OF(dict, ${name}Real, dict);
|
|
529
|
-
return (${name}${dictionary.key} *)g_hash_table_lookup(dict_real->_hash, GUINT_TO_POINTER(
|
|
529
|
+
return (${name}${dictionary.key} *)g_hash_table_lookup(dict_real->_hash, GUINT_TO_POINTER(key));
|
|
530
530
|
}
|
|
531
531
|
|
|
532
532
|
/**
|
|
@@ -547,7 +547,7 @@ static gboolean ${name}_insert(const ${name} *dict, ${key_declare}, ${name}${dic
|
|
|
547
547
|
% if dictionary.key_type in ["string", "object_path", "signature"]:
|
|
548
548
|
gboolean ret = g_hash_table_insert(dict_real->_hash, g_strdup(key), *value);
|
|
549
549
|
% else:
|
|
550
|
-
gboolean ret = g_hash_table_insert(dict_real->_hash, GUINT_TO_POINTER(
|
|
550
|
+
gboolean ret = g_hash_table_insert(dict_real->_hash, GUINT_TO_POINTER(key), *value);
|
|
551
551
|
% endif
|
|
552
552
|
if (ret) {
|
|
553
553
|
*value = NULL;
|
|
@@ -571,7 +571,7 @@ static gboolean ${name}_remove(const ${name} *dict, ${key_declare})
|
|
|
571
571
|
}
|
|
572
572
|
|
|
573
573
|
const ${name}Real *dict_real = CONTAINER_OF(dict, ${name}Real, dict);
|
|
574
|
-
return g_hash_table_remove(dict_real->_hash, GUINT_TO_POINTER(
|
|
574
|
+
return g_hash_table_remove(dict_real->_hash, GUINT_TO_POINTER(key));
|
|
575
575
|
}
|
|
576
576
|
|
|
577
577
|
/**
|
|
@@ -20,7 +20,6 @@ from lbkit.codegen.codegen import Version
|
|
|
20
20
|
|
|
21
21
|
tools = Tools("comp_build")
|
|
22
22
|
log = tools.log
|
|
23
|
-
cwd = os.getcwd()
|
|
24
23
|
lb_cwd = os.path.split(os.path.realpath(__file__))[0]
|
|
25
24
|
|
|
26
25
|
|
|
@@ -52,6 +51,7 @@ class DeployComponent():
|
|
|
52
51
|
|
|
53
52
|
class BuildComponent():
|
|
54
53
|
def __init__(self, args_parser: ArgumentParser, args=None):
|
|
54
|
+
self.cwd = os.getcwd()
|
|
55
55
|
self.deploy_success = True
|
|
56
56
|
self.options = args_parser.parse_args(args)
|
|
57
57
|
self.options.build_type = self.options.build_type.capitalize()
|
|
@@ -64,7 +64,7 @@ class BuildComponent():
|
|
|
64
64
|
self.verbose = False if self.options.summary else True
|
|
65
65
|
self.from_source = self.options.from_source
|
|
66
66
|
# 当前组件及其依赖将被部署到rootfs目录
|
|
67
|
-
self.rootfs_dir = os.path.join(cwd, ".temp", "rootfs")
|
|
67
|
+
self.rootfs_dir = os.path.join(self.cwd, ".temp", "rootfs")
|
|
68
68
|
shutil.rmtree(self.rootfs_dir, ignore_errors=True)
|
|
69
69
|
os.makedirs(self.rootfs_dir, exist_ok=True)
|
|
70
70
|
|
|
@@ -117,7 +117,7 @@ class BuildComponent():
|
|
|
117
117
|
return False
|
|
118
118
|
|
|
119
119
|
def gen_conaninfo(self):
|
|
120
|
-
package_yml = os.path.join(cwd, "metadata/package.yml")
|
|
120
|
+
package_yml = os.path.join(self.cwd, "metadata/package.yml")
|
|
121
121
|
if not os.path.isfile(package_yml):
|
|
122
122
|
raise FileNotFoundError("metadata/package.yml文件不存在")
|
|
123
123
|
# 验证失败时抛异常,此处不用处理,由外层处理
|
|
@@ -155,10 +155,10 @@ class BuildComponent():
|
|
|
155
155
|
self.base_cmd += f" -o {conan}/*:{k}={v}"
|
|
156
156
|
|
|
157
157
|
# 生成conan构建脚本
|
|
158
|
-
conanfile = os.path.join(cwd, "conanbase.py")
|
|
158
|
+
conanfile = os.path.join(self.cwd, "conanbase.py")
|
|
159
159
|
# 当git未跟踪conanfile.py时生成新的conanfile.py
|
|
160
160
|
if not self._is_conanfile_tracked:
|
|
161
|
-
conanfile = os.path.join(cwd, "conanfile.py")
|
|
161
|
+
conanfile = os.path.join(self.cwd, "conanfile.py")
|
|
162
162
|
|
|
163
163
|
# 使用litebmc.conanfile.mako模板生成基础litebmc公共conanfile
|
|
164
164
|
lookup = TemplateLookup(directories=os.path.join(lb_cwd, "template"))
|
|
@@ -210,8 +210,8 @@ class BuildComponent():
|
|
|
210
210
|
# import sys
|
|
211
211
|
# sys.exit(-1)
|
|
212
212
|
|
|
213
|
-
lockfile = os.path.join(cwd, ".temp", "conan.lock")
|
|
214
|
-
graphfile = os.path.join(cwd, ".temp", "graph.info")
|
|
213
|
+
lockfile = os.path.join(self.cwd, ".temp", "conan.lock")
|
|
214
|
+
graphfile = os.path.join(self.cwd, ".temp", "graph.info")
|
|
215
215
|
lock_cmd = f"conan lock create . {self.base_cmd} --lockfile-out={lockfile}"
|
|
216
216
|
tools.run(lock_cmd, capture_output=False)
|
|
217
217
|
graph_cmd = f"conan graph info . {self.base_cmd} -f json --lockfile={lockfile}"
|
|
@@ -232,7 +232,7 @@ class BuildComponent():
|
|
|
232
232
|
|
|
233
233
|
# 设置ROOTFS_DIR环境变量,为DT测试提供相对路径
|
|
234
234
|
os.environ["ROOTFS_DIR"] = self.rootfs_dir
|
|
235
|
-
os.chdir(cwd)
|
|
235
|
+
os.chdir(self.cwd)
|
|
236
236
|
|
|
237
237
|
def _validate_odf_object(self, name, obj):
|
|
238
238
|
properties = obj.get("properties")
|
|
@@ -276,7 +276,7 @@ class BuildComponent():
|
|
|
276
276
|
for root, _, files in os.walk(self.rootfs_dir):
|
|
277
277
|
for file in files:
|
|
278
278
|
file = os.path.join(root, file)
|
|
279
|
-
file = os.path.relpath(file, cwd)
|
|
279
|
+
file = os.path.relpath(file, self.cwd)
|
|
280
280
|
if not file.endswith(".yaml"):
|
|
281
281
|
log.debug(f"file {file} not endswith .yaml, skip validate")
|
|
282
282
|
continue
|
|
@@ -12,11 +12,11 @@ from lbkit.misc import Color
|
|
|
12
12
|
|
|
13
13
|
tool = Tools("comp_test")
|
|
14
14
|
log = tool.log
|
|
15
|
-
cwd = os.getcwd()
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
class TestComponent():
|
|
19
18
|
def __init__(self, args=None):
|
|
19
|
+
self.cwd = os.getcwd()
|
|
20
20
|
self.build_parser = ArgParser.new(True)
|
|
21
21
|
self.build_parser.parse_args(args) # 共享命令参数
|
|
22
22
|
self.origin_args = args
|
|
@@ -95,13 +95,13 @@ class TestComponent():
|
|
|
95
95
|
self._make_ld_library_path(build.rootfs_dir)
|
|
96
96
|
|
|
97
97
|
# 为确保路径正确,切换到初始路径
|
|
98
|
-
os.chdir(cwd)
|
|
98
|
+
os.chdir(self.cwd)
|
|
99
99
|
# 必须存在test.py时才测试
|
|
100
100
|
if not os.path.isfile("test.py"):
|
|
101
101
|
log.warn("Test file(test.py) not exist, skip test")
|
|
102
102
|
return 0
|
|
103
103
|
# 从test.py加载LiteBmcComponentTest实例并运行用命
|
|
104
|
-
loader = importlib.machinery.SourceFileLoader("test", os.path.join(cwd, "test.py"))
|
|
104
|
+
loader = importlib.machinery.SourceFileLoader("test", os.path.join(self.cwd, "test.py"))
|
|
105
105
|
mod = loader.load_module()
|
|
106
106
|
klass = getattr(mod, "LiteBmcComponentTest")
|
|
107
107
|
if klass is None:
|
|
@@ -5,6 +5,7 @@ import json
|
|
|
5
5
|
import yaml
|
|
6
6
|
import re
|
|
7
7
|
import requests
|
|
8
|
+
import fcntl
|
|
8
9
|
from string import Template
|
|
9
10
|
from colorama import Fore, Style
|
|
10
11
|
from jsonschema import validate, ValidationError
|
|
@@ -104,3 +105,43 @@ def load_yml_with_json_schema_validate(yml_file, default_json_schema_file, **kwa
|
|
|
104
105
|
raise PackageConfigException(f"validate {yml_file} failed, schema file is {schema_file}, "
|
|
105
106
|
f"message: {exc.message}\n"
|
|
106
107
|
"installing redhat.vscode-yaml plugin in vscode will help you write odf files")
|
|
108
|
+
|
|
109
|
+
class DownloadFlag():
|
|
110
|
+
@staticmethod
|
|
111
|
+
def clean(filename):
|
|
112
|
+
"""清理文件标记"""
|
|
113
|
+
filename += ".flag"
|
|
114
|
+
fp = open(filename, "a+")
|
|
115
|
+
fcntl.flock(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
116
|
+
fp.truncate(0)
|
|
117
|
+
fcntl.flock(fp, fcntl.F_UNLCK)
|
|
118
|
+
fp.close()
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def create(filename, url, new_hash):
|
|
122
|
+
"""创建文件标记"""
|
|
123
|
+
filename += ".flag"
|
|
124
|
+
fp = open(filename, "a+")
|
|
125
|
+
fcntl.flock(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
126
|
+
fp.seek(0, 0)
|
|
127
|
+
fp.truncate(0)
|
|
128
|
+
fp.write(url + "|" + new_hash)
|
|
129
|
+
fcntl.flock(fp, fcntl.F_UNLCK)
|
|
130
|
+
fp.close()
|
|
131
|
+
|
|
132
|
+
@staticmethod
|
|
133
|
+
def read(filename):
|
|
134
|
+
"""读取文件标记"""
|
|
135
|
+
filename += ".flag"
|
|
136
|
+
if not os.path.isfile(filename):
|
|
137
|
+
return "", ""
|
|
138
|
+
fp = open(filename, "a+")
|
|
139
|
+
fcntl.flock(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
140
|
+
fp.seek(0, 0)
|
|
141
|
+
content = fp.read()
|
|
142
|
+
fcntl.flock(fp, fcntl.F_UNLCK)
|
|
143
|
+
fp.close()
|
|
144
|
+
if len(content) == 0:
|
|
145
|
+
return "", ""
|
|
146
|
+
chunk = content.split("|")
|
|
147
|
+
return chunk[0], chunk[1]
|
|
@@ -15,6 +15,7 @@ class Config(object):
|
|
|
15
15
|
|
|
16
16
|
# 配置项
|
|
17
17
|
self.manifest = os.path.join(os.getcwd(), args.manifest)
|
|
18
|
+
self.manifest = os.path.realpath(self.manifest)
|
|
18
19
|
# 配置项目录
|
|
19
20
|
self.work_dir = os.path.dirname(self.manifest)
|
|
20
21
|
sys.path.append(self.work_dir)
|
|
@@ -32,13 +33,14 @@ class Config(object):
|
|
|
32
33
|
|
|
33
34
|
# 编译主机配置项
|
|
34
35
|
self.profile_build = args.profile_build
|
|
35
|
-
#
|
|
36
|
-
self.profile_host =
|
|
36
|
+
# 待所有参数确认后会调用refresh_profile_name设置正确的profile
|
|
37
|
+
self.profile_host = None
|
|
37
38
|
|
|
38
39
|
# conan.lock options
|
|
39
40
|
self.using_lockfile = args.lockfile
|
|
40
41
|
self.update_lockfile = args.update_lockfile
|
|
41
42
|
self.target = args.target
|
|
43
|
+
self.product = args.product
|
|
42
44
|
|
|
43
45
|
# 设置并创建构建所需目录
|
|
44
46
|
log.info("Work dir: %s", self.work_dir)
|
|
@@ -47,20 +49,22 @@ class Config(object):
|
|
|
47
49
|
self.output_path = os.path.join(self.temp_path, "output")
|
|
48
50
|
self.download_path = os.path.join(self.temp_path, "download")
|
|
49
51
|
self.tool_path = os.path.join(self.temp_path, "tools")
|
|
52
|
+
self.compiler_path = os.path.join(self.tool_path, "compiler")
|
|
50
53
|
# conan组件打包目录
|
|
51
54
|
self.conan_install = []
|
|
52
55
|
self.mnt_path = os.path.join(self.temp_path, "mnt_path")
|
|
53
56
|
self.rootfs_img = os.path.join(self.output_path, "rootfs.img")
|
|
54
57
|
# rootfs、uboot和kernel关键文件路径
|
|
55
|
-
self.uboot_bin = None
|
|
56
|
-
self.linux_bin = None
|
|
57
|
-
self.rootfs_tar = None
|
|
58
58
|
os.makedirs(self.temp_path, exist_ok=True)
|
|
59
59
|
os.makedirs(self.tool_path, exist_ok=True)
|
|
60
60
|
os.makedirs(self.output_path, exist_ok=True)
|
|
61
61
|
os.makedirs(self.download_path, exist_ok=True)
|
|
62
|
+
os.makedirs(self.compiler_path, exist_ok=True)
|
|
62
63
|
# 制作rootfs时需要strip镜像,所以需要单独指定stip路径
|
|
63
64
|
self.strip = "strip"
|
|
65
|
+
self.check_product()
|
|
66
|
+
# 刷新conan profile
|
|
67
|
+
self.refresh_profile_name()
|
|
64
68
|
|
|
65
69
|
@staticmethod
|
|
66
70
|
def target_list():
|
|
@@ -79,12 +83,12 @@ class Config(object):
|
|
|
79
83
|
parser = argparse.ArgumentParser(description="Build LiteBMC", formatter_class=argparse.RawTextHelpFormatter)
|
|
80
84
|
parser.add_argument("-m", "--manifest", help="Specify the manifest.yml, ignored when -l is specified.", default="./manifest.yml")
|
|
81
85
|
parser.add_argument("-s", "--from_source", help="Build from source", action="store_true")
|
|
82
|
-
parser.add_argument("-pr", "--profile", help="Apply the specified profile to the host machine", default="litebmc.ini")
|
|
83
86
|
parser.add_argument("-pr:b", "--profile_build", help="Apply the specified profile to the build machine", default="default")
|
|
84
87
|
parser.add_argument("-bt", "--build_type", type=str, choices=['debug', 'release', 'minsize'], help="Set the build type", default="debug")
|
|
85
88
|
parser.add_argument("-r", "--remote", help="specified conan server", default="litebmc")
|
|
86
89
|
parser.add_argument("-l", "--lockfile", help="using conan.lock", action="store_true")
|
|
87
90
|
parser.add_argument("-ul", "--update_lockfile", help="update conan.lock", action="store_true")
|
|
91
|
+
parser.add_argument("-p", "--product", help="product name, default product is `default`", default="default")
|
|
88
92
|
targets = Config.target_list()
|
|
89
93
|
target_help = "build target:"
|
|
90
94
|
for tgt, _ in targets.items():
|
|
@@ -102,6 +106,45 @@ class Config(object):
|
|
|
102
106
|
return default
|
|
103
107
|
return manifest
|
|
104
108
|
|
|
109
|
+
@staticmethod
|
|
110
|
+
def merge_cfg(dst, src):
|
|
111
|
+
"""合并两个配置项"""
|
|
112
|
+
# 如果源为None,则返回dst
|
|
113
|
+
if src is None:
|
|
114
|
+
return dst
|
|
115
|
+
# 如果目标是空的,直接返回src
|
|
116
|
+
if not dst:
|
|
117
|
+
return src
|
|
118
|
+
# 如果是数组、标量的直接覆盖dst即可,所以返回src
|
|
119
|
+
if not isinstance(dst, dict):
|
|
120
|
+
return src
|
|
121
|
+
# 如果目标非空,但源是空,直接返回目标
|
|
122
|
+
if not src:
|
|
123
|
+
return dst
|
|
124
|
+
if not isinstance(src, dict):
|
|
125
|
+
raise Exception(f"Merge configuration failed, source config {src} is not a dictionary")
|
|
126
|
+
output = {}
|
|
127
|
+
for key, val in src.items():
|
|
128
|
+
dst_val = dst.get(key)
|
|
129
|
+
output[key] = Config.merge_cfg(dst_val, val)
|
|
130
|
+
for key, val in dst.items():
|
|
131
|
+
# 已经合并过,即目标中存在,但源不存在,直接合并
|
|
132
|
+
if key in output:
|
|
133
|
+
continue
|
|
134
|
+
output[key] = val
|
|
135
|
+
return output
|
|
136
|
+
|
|
137
|
+
def get_product_config(self, key: str, default=None):
|
|
138
|
+
"""获取产品配置,注意,key只需要基于products/[name]/即可,如 toolchain"""
|
|
139
|
+
global_cfg = self.get_manifest_config(key, default)
|
|
140
|
+
key = f"products/{self.product}/{key}"
|
|
141
|
+
product_cfg = self.get_manifest_config(key, None)
|
|
142
|
+
if not product_cfg:
|
|
143
|
+
return global_cfg
|
|
144
|
+
if not global_cfg:
|
|
145
|
+
return product_cfg
|
|
146
|
+
return Config.merge_cfg(global_cfg, product_cfg)
|
|
147
|
+
|
|
105
148
|
def load_manifest(self):
|
|
106
149
|
"""加载manifest.yml并验证schema文件"""
|
|
107
150
|
template = {}
|
|
@@ -110,6 +153,19 @@ class Config(object):
|
|
|
110
153
|
template["download_path"] = os.path.join(self.download_path)
|
|
111
154
|
return load_yml_with_json_schema_validate(self.manifest, "/usr/share/litebmc/schema/pdf.v1.json", **template)
|
|
112
155
|
|
|
156
|
+
def check_product(self):
|
|
157
|
+
products = self.get_manifest_config("products", {})
|
|
158
|
+
if products.get(self.product):
|
|
159
|
+
return
|
|
160
|
+
log.error(f"Only the following products are supported:")
|
|
161
|
+
for key, _ in products.items():
|
|
162
|
+
log.info(" * " + key)
|
|
163
|
+
# todo: 待manifest.yml整改到位到删除下面注释
|
|
164
|
+
# raise Exception(f"Unkown product {self.product}")
|
|
165
|
+
|
|
166
|
+
def refresh_profile_name(self):
|
|
167
|
+
self.profile_host = self.get_product_config("toolchain/profile/name", "litebmc")
|
|
168
|
+
|
|
113
169
|
def set_build_type(self, value):
|
|
114
170
|
self.build_type = value
|
|
115
171
|
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import importlib
|
|
4
4
|
import os
|
|
5
5
|
import time
|
|
6
|
+
import traceback
|
|
6
7
|
import sys
|
|
8
|
+
import psutil
|
|
7
9
|
|
|
8
10
|
from multiprocessing import Process
|
|
9
11
|
from multiprocessing import Manager
|
|
@@ -138,6 +140,7 @@ def task_handler(te:TaskExecutor):
|
|
|
138
140
|
try:
|
|
139
141
|
ret = te.run()
|
|
140
142
|
except Exception as e:
|
|
143
|
+
traceback.print_exc()
|
|
141
144
|
log.error(f"Task {te.status_key} exit with exceiption: {str(e)}")
|
|
142
145
|
with status_lock:
|
|
143
146
|
status_dict[te.status_key] = TASK_STATUS_EXCEPT
|
|
@@ -158,6 +161,19 @@ class TaskInfo():
|
|
|
158
161
|
self.proc = proc
|
|
159
162
|
|
|
160
163
|
|
|
164
|
+
def kill_process_and_children(pid):
|
|
165
|
+
try:
|
|
166
|
+
parent = psutil.Process(pid)
|
|
167
|
+
except psutil.NoSuchProcess:
|
|
168
|
+
return
|
|
169
|
+
|
|
170
|
+
children = parent.children(recursive=True)
|
|
171
|
+
for child in children:
|
|
172
|
+
child.terminate()
|
|
173
|
+
|
|
174
|
+
parent.terminate()
|
|
175
|
+
|
|
176
|
+
|
|
161
177
|
def wait_tasks(tasks: dict[str, TaskInfo], alow_processes_alive=0):
|
|
162
178
|
while True:
|
|
163
179
|
new_results = {}
|
|
@@ -170,13 +186,12 @@ def wait_tasks(tasks: dict[str, TaskInfo], alow_processes_alive=0):
|
|
|
170
186
|
continue
|
|
171
187
|
with status_lock:
|
|
172
188
|
status = status_dict.get(ti.te.status_key)
|
|
173
|
-
if status == TASK_STATUS_EXCEPT:
|
|
189
|
+
if status == TASK_STATUS_EXCEPT or status == TASK_STATUS_FAILED:
|
|
174
190
|
killall = True
|
|
175
191
|
break
|
|
176
192
|
if killall:
|
|
177
193
|
for _, ti in tasks.items():
|
|
178
|
-
|
|
179
|
-
ti.proc.terminate()
|
|
194
|
+
kill_process_and_children(ti.proc.pid)
|
|
180
195
|
return None, False
|
|
181
196
|
tasks = new_results
|
|
182
197
|
if cnt > 0 and cnt >= alow_processes_alive:
|
|
@@ -242,7 +257,7 @@ class Executor(object):
|
|
|
242
257
|
target = config.target
|
|
243
258
|
succ = target_executor(config)
|
|
244
259
|
except Exception as e:
|
|
245
|
-
|
|
260
|
+
traceback.print_exc()
|
|
246
261
|
raise Exception(f"任务 {target} 执行失败")
|
|
247
262
|
if succ:
|
|
248
263
|
log.success(f"任务 {target} 执行成功")
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""环境准备"""
|
|
2
|
+
import os
|
|
3
|
+
from lbkit.tasks.config import Config
|
|
4
|
+
from lbkit.tasks.task import Task
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TaskMakeImage(Task):
|
|
8
|
+
def available(self):
|
|
9
|
+
return False
|
|
10
|
+
|
|
11
|
+
def run(self):
|
|
12
|
+
return
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
config = Config()
|
|
16
|
+
build = TaskMakeImage(config, "test")
|
|
17
|
+
build.run()
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""环境准备"""
|
|
2
|
+
import os
|
|
3
|
+
import tempfile
|
|
4
|
+
from lbkit.tasks.config import Config
|
|
5
|
+
from lbkit.log import Logger
|
|
6
|
+
from lbkit.utils.images.emmc import MakeImage as MekeEmmcImage
|
|
7
|
+
from lbkit.tasks.image_maker.make_image import TaskMakeImage
|
|
8
|
+
|
|
9
|
+
log = Logger("build_image")
|
|
10
|
+
|
|
11
|
+
src_cwd = os.path.split(os.path.realpath(__file__))[0]
|
|
12
|
+
|
|
13
|
+
class TaskMakeQemuImage(TaskMakeImage):
|
|
14
|
+
def __init__(self, config, name):
|
|
15
|
+
super().__init__(config, name)
|
|
16
|
+
self.chip_model = None
|
|
17
|
+
chip_model = self.config.get_product_config("chip_model")
|
|
18
|
+
if chip_model not in ["qemu_arm64"]:
|
|
19
|
+
return
|
|
20
|
+
self.chip_model = chip_model
|
|
21
|
+
self.uboot = self.config.get_product_config("flash/uboot")
|
|
22
|
+
self.kernel = self.config.get_product_config("flash/kernel")
|
|
23
|
+
self.rootfs = self.config.rootfs_img
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def _trans_to_blk_1m(cfg: str):
|
|
27
|
+
if cfg.endswith("K"):
|
|
28
|
+
return int(cfg[:-1]) / 1024
|
|
29
|
+
elif cfg.endswith("M"):
|
|
30
|
+
return int(cfg[:-1])
|
|
31
|
+
elif cfg.endswith("G"):
|
|
32
|
+
return int(cfg[:-1]) * 1024
|
|
33
|
+
|
|
34
|
+
def available(self):
|
|
35
|
+
if not self.chip_model:
|
|
36
|
+
return False
|
|
37
|
+
if self.config.get_product_config("flash/type") != "emmc":
|
|
38
|
+
return False
|
|
39
|
+
return True
|
|
40
|
+
|
|
41
|
+
def run(self):
|
|
42
|
+
"""任务入口"""
|
|
43
|
+
"""检查manifest文件是否满足schema格式描述"""
|
|
44
|
+
os.chdir(self.config.output_path)
|
|
45
|
+
|
|
46
|
+
mk = MekeEmmcImage(os.path.join(self.config.temp_path, "emmc_tmp_dir"))
|
|
47
|
+
rootfs_size = self.config.get_product_config("rootfs/size")
|
|
48
|
+
if rootfs_size:
|
|
49
|
+
mk.rootfs_blk_1m = self._trans_to_blk_1m(rootfs_size)
|
|
50
|
+
emmc_size = self.config.get_product_config("flash/size")
|
|
51
|
+
if emmc_size:
|
|
52
|
+
mk.size_1m = self._trans_to_blk_1m(emmc_size)
|
|
53
|
+
tmpdir = tempfile.TemporaryDirectory()
|
|
54
|
+
cmd = f"fuse2fs {self.rootfs} {tmpdir.name} -o fakeroot"
|
|
55
|
+
self.exec(cmd)
|
|
56
|
+
# 复制内核文件到boot/extlinux/Image
|
|
57
|
+
cmd = f"cp {self.kernel} {tmpdir.name}/boot/Image"
|
|
58
|
+
self.exec(cmd)
|
|
59
|
+
cmd = f"umount {tmpdir.name}"
|
|
60
|
+
self.exec(cmd)
|
|
61
|
+
mk.run(self.config.rootfs_img, "qemu.img")
|
|
62
|
+
cmd = 'cp /usr/share/litebmc/qemu.conf qemu.conf'
|
|
63
|
+
self.exec(cmd)
|
|
64
|
+
cmd = f'cp {self.uboot} u-boot.bin'
|
|
65
|
+
self.exec(cmd)
|
|
66
|
+
output_img = os.path.join(self.config.output_path, "litebmc_qemu.tar.gz")
|
|
67
|
+
cmd = f'tar -czf {output_img} -C . qemu.img u-boot.bin qemu.conf'
|
|
68
|
+
self.exec(cmd)
|
|
69
|
+
log.success(f"Create litebmc image {output_img} successfully")
|
|
70
|
+
return 0
|
|
71
|
+
|
|
72
|
+
if __name__ == "__main__":
|
|
73
|
+
config = Config()
|
|
74
|
+
build = TaskMakeQemuImage(config, "test")
|
|
75
|
+
build.run()
|