lbkit 0.6.0__tar.gz → 0.6.2__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 (58) hide show
  1. {lbkit-0.6.0/lbkit.egg-info → lbkit-0.6.2}/PKG-INFO +3 -3
  2. lbkit-0.6.2/lbkit/__init__.py +2 -0
  3. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/build_conan_parallel.py +12 -3
  4. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/ci_robot/gitee.py +4 -0
  5. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/component/build.py +4 -1
  6. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/component/template/conanbase.mako +13 -3
  7. lbkit-0.6.2/lbkit/integration/build_image.py +49 -0
  8. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/integration/build_manifest.py +24 -0
  9. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/integration/build_prepare.py +1 -1
  10. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/integration/build_rootfs.py +32 -79
  11. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/integration/config.py +23 -6
  12. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/integration/task.py +3 -11
  13. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/misc.py +5 -2
  14. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/tools.py +5 -2
  15. lbkit-0.6.2/lbkit/utils/images/__init__.py +2 -0
  16. lbkit-0.6.2/lbkit/utils/images/emmc.py +109 -0
  17. {lbkit-0.6.0 → lbkit-0.6.2/lbkit.egg-info}/PKG-INFO +3 -3
  18. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit.egg-info/SOURCES.txt +3 -0
  19. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit.egg-info/requires.txt +2 -2
  20. {lbkit-0.6.0 → lbkit-0.6.2}/setup.py +1 -1
  21. lbkit-0.6.0/lbkit/integration/build_image.py +0 -89
  22. {lbkit-0.6.0 → lbkit-0.6.2}/AUTHORS +0 -0
  23. {lbkit-0.6.0 → lbkit-0.6.2}/LICENSE +0 -0
  24. {lbkit-0.6.0 → lbkit-0.6.2}/MANIFEST.in +0 -0
  25. {lbkit-0.6.0 → lbkit-0.6.2}/README.md +0 -0
  26. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/ci_robot/__init__.py +0 -0
  27. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/cli.py +0 -0
  28. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/__init__.py +0 -0
  29. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/codegen.py +0 -0
  30. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/ctype_defination.py +0 -0
  31. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/idf_interface.py +0 -0
  32. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/renderer.py +0 -0
  33. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/template/client.c.mako +0 -0
  34. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/template/client.h.mako +0 -0
  35. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/template/interface.c.mako +0 -0
  36. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/template/interface.introspect.xml.mako +0 -0
  37. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/template/public.c.mako +0 -0
  38. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/template/public.h.mako +0 -0
  39. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/template/server.c.mako +0 -0
  40. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/codegen/template/server.h.mako +0 -0
  41. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/component/__init__.py +0 -0
  42. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/component/arg_parser.py +0 -0
  43. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/component/template/deploy.mako +0 -0
  44. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/component/test.py +0 -0
  45. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/errors.py +0 -0
  46. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/helper.py +0 -0
  47. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/integration/__init__.py +0 -0
  48. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/integration/template/conanfile.py.mako +0 -0
  49. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/lbkit.py +0 -0
  50. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit/log.py +0 -0
  51. {lbkit-0.6.0/lbkit → lbkit-0.6.2/lbkit/utils}/__init__.py +0 -0
  52. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit.egg-info/dependency_links.txt +0 -0
  53. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit.egg-info/entry_points.txt +0 -0
  54. {lbkit-0.6.0 → lbkit-0.6.2}/lbkit.egg-info/top_level.txt +0 -0
  55. {lbkit-0.6.0 → lbkit-0.6.2}/setup.cfg +0 -0
  56. {lbkit-0.6.0 → lbkit-0.6.2}/test/__init__.py +0 -0
  57. {lbkit-0.6.0 → lbkit-0.6.2}/test/test_codegen.py +0 -0
  58. {lbkit-0.6.0 → lbkit-0.6.2}/test/test_helper.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lbkit
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: Tools provided by litebmc.com
5
5
  Home-page: https://www.litebmc.com
6
6
  Author: xuhj@litebmc.com
@@ -14,12 +14,12 @@ License-File: AUTHORS
14
14
  Requires-Dist: pyyaml
15
15
  Requires-Dist: colorama
16
16
  Requires-Dist: mako
17
- Requires-Dist: node-semver==0.6.1
17
+ Requires-Dist: node-semver>=0.6.1
18
18
  Requires-Dist: jsonschema
19
19
  Requires-Dist: conan
20
20
  Requires-Dist: requests
21
21
  Requires-Dist: gitpython
22
22
  Requires-Dist: inflection
23
- Requires-Dist: meson==1.4.0
23
+ Requires-Dist: meson>=1.4.0
24
24
 
25
25
  build and code generate tools
@@ -0,0 +1,2 @@
1
+
2
+ __version__ = '0.6.2'
@@ -1,6 +1,7 @@
1
1
  """任务基础类"""
2
2
  import os
3
3
  import json
4
+ import tempfile
4
5
  from queue import Queue
5
6
  from threading import Thread
6
7
  from lbkit.log import Logger
@@ -84,15 +85,16 @@ class BuildConanParallel(object):
84
85
  cmd += " --build=missing"
85
86
  cmd += f" --lockfile={self.lockfile}"
86
87
  try:
87
- log.info(f">>>> build {cp.ref} start")
88
+ logfile = f"{misc.LOG_DIR}/conan_{cp.name}.log"
89
+ log.info(f">>>> build {cp.ref} start, logfile: {logfile}")
88
90
  log.debug(f">>>> {cmd}")
