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.
Files changed (71) hide show
  1. {lbkit-0.8.5/lbkit.egg-info → lbkit-0.8.7}/PKG-INFO +4 -2
  2. lbkit-0.8.7/lbkit/__init__.py +2 -0
  3. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/cli.py +6 -2
  4. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/codegen.py +2 -1
  5. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/ctype_defination.py +14 -14
  6. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/public.c.mako +3 -3
  7. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/build.py +9 -9
  8. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/test.py +3 -3
  9. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/misc.py +41 -0
  10. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/config.py +62 -6
  11. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/executor.py +19 -4
  12. lbkit-0.8.7/lbkit/tasks/image_maker/make_image.py +17 -0
  13. lbkit-0.8.7/lbkit/tasks/image_maker/make_qemu_image.py +75 -0
  14. lbkit-0.8.7/lbkit/tasks/image_maker/make_rockchip_image.py +78 -0
  15. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/task.py +21 -3
  16. lbkit-0.8.7/lbkit/tasks/task_build_image.py +29 -0
  17. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/task_build_manifest.py +2 -24
  18. lbkit-0.8.7/lbkit/tasks/task_build_prepare.py +109 -0
  19. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/task_build_rootfs.py +117 -14
  20. lbkit-0.8.7/lbkit/tasks/task_download.py +143 -0
  21. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tools.py +8 -4
  22. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/utils/env_detector.py +1 -1
  23. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/utils/images/emmc.py +11 -6
  24. {lbkit-0.8.5 → lbkit-0.8.7/lbkit.egg-info}/PKG-INFO +4 -2
  25. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit.egg-info/SOURCES.txt +6 -2
  26. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit.egg-info/requires.txt +1 -0
  27. {lbkit-0.8.5 → lbkit-0.8.7}/setup.py +1 -1
  28. lbkit-0.8.7/test/__init__.py +0 -0
  29. lbkit-0.8.7/test/test_config.py +66 -0
  30. lbkit-0.8.5/lbkit/__init__.py +0 -2
  31. lbkit-0.8.5/lbkit/tasks/task_build_image.py +0 -45
  32. lbkit-0.8.5/lbkit/tasks/task_build_prepare.py +0 -59
  33. lbkit-0.8.5/lbkit/tasks/task_test.py +0 -29
  34. lbkit-0.8.5/lbkit/tasks/test.py +0 -40
  35. {lbkit-0.8.5 → lbkit-0.8.7}/AUTHORS +0 -0
  36. {lbkit-0.8.5 → lbkit-0.8.7}/LICENSE +0 -0
  37. {lbkit-0.8.5 → lbkit-0.8.7}/MANIFEST.in +0 -0
  38. {lbkit-0.8.5 → lbkit-0.8.7}/README.md +0 -0
  39. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/build_conan_parallel.py +0 -0
  40. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/ci_robot/__init__.py +0 -0
  41. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/ci_robot/gitee.py +0 -0
  42. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/__init__.py +0 -0
  43. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/idf_interface.py +0 -0
  44. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/renderer.py +0 -0
  45. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/client.c.mako +0 -0
  46. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/client.h.mako +0 -0
  47. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/interface.c.mako +0 -0
  48. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/interface.introspect.xml.mako +0 -0
  49. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/public.h.mako +0 -0
  50. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/server.c.mako +0 -0
  51. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/codegen/template/server.h.mako +0 -0
  52. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/__init__.py +0 -0
  53. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/arg_parser.py +0 -0
  54. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/template/conanbase.mako +0 -0
  55. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/component/template/deploy.mako +0 -0
  56. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/errors.py +0 -0
  57. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/helper.py +0 -0
  58. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/lbkit.py +0 -0
  59. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/log.py +0 -0
  60. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/__init__.py +0 -0
  61. {lbkit-0.8.5/test → lbkit-0.8.7/lbkit/tasks/image_maker}/__init__.py +0 -0
  62. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/template/conanfile.py.mako +0 -0
  63. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/tasks/template/rootfs.py.mako +0 -0
  64. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/utils/__init__.py +0 -0
  65. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit/utils/images/__init__.py +0 -0
  66. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit.egg-info/dependency_links.txt +0 -0
  67. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit.egg-info/entry_points.txt +0 -0
  68. {lbkit-0.8.5 → lbkit-0.8.7}/lbkit.egg-info/top_level.txt +0 -0
  69. {lbkit-0.8.5 → lbkit-0.8.7}/setup.cfg +0 -0
  70. {lbkit-0.8.5 → lbkit-0.8.7}/test/test_codegen.py +0 -0
  71. {lbkit-0.8.5 → lbkit-0.8.7}/test/test_helper.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: lbkit
3
- Version: 0.8.5
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
 
@@ -0,0 +1,2 @@
1
+
2
+ __version__ = '0.8.7'
@@ -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.1")
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> = g_variant_new_uint64(<arg_name>)"],
788
- ["<arg_in> = g_variant_get_uint64(<arg_name>)"],
789
- IntegerValidator("uint64", 0xffff_ffff_ffff_ffff, 0)
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> = g_variant_new_int64(<arg_name>)"],
796
- ["<arg_in> = g_variant_get_int64(<arg_name>)"],
797
- IntegerValidator("int64", 0x7fff_ffff_ffff_ffff, -(0x8000_0000_0000_0000), True)
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> = lb_array_int64_encode(<arg_name>, n_<arg_name>)"],
925
- ["<arg_in> = lb_array_int64_decode(<arg_name>, &n_<arg_in>)"],
926
- IntegerArrayValidator("int64",0x7fff_ffff_ffff_ffff, -(0x8000_0000_0000_0000), True)
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> = lb_array_uint64_encode(<arg_name>, n_<arg_name>)"],
933
- ["<arg_in> = lb_array_uint64_decode(<arg_name>, &n_<arg_in>)"],
934
- IntegerArrayValidator("uint64", 0xffff_ffff_ffff_ffff, 0)
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((guint64)key));
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((guint64)key), *value);
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((guint64)key));
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 = args.profile
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
- if ti.proc.is_alive():
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
- log.error(str(e))
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()