89
- tools.exec(cmd, echo_cmd=False, log_name=f"{misc.LOG_DIR}/conan_{cp.name}.log")
91
+ tools.exec(cmd, echo_cmd=False, log_name=logfile)
90
92
  log.success(f"<<<< build {cp.ref} finished")
91
93
  except Exception as e:
92
94
  self.exception = e
93
95
  self.queue.put(cp)
94
96
 
95
- def build(self):
97
+ def _build(self):
96
98
  with open(self.graphinfo, "r") as fp:
97
99
  grapth = json.load(fp)
98
100
  nodes = grapth.get("graph", {}).get("nodes", {})
@@ -195,3 +197,10 @@ class BuildConanParallel(object):
195
197
  dep.building = False
196
198
  dep.binary_exist = True
197
199
 
200
+
201
+ def build(self):
202
+ cwd = os.getcwd()
203
+ tmp = tempfile.TemporaryDirectory()
204
+ os.chdir(tmp.name)
205
+ self._build()
206
+ os.chdir(cwd)
@@ -78,6 +78,8 @@ class Gitee():
78
78
  self.check_parameter_format("token", f"^[a-z0-9]+$", self.token)
79
79
 
80
80
  self.owner = os.environ.get("giteeTargetNamespace")
81
+ if not self.owner:
82
+ self.owner = os.environ.get("giteeSourceNamespace")
81
83
  if self.options.owner is not None:
82
84
  self.owner = self.options.owner
83
85
  if self.owner is None:
@@ -85,6 +87,8 @@ class Gitee():
85
87
  self.check_parameter_format("owner", f"^[a-z0-9_a-z-]+$", self.owner)
86
88
 
87
89
  self.repo = os.environ.get("giteeTargetRepoName")
90
+ if not self.repo:
91
+ self.repo = os.environ.get("giteeSourceRepoName")
88
92
  if self.options.repo is not None:
89
93
  self.repo = self.options.repo
90
94
  if self.repo is None:
@@ -190,10 +190,13 @@ class BuildComponent():
190
190
  def build(self):
191
191
  log.info(os.getcwd())
192
192
 
193
+ export_cmd = f"conan export . --user={self.user} --channel={self.channel}"
194
+ tools.run(export_cmd, capture_output=False)
195
+
193
196
  lockfile = os.path.join(cwd, ".temp", "conan.lock")
194
197
  graphfile = os.path.join(cwd, ".temp", "graph.info")
195
198
  lock_cmd = f"conan lock create . {self.base_cmd} --lockfile-out={lockfile}"
196
- tools.exec(lock_cmd)
199
+ tools.run(lock_cmd, capture_output=False)
197
200
  graph_cmd = f"conan graph info . {self.base_cmd} -f json --lockfile={lockfile}"
198
201
  tools.pipe([graph_cmd], out_file=graphfile)
199
202
  log.success(f"start build dependency packages of {self.package}")
@@ -77,9 +77,19 @@ class LiteBmcConan(ConanFile):
77
77
  files.update_conandata(self, {"sources": {"commit": None, "url": None, "pwd": os.getcwd()}})
78
78
  return
79
79
 
80
- scm_url, scm_commit = git.get_url_and_commit()
81
- if not scm_url.startswith("https://"):
82
- print(f"url not startswith https://, use fake conandata.yml instead")
80
+ scm_url = None
81
+ remotes = git.run("remote -v")
82
+ checked_name = []
83
+ for r in remotes.splitlines():
84
+ name, url = r.split(maxsplit=1)
85
+ if name in checked_name:
86
+ continue
87
+ checked_name.append(name)
88
+ url, scm_commit = git.get_url_and_commit(remote=name)
89
+ if url.startswith("https://"):
90
+ scm_url = url
91
+ break
92
+ if not scm_url:
83
93
  files.update_conandata(self, {"sources": {"commit": None, "url": None, "pwd": os.getcwd()}})
84
94
  return
85
95
  files.update_conandata(self, {"sources": {"commit": scm_commit, "url": scm_url}})
@@ -0,0 +1,49 @@
1
+ """环境准备"""
2
+ import os
3
+ import tarfile
4
+ from lbkit.integration.config import Config
5
+ from lbkit.integration.task import Task
6
+ from lbkit.log import Logger
7
+ from lbkit import errors
8
+ from lbkit.utils.images.emmc import MakeImage as MekeEmmcImage
9
+
10
+ log = Logger("build_image")
11
+
12
+ src_cwd = os.path.split(os.path.realpath(__file__))[0]
13
+
14
+ class BuildImage(Task):
15
+ @staticmethod
16
+ def _trans_to_blk_1m(cfg: str):
17
+ if cfg.endswith("K"):
18
+ return int(cfg[:-1]) / 1024
19
+ elif cfg.endswith("M"):
20
+ return int(cfg[:-1])
21
+ elif cfg.endswith("G"):
22
+ return int(cfg[:-1]) * 1024
23
+
24
+ def run(self):
25
+ """任务入口"""
26
+ """检查manifest文件是否满足schema格式描述"""
27
+ os.chdir(self.config.output_path)
28
+ cmd = "qemu-system-aarch64 -M virt -cpu cortex-a57 -M virt,dumpdtb=virt.dtb"
29
+ self.exec(cmd)
30
+
31
+ mk = MekeEmmcImage(os.path.join(self.config.temp_path, "emmc_tmp_dir"))
32
+ rootfs_size = self.get_manifest_config("metadata/rootfs_size")
33
+ if rootfs_size:
34
+ mk.rootfs_blk_1m = self._trans_to_blk_1m(rootfs_size)
35
+ emmc_size = self.get_manifest_config("metadata/emmc_size")
36
+ if emmc_size:
37
+ mk.size_1m = self._trans_to_blk_1m(emmc_size)
38
+ mk.run("virt.dtb", self.config.rootfs_img, "qemu.img")
39
+ cmd = 'cp /usr/share/litebmc/qemu.conf qemu.conf'
40
+ self.exec(cmd)
41
+ output_img = os.path.join(self.config.output_path, "litebmc_qemu.tar.gz")
42
+ cmd = f'tar -czf {output_img} -C . qemu.img {self.config.uboot_bin} qemu.conf'
43
+ self.exec(cmd)
44
+ log.success(f"Create litebmc image {output_img} successfully")
45
+
46
+ if __name__ == "__main__":
47
+ config = Config()
48
+ build = BuildImage(config)
49
+ build.run()
@@ -8,6 +8,7 @@ from lbkit.integration.task import Task
8
8
  from lbkit.log import Logger
9
9
  from lbkit.build_conan_parallel import BuildConanParallel
10
10
  from concurrent.futures import ThreadPoolExecutor
11
+ from lbkit.errors import LiteBmcException
11
12
 
12
13
  log = Logger("product_build")
13
14
 
@@ -47,6 +48,17 @@ class BuildManifest(Task):
47
48
  continue
48
49
  cmd = f"conan cache path {ref}:{id}"
49
50
  package_folder = self.tools.run(cmd).stdout.strip()
51
+ rootfs_tar = os.path.join(package_folder, "rootfs.tar")
52
+ uboot_bin = os.path.join(package_folder, "u-boot.bin")
53
+ linux_bin = os.path.join(package_folder, "boot/Image")
54
+ if os.path.isfile(rootfs_tar):
55
+ self.config.rootfs_tar = rootfs_tar
56
+ continue
57
+ elif os.path.isfile(uboot_bin):
58
+ self.config.uboot_bin = uboot_bin
59
+ continue
60
+ elif os.path.isfile(linux_bin):
61
+ self.config.linux_bin = linux_bin
50
62
  self.config.conan_install.append(package_folder)
51
63
 
52
64
  def download_recipe(self, pkg):
@@ -106,6 +118,18 @@ class BuildManifest(Task):
106
118
  def run(self):
107
119
  """任务入口"""
108
120
  self.build_litebmc()
121
+ error = False
122
+ if not self.config.rootfs_tar:
123
+ error = True
124
+ self.log.error("rootfs.tar not found in any conan package")
125
+ if not self.config.uboot_bin:
126
+ error = True
127
+ self.log.error("u-boot.bin not found in any conan package")
128
+ if not self.config.linux_bin:
129
+ error = True
130
+ self.log.error("boot/Image not found in any conan package")
131
+ if error:
132
+ raise FileNotFoundError("Build failed because important files are missing")
109
133
 
110
134
  if __name__ == "__main__":
111
135
  config = Config()
@@ -50,7 +50,7 @@ class BuildPrepare(Task):
50
50
  def run(self):
51
51
  """任务入口"""
52
52
  """检查manifest文件是否满足schema格式描述"""
53
- self.load_manifest()
53
+ self.config.load_manifest()
54
54
  self.load_conan_profile()
55
55
 
56
56
  if __name__ == "__main__":
@@ -58,39 +58,15 @@ class BuildRootfs(Task):
58
58
  cmd = f"chown {uid}:{gid} {chunk[0]}"
59
59
  self.exec(cmd)
60
60
 
61
- def download_rootfs(self, rootfs_img):
62
- """下载rootfs基础镜像"""
63
- os.chdir(self.config.download_path)
64
- rootfs_tar = "rootfs.tar.gz"
65
-
66
- url = self.get_manifest_config("components/rootfs/url")
67
- sha256 = None
68
- if not self.config.not_check_download_sha:
69
- sha256 = self.get_manifest_config("components/rootfs/sha256")
70
- self.tools.download(url, rootfs_tar, sha256)
71
- tar = tarfile.open(rootfs_tar)
72
- members = tar.getmembers()
73
- for member in members:
74
- if not member.isfile():
75
- continue
76
- if member.name != "rootfs.img" and member.name != "rootfs.ext4" and member.name != "rootfs.ext2":
77
- continue
78
- io = tar.extractfile(member)
79
- fp = open(rootfs_img, "wb+")
80
- while True:
81
- buf = io.read(65536)
82
- if len(buf) == 0:
83
- break
84
- fp.write(buf)
85
- fp.close()
86
- return
87
- raise errors.ExtractRootfsTarFileError("Extract failed, the rootfs.img can't be found in rootfs.tar")
88
-
89
61
  def copy_conan_install(self, src_dir, mnt_path):
90
62
  src_dir += "/"
91
- cmd = f"rsync -aHK --exclude 'include' --exclude '*.a' --chown=0:0 {src_dir} {mnt_path}"
63
+ cmd = f"rsync -aHK --exclude '*.hpp' --exclude '*.h'"
64
+ cmd += f" --exclude 'rootfs.tar' --exclude 'u-boot.bin'"
65
+ cmd += f" --exclude 'conanmanifest.txt' --exclude 'conaninfo.txt'"
66
+ cmd += f" --exclude '*.a' --chown=0:0 {src_dir} {mnt_path}"
92
67
  log.info("copy %s to %s", src_dir, mnt_path)
93
- self.exec_easy(cmd, capture_output=False)
68
+ self.exec(cmd, echo_cmd=False)
69
+ strip = self.get_manifest_config("metadata/strip")
94
70
  for root, dirs, files in os.walk(src_dir):
95
71
  root = root.replace(src_dir, "")
96
72
  for dir in dirs:
@@ -101,14 +77,27 @@ class BuildRootfs(Task):
101
77
  self.exec(cmd, echo_cmd=False)
102
78
  for file in files:
103
79
  name = os.path.join(mnt_path, root, file)
80
+ cmd = f"chown -h 0:0 {name}"
104
81
  if not os.path.isfile(name):
105
82
  continue
106
- cmd = f"chown 0:0 {name}"
107
83
  self.exec(cmd, echo_cmd=False)
84
+ if name.find("usr/share") > 0 and name.find("bin") == -1:
85
+ continue
86
+ suffix = name.split(".")[-1]
87
+ no_need_strip = ["json", "html", "md", "txt", "yaml", "xml"]
88
+ no_need_strip.extend(["yml", "mo", "conf", "gz", "inc", "service", "py"])
89
+ no_need_strip.extend(["m4", "pc", "cmake", "rules", "ts", "js", "png"])
90
+ no_need_strip.extend(["jpg", "jpeg", "mpeg", "c", "h", "hpp"])
91
+ if suffix != name and suffix in no_need_strip:
92
+ continue
93
+ strip = self.get_manifest_config("metadata/strip")
94
+ if strip:
95
+ cmds = [f"file {name}", "grep \"not stripped\"", f"{self.config.strip} -s {name}"]
96
+ self.pipe(cmds, error_log="", ignore_error=True)
108
97
  per_file = os.path.join(src_dir, "permissions")
109
98
  self.do_permission(per_file)
110
99
 
111
- def merge_rootfs(self, rootfs_img):
100
+ def merge_rootfs(self):
112
101
  """将产品依赖的所有组件安装到rootfs镜像中"""
113
102
  mnt_path = self.config.mnt_path
114
103
  self.exec("umount " + mnt_path, ignore_error=True)
@@ -116,13 +105,20 @@ class BuildRootfs(Task):
116
105
  os.makedirs(mnt_path)
117
106
  # 按manifest配置的大小调整rootfs
118
107
  rootfs_size = self.get_manifest_config("metadata/rootfs_size")
119
- self.exec(f"resize2fs {rootfs_img} {rootfs_size}")
108
+ if self.config.rootfs_tar:
109
+ cmd = f"mkfs.ext4 -d {mnt_path} -r 1 -N 0 -m 5 -L \"rootfs\" -O ^64bit {self.config.rootfs_img} \"{rootfs_size}\""
110
+ self.exec(cmd)
120
111
  # 挂载rootfs镜像
121
- self.exec(f"fuse2fs {rootfs_img} {mnt_path} -o fakeroot")
112
+ self.exec(f"fuse2fs {self.config.rootfs_img} {mnt_path} -o fakeroot")
113
+ # 从rootfs.tar解压内容
114
+ if self.config.rootfs_tar:
115
+ cmd = f"tar -pxf {self.config.rootfs_tar} -C {mnt_path} ."
116
+ self.exec(cmd)
117
+ cmd = f"chown root:root {mnt_path} -R"
118
+ self.exec(cmd)
122
119
  # 切换到rootfs挂载目录
123
120
  os.chdir(mnt_path)
124
121
  log.info("Copy customization rootfs......")
125
- per_files = []
126
122
  for src_dir in self.config.conan_install:
127
123
  self.copy_conan_install(src_dir, mnt_path)
128
124
 
@@ -131,8 +127,6 @@ class BuildRootfs(Task):
131
127
  if os.path.isdir(product_rootfs):
132
128
  self.copy_conan_install(product_rootfs, mnt_path)
133
129
 
134
- for per_file in per_files:
135
- self.do_permission(per_file)
136
130
  # 执行rootfs定制化脚本
137
131
  os.chdir(self.config.work_dir)
138
132
  hook_name = "hook.post_rootfs"
@@ -146,55 +140,14 @@ class BuildRootfs(Task):
146
140
  cmd = "rm " + os.path.join(self.config.mnt_path, "permissions")
147
141
  self.exec(cmd)
148
142
 
149
- # 清理冗余静态文件
150
- cmds = ["find " + self.config.mnt_path + " -name *.a -type f", "xargs -i{} rm {} -f"]
151
- self.pipe(cmds)
152
-
153
- # 按manifest配置的大小调整rootfs
154
- strip = self.get_manifest_config("metadata/strip")
155
- if strip:
156
- log.info("Start strip files")
157
- file_list = os.path.join(self.config.temp_path, "strip.filelist")
158
- unstrip_regex = [
159
- "*.yaml$",
160
- "*.mo$",
161
- "*.target$",
162
- "*.service$",
163
- "*.md$",
164
- "*.html$",
165
- "*usr/share/",
166
- "*.py$",
167
- "*.pc$",
168
- "*.mc$",
169
- "*.in$",
170
- "*.ini$",
171
- "*.rules$",
172
- "*.conf$"]
173
- cmds = ["find " + self.config.mnt_path + " -type f"]
174
- for unstrip in unstrip_regex:
175
- cmds.append(f"grep -vE {unstrip}")
176
- self.pipe(cmds, out_file=file_list)
177
-
178
- cmds = [f"cat {file_list}", "xargs file", "grep 'not stripped'", "awk -F':' '{{print $1}}'"]
179
- cmds.append(f"xargs -i{{}} {self.config.strip} -s {{}}")
180
- self.pipe(cmds)
181
-
182
- log.info("remove static libraries")
183
- cmds = [f"find {self.config.mnt_path} -name *.a", "xargs -i{} rm {}"]
184
- self.pipe(cmds)
185
143
  log.info("remove all .fuse_hiddeng* files")
186
144
  cmds = [f"find {self.config.mnt_path} -name .fuse_hidden*", "xargs -i{} rm {}"]
187
145
  self.pipe(cmds)
188
146
  self.exec("umount " + mnt_path)
189
147
 
190
148
  def run(self):
191
- rootfs_img = os.path.join(self.config.download_path, IMG_FILE)
192
- if os.path.isfile(rootfs_img):
193
- os.unlink(rootfs_img)
194
149
  # 任务入口
195
- self.download_rootfs(rootfs_img)
196
- self.merge_rootfs(rootfs_img)
197
- os.rename(rootfs_img, self.config.rootfs_img)
150
+ self.merge_rootfs()
198
151
  log.success(f"Create image {self.config.rootfs_img} successfully")
199
152
 
200
153
  if __name__ == "__main__":
@@ -2,6 +2,7 @@
2
2
  import argparse
3
3
  import os, sys
4
4
  from lbkit.log import Logger
5
+ from lbkit.misc import load_yml_with_json_schema_validate
5
6
 
6
7
  log = Logger("build_config")
7
8
 
@@ -25,7 +26,6 @@ class Config(object):
25
26
  self.build_type = args.build_type
26
27
  # conan中心仓
27
28
  self.remote = args.remote
28
- self.not_check_download_sha = args.not_check_download_sha
29
29
 
30
30
  if not os.path.isfile(self.manifest):
31
31
  raise FileNotFoundError(f"File {args.manifest} not exist")
@@ -43,16 +43,17 @@ class Config(object):
43
43
  self.temp_path = os.path.join(self.code_path, ".temp")
44
44
  self.output_path = os.path.join(self.temp_path, "output")
45
45
  self.tool_path = os.path.join(self.temp_path, "tools")
46
- self.download_path = os.path.join(self.temp_path, "download")
47
- self.rootfs_path = os.path.join(self.temp_path, "rootfs")
46
+ # conan组件打包目录
48
47
  self.conan_install = []
49
48
  self.mnt_path = os.path.join(self.temp_path, "mnt_path")
50
49
  self.rootfs_img = os.path.join(self.output_path, "rootfs.img")
50
+ # rootfs、uboot和kernel关键文件路径
51
+ self.uboot_bin = None
52
+ self.linux_bin = None
53
+ self.rootfs_tar = None
51
54
  os.makedirs(self.temp_path, exist_ok=True)
52
55
  os.makedirs(self.tool_path, exist_ok=True)
53
56
  os.makedirs(self.output_path, exist_ok=True)
54
- os.makedirs(self.download_path, exist_ok=True)
55
- os.makedirs(self.rootfs_path, exist_ok=True)
56
57
  # 制作rootfs时需要strip镜像,所以需要单独指定stip路径
57
58
  self.strip = "strip"
58
59
 
@@ -65,7 +66,23 @@ class Config(object):
65
66
  parser.add_argument("-pr", "--profile", help="Apply the specified profile to the host machine", default="litebmc.ini")
66
67
  parser.add_argument("-pr:b", "--profile_build", help="Apply the specified profile to the build machine", default="default")
67
68
  parser.add_argument("-t", "--build_type", type=str, choices=['debug', 'release', 'minsize'], help="Set the build type", default="debug")
68
- parser.add_argument("--not_check_download_sha", help="don't check sha256 of download file", action="store_true")
69
69
  parser.add_argument("-r", "--remote", help="specified conan server", default="litebmc")
70
70
  parser.add_argument("-l", "--create_conan_lock", help="Create new conan.lock", action="store_true")
71
71
  return parser
72
+
73
+ def get_manifest_config(self, key: str, default=None):
74
+ """从manifest中读取配置"""
75
+ manifest = self.load_manifest()
76
+ keys = key.split("/")
77
+ for k in keys:
78
+ manifest = manifest.get(k, None)
79
+ if manifest is None:
80
+ return default
81
+ return manifest
82
+
83
+ def load_manifest(self):
84
+ """加载manifest.yml并验证schema文件"""
85
+ template = {}
86
+ template["code_path"] = self.code_path
87
+ template["temp_path"] = self.temp_path
88
+ return load_yml_with_json_schema_validate(self.manifest, "/usr/share/litebmc/schema/pdf.v1.json", **template)
@@ -50,17 +50,9 @@ class Task(Process):
50
50
  hook = module.TaskHook(self.config, "do_hook")
51
51
  hook.run()
52
52
 
53
- def get_manifest_config(self, key: str):
54
- """从manifest中读取配置"""
55
- with open(self.config.manifest, "r", encoding="utf-8") as fp:
56
- manifest = yaml.load(fp, yaml.FullLoader)
57
- keys = key.split("/")
58
- for k in keys:
59
- manifest = manifest.get(k, None)
60
- if manifest is None:
61
- return None
62
- return manifest
53
+ def get_manifest_config(self, key: str, default=None):
54
+ return self.config.get_manifest_config(key, default)
63
55
 
64
56
  def load_manifest(self):
65
57
  """加载manifest.yml并验证schema文件"""
66
- return load_yml_with_json_schema_validate(self.config.manifest, "/usr/share/litebmc/schema/pdf.v1.json")
58
+ return self.config.load_manifest()
@@ -5,6 +5,7 @@ import json
5
5
  import yaml
6
6
  import re
7
7
  import requests
8
+ from string import Template
8
9
  from colorama import Fore, Style
9
10
  from jsonschema import validate, ValidationError
10
11
  from lbkit.errors import PackageConfigException, HttpRequestException
@@ -80,7 +81,7 @@ def load_json_schema(schema_file):
80
81
  tmp = fp.read()
81
82
  return json.loads(tmp)
82
83
 
83
- def load_yml_with_json_schema_validate(yml_file, default_json_schema_file):
84
+ def load_yml_with_json_schema_validate(yml_file, default_json_schema_file, **kwargs):
84
85
  """使用json schema文件校验yml_file配置文件"""
85
86
  schema_file = get_json_schema_file(yml_file, default_json_schema_file)
86
87
  if schema_file is None:
@@ -89,8 +90,10 @@ def load_yml_with_json_schema_validate(yml_file, default_json_schema_file):
89
90
  schema = load_json_schema(schema_file)
90
91
  try:
91
92
  fp = open(yml_file, "r")
92
- data = yaml.safe_load(fp)
93
+ template = Template(fp.read())
93
94
  fp.close()
95
+ content = template.safe_substitute(kwargs)
96
+ data = yaml.safe_load(content)
94
97
  validate(data, schema)
95
98
  return data
96
99
  except ValidationError as exc:
@@ -104,10 +104,13 @@ class Tools(object):
104
104
  raise errors.RunCommandException(f"Run command {real_cmd[0]} failed")
105
105
  ret.communicate()
106
106
  if ret.returncode != 0:
107
+ error_log = "Run command ({}) failed, error: {}".format(cmd, ret.stderr)
108
+ error_log = kwargs.get("error_log", error_log)
107
109
  if ignore_error:
108
- self.log.info("Run command ({}) failed".format(cmd), uptrace=uptrace)
110
+ if error_log:
111
+ self.log.info(failed_info)
109
112
  return
110
- raise errors.RunCommandException(f"command {cmd} return non-zero, error: {ret.stderr}")
113
+ raise errors.RunCommandException(error_log)
111
114
  if stdin:
112
115
  stdin.close()
113
116
  stdin = stdout
@@ -0,0 +1,2 @@
1
+
2
+ __version__ = '0.6.0'
@@ -0,0 +1,109 @@
1
+ """环境准备"""
2
+ import os
3
+ import tempfile
4
+ from lbkit import errors
5
+ from lbkit.tools import Tools
6
+
7
+
8
+ src_cwd = os.path.split(os.path.realpath(__file__))[0]
9
+
10
+ class MakeImage():
11
+ def __init__(self, tmp_dir):
12
+ self.tools = Tools("make emmc_image")
13
+ self.log = self.tools.log
14
+ self.size_1m = 4096
15
+ self.misc_blk_1k = 1024
16
+ self.ubootenv_blk_1k = 1024
17
+ self.vbmeta_blk_1k = 1024
18
+ # 会创建3个rootfs镜像
19
+ self.rootfs_blk_1m = 1024
20
+ # 用户数据区最小512m
21
+ self.userdata_blk_1m = 512
22
+ self.tmp_dir = tmp_dir
23
+ if not os.path.isdir(tmp_dir):
24
+ os.makedirs(self.tmp_dir)
25
+ else:
26
+ cmd = "umount " + tmp_dir
27
+ self.tools.exec(cmd, ignore_error=True, echo_cmd=False)
28
+
29
+ def run(self, dtb, rootfs, output="emmc.img"):
30
+ blk_1k = self.misc_blk_1k + self.ubootenv_blk_1k + self.vbmeta_blk_1k
31
+ blk_1k += self.rootfs_blk_1m * 1024 * 3
32
+ blk_1k += self.userdata_blk_1m * 1024
33
+ if self.size_1m * 1024 < blk_1k:
34
+ blk_1m = int((blk_1k + 1023) / 1024)
35
+ raise errors.LiteBmcException(f"参数检测错误,镜像文件{self.size_1m}M小于需要的{blk_1m}M大小")
36
+ if self.userdata_blk_1m == 512:
37
+ self.userdata_blk_1m = int(self.size_1m - blk_1k / 1024) - 128
38
+ self.log.info(f"重置userdata大小为{self.userdata_blk_1m}M")
39
+ if os.path.isfile(output):
40
+ os.unlink(output)
41
+ self.log.info(f"创建一个{self.size_1m}M大小的镜像")
42
+ self.tools.exec(f"dd if=/dev/zero of={output} bs=1M count=1 seek={self.size_1m -1}")
43
+ self.tools.exec(f"parted {output} mktable gpt")
44
+ start = 4096
45
+ end = start + self.misc_blk_1k * 2
46
+ self.log.info(f"创建misc区")
47
+ self.tools.exec(f"parted {output} mkpart misc {start}s {end - 1}s")
48
+ start = end
49
+ end += self.ubootenv_blk_1k * 2
50
+ self.log.info(f"创建ubootenv区")
51
+ self.tools.exec(f"parted -s -a none {output} mkpart ubootenv {start}s {end - 1}s")
52
+ start = end
53
+ end += self.vbmeta_blk_1k * 2
54
+ self.log.info(f"创建vbmeta区")
55
+ self.tools.exec(f"parted -s -a none {output} mkpart vbmeta {start}s {end - 1}s")
56
+ start = end
57
+ end += self.rootfs_blk_1m * 1024 * 2
58
+ self.log.info("创建rootfs镜像区")
59
+ self.tools.exec(f"parted -s -a none {output} mkpart rootfs_a {start}s {end - 1}s")
60
+ self.log.info(f"挂载rootfs分区并复制内容,注意,此时会修改原始{rootfs}镜像并添加dtb以及启动参数")
61
+ self.tools.exec(f"fuse2fs {rootfs} {self.tmp_dir} -o fakeroot -o nonempty")
62
+ extlinux = os.path.join(self.tmp_dir, "boot/extlinux")
63
+ os.makedirs(extlinux, exist_ok=True)
64
+ with open(os.path.join(extlinux, "extlinux.conf"), "w+") as fp:
65
+ fp.write("menu title U-Boot menu\n")
66
+ fp.write("prompt 0\n")
67
+ fp.write("timeout 10\n")
68
+ fp.write("\n")
69
+ fp.write("label litebmc-active\n")
70
+ fp.write(" kernel /boot/Image\n")
71
+ fp.write(" fdt /boot/litebmc.dtb\n")
72
+ fp.write(" append console=ttyAMA0 loglevel=10 rootwait root=/dev/nvme0n1p4 rw\n")
73
+ self.tools.exec(f"cp {dtb} {self.tmp_dir}/boot/litebmc.dtb")
74
+ self.tools.exec(f"chown 0:0 {self.tmp_dir}/boot/ -R")
75
+ self.tools.exec(f"chmod 700 {self.tmp_dir}/boot/extlinux/")
76
+ self.tools.exec(f"chmod 600 {self.tmp_dir}/boot/extlinux/extlinux.conf")
77
+ self.tools.exec(f"chmod 600 {self.tmp_dir}/boot/Image")
78
+ self.tools.exec(f"chmod 600 {self.tmp_dir}/boot/litebmc.dtb")
79
+ self.tools.exec(f"umount {self.tmp_dir}")
80
+ self.log.info("复制镜像文件到rootfs_a区域")
81
+ self.tools.exec(f"dd if={rootfs} of={output} bs=512 seek={start} conv=notrunc")
82
+ self.log.info("制作rootfs_b")
83
+ start = end
84
+ end += self.rootfs_blk_1m * 1024 * 2
85
+ self.tools.exec(f"parted -s -a none {output} mkpart rootfs_b {start}s {end - 1}s")
86
+ self.log.info("复制镜像文件到rootfs_b")
87
+ self.tools.exec(f"dd if={rootfs} of={output} bs=512 seek={start} conv=notrunc")
88
+ self.log.info("制作rootfs_c")
89
+ start = end
90
+ end += self.rootfs_blk_1m * 1024 * 2
91
+ self.tools.exec(f"parted -s -a none {output} mkpart rootfs_c {start}s {end - 1}s")
92
+ self.log.info("复制镜像文件到rootfs_c")
93
+ self.tools.exec(f"dd if={rootfs} of={output} bs=512 seek={start} conv=notrunc")
94
+ start = end
95
+ self.log.info("制作userdata区")
96
+ end += self.userdata_blk_1m * 1024 * 2
97
+ self.tools.exec(f"parted -s -a none {output} mkpart userdata ext4 {start}s {end - 1}s")
98
+ self.log.info("为userdata区创建一个空镜像")
99
+ tmpfile = tempfile.NamedTemporaryFile()
100
+ empty_img = tmpfile.name
101
+ self.tools.exec(f"dd if=/dev/zero of={empty_img} bs=1M seek={self.userdata_blk_1m - 1} count=1")
102
+ self.tools.exec(f"mkfs.ext4 {empty_img}")
103
+ self.log.info("复制空镜像到userdata区")
104
+ self.tools.exec(f"dd if={empty_img} of={output} bs=512 seek={start} conv=notrunc")
105
+ self.tools.exec(f"parted {output} set 4 boot on")
106
+
107
+ if __name__ == "__main__":
108
+ mk = MakeImage()
109
+ mk.run("./Image", "./virt.dtb", "./rootfs.img", "./qemu.img")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lbkit
3
- Version: 0.6.0
3
+ Version: 0.6.2
4
4
  Summary: Tools provided by litebmc.com
5
5
  Home-page: https://www.litebmc.com
6
6
  Author: xuhj@litebmc.com
@@ -14,12 +14,12 @@ License-File: AUTHORS
14
14
  Requires-Dist: pyyaml
15
15
  Requires-Dist: colorama
16
16
  Requires-Dist: mako
17
- Requires-Dist: node-semver==0.6.1
17
+ Requires-Dist: node-semver>=0.6.1
18
18
  Requires-Dist: jsonschema
19
19
  Requires-Dist: conan
20
20
  Requires-Dist: requests
21
21
  Requires-Dist: gitpython
22
22
  Requires-Dist: inflection
23
- Requires-Dist: meson==1.4.0
23
+ Requires-Dist: meson>=1.4.0
24
24
 
25
25
  build and code generate tools
@@ -47,6 +47,9 @@ lbkit/integration/build_rootfs.py
47
47
  lbkit/integration/config.py
48
48
  lbkit/integration/task.py
49
49
  lbkit/integration/template/conanfile.py.mako
50
+ lbkit/utils/__init__.py
51
+ lbkit/utils/images/__init__.py
52
+ lbkit/utils/images/emmc.py
50
53
  test/__init__.py
51
54
  test/test_codegen.py
52
55
  test/test_helper.py
@@ -1,10 +1,10 @@
1
1
  pyyaml
2
2
  colorama
3
3
  mako
4
- node-semver==0.6.1
4
+ node-semver>=0.6.1
5
5
  jsonschema
6
6
  conan
7
7
  requests
8
8
  gitpython
9
9
  inflection
10
- meson==1.4.0
10
+ meson>=1.4.0
@@ -19,7 +19,7 @@ setup(
19
19
  description="Tools provided by litebmc.com",
20
20
  long_description="build and code generate tools",
21
21
  long_description_content_type="text/markdown",
22
- install_requires=["pyyaml", "colorama", "mako", "node-semver==0.6.1", "jsonschema", "conan", "requests", "gitpython", "inflection", "meson==1.4.0"],
22
+ install_requires=["pyyaml", "colorama", "mako", "node-semver>=0.6.1", "jsonschema", "conan", "requests", "gitpython", "inflection", "meson>=1.4.0"],
23
23
  url="https://www.litebmc.com",
24
24
  packages=find_packages(),
25
25
  include_package_data=True,
@@ -1,89 +0,0 @@
1
- """环境准备"""
2
- import os
3
- import tempfile
4
- import tarfile
5
- import shutil
6
- from lbkit.integration.config import Config
7
- from lbkit.integration.task import Task
8
- from lbkit.log import Logger
9
- from lbkit import errors
10
-
11
- log = Logger("build_image")
12
-
13
- src_cwd = os.path.split(os.path.realpath(__file__))[0]
14
-
15
- class BuildImage(Task):
16
- def download_uboot(self, img_file):
17
- tar_file = os.path.join(self.config.download_path, "uboot.tar.gz")
18
-
19
- url = self.get_manifest_config("components/uboot/url")
20
- sha256 = None
21
- if not self.config.not_check_download_sha:
22
- sha256 = self.get_manifest_config("components/uboot/sha256")
23
- self.tools.download(url, tar_file, sha256)
24
- tar = tarfile.open(tar_file)
25
- members = tar.getmembers()
26
- for member in members:
27
- if not member.isfile():
28
- continue
29
- if member.name != "uboot.bin" and member.name != "u-boot.bin":
30
- continue
31
- io = tar.extractfile(member)
32
- fp = open(img_file, "wb+")
33
- while True:
34
- buf = io.read(65536)
35
- if len(buf) == 0:
36
- break
37
- fp.write(buf)
38
- fp.close()
39
- return
40
- raise errors.ExtractRootfsTarFileError("Extract failed, the u-boot.bin can't be found in " + url)
41
-
42
- def download_kernel(self, img_file):
43
- tar_file = os.path.join(self.config.download_path, "kernel.tar.gz")
44
-
45
- url = self.get_manifest_config("components/kernel/url")
46
- sha256 = None
47
- if not self.config.not_check_download_sha:
48
- sha256 = self.get_manifest_config("components/kernel/sha256")
49
- self.tools.download(url, tar_file, sha256)
50
- tar = tarfile.open(tar_file)
51
- members = tar.getmembers()
52
- for member in members:
53
- if not member.isfile():
54
- continue
55
- if member.name != "Image":
56
- continue
57
- io = tar.extractfile(member)
58
- fp = open(img_file, "wb+")
59
- while True:
60
- buf = io.read(65536)
61
- if len(buf) == 0:
62
- break
63
- fp.write(buf)
64
- fp.close()
65
- return
66
- raise errors.ExtractRootfsTarFileError("Extract failed, the Image can't be found in " + url)
67
-
68
- def run(self):
69
- """任务入口"""
70
- """检查manifest文件是否满足schema格式描述"""
71
- os.chdir(self.config.output_path)
72
- self.download_uboot("u-boot.bin")
73
- self.download_kernel("Image")
74
- cmd = "qemu-system-aarch64 -M virt -cpu cortex-a57 -M virt,dumpdtb=virt.dtb"
75
- self.exec(cmd)
76
-
77
- cmd = 'lbpack_emmc.sh ./Image ./virt.dtb ./rootfs.img ./qemu.img'
78
- self.exec(cmd)
79
- cmd = 'cp /usr/share/litebmc/qemu.conf ./qemu.conf'
80
- self.exec(cmd)
81
- output_img = os.path.join(self.config.output_path, "litebmc_qemu.tar.gz")
82
- cmd = f'tar -czf {output_img} -C . qemu.img u-boot.bin qemu.conf'
83
- self.exec(cmd)
84
- log.success(f"Create litebmc image {output_img} successfully")
85
-
86
- if __name__ == "__main__":
87
- config = Config()
88
- build = BuildImage(config)
89
- build.run()
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