lbkit 0.6.1__tar.gz → 0.6.3__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 (59) hide show
  1. {lbkit-0.6.1/lbkit.egg-info → lbkit-0.6.3}/PKG-INFO +1 -1
  2. lbkit-0.6.3/lbkit/__init__.py +2 -0
  3. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/build_conan_parallel.py +3 -2
  4. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/ci_robot/gitee.py +4 -0
  5. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/build.py +12 -4
  6. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/template/conanbase.mako +9 -10
  7. lbkit-0.6.3/lbkit/integration/build_image.py +49 -0
  8. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/build_manifest.py +24 -0
  9. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/build_prepare.py +1 -1
  10. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/build_rootfs.py +28 -43
  11. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/config.py +23 -6
  12. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/task.py +3 -11
  13. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/misc.py +5 -2
  14. lbkit-0.6.3/lbkit/utils/__init__.py +2 -0
  15. lbkit-0.6.3/lbkit/utils/images/__init__.py +2 -0
  16. lbkit-0.6.3/lbkit/utils/images/emmc.py +109 -0
  17. {lbkit-0.6.1 → lbkit-0.6.3/lbkit.egg-info}/PKG-INFO +1 -1
  18. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit.egg-info/SOURCES.txt +3 -0
  19. lbkit-0.6.1/lbkit/__init__.py +0 -2
  20. lbkit-0.6.1/lbkit/integration/build_image.py +0 -89
  21. {lbkit-0.6.1 → lbkit-0.6.3}/AUTHORS +0 -0
  22. {lbkit-0.6.1 → lbkit-0.6.3}/LICENSE +0 -0
  23. {lbkit-0.6.1 → lbkit-0.6.3}/MANIFEST.in +0 -0
  24. {lbkit-0.6.1 → lbkit-0.6.3}/README.md +0 -0
  25. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/ci_robot/__init__.py +0 -0
  26. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/cli.py +0 -0
  27. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/__init__.py +0 -0
  28. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/codegen.py +0 -0
  29. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/ctype_defination.py +0 -0
  30. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/idf_interface.py +0 -0
  31. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/renderer.py +0 -0
  32. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/client.c.mako +0 -0
  33. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/client.h.mako +0 -0
  34. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/interface.c.mako +0 -0
  35. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/interface.introspect.xml.mako +0 -0
  36. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/public.c.mako +0 -0
  37. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/public.h.mako +0 -0
  38. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/server.c.mako +0 -0
  39. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/server.h.mako +0 -0
  40. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/__init__.py +0 -0
  41. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/arg_parser.py +0 -0
  42. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/template/deploy.mako +0 -0
  43. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/test.py +0 -0
  44. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/errors.py +0 -0
  45. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/helper.py +0 -0
  46. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/__init__.py +0 -0
  47. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/template/conanfile.py.mako +0 -0
  48. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/lbkit.py +0 -0
  49. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/log.py +0 -0
  50. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/tools.py +0 -0
  51. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit.egg-info/dependency_links.txt +0 -0
  52. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit.egg-info/entry_points.txt +0 -0
  53. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit.egg-info/requires.txt +0 -0
  54. {lbkit-0.6.1 → lbkit-0.6.3}/lbkit.egg-info/top_level.txt +0 -0
  55. {lbkit-0.6.1 → lbkit-0.6.3}/setup.cfg +0 -0
  56. {lbkit-0.6.1 → lbkit-0.6.3}/setup.py +0 -0
  57. {lbkit-0.6.1 → lbkit-0.6.3}/test/__init__.py +0 -0
  58. {lbkit-0.6.1 → lbkit-0.6.3}/test/test_codegen.py +0 -0
  59. {lbkit-0.6.1 → lbkit-0.6.3}/test/test_helper.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lbkit
3
- Version: 0.6.1
3
+ Version: 0.6.3
4
4
  Summary: Tools provided by litebmc.com
5
5
  Home-page: https://www.litebmc.com
6
6
  Author: xuhj@litebmc.com
@@ -0,0 +1,2 @@
1
+
2
+ __version__ = '0.6.3'
@@ -85,9 +85,10 @@ class BuildConanParallel(object):
85
85
  cmd += " --build=missing"
86
86
  cmd += f" --lockfile={self.lockfile}"
87
87
  try:
88
- 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}")
89
90
  log.debug(f">>>> {cmd}")
90
- 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)
91
92
  log.success(f"<<<< build {cp.ref} finished")
92
93
  except Exception as e:
93
94
  self.exception = e
@@ -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:
@@ -71,7 +71,10 @@ class BuildComponent():
71
71
  self.pkg = None
72
72
  self.base_cmd = ""
73
73
  self.gen_conaninfo()
74
- self.base_cmd += f" --user {self.user} --channel {self.channel}"
74
+ # 此场景发布的包名不带@user/channel
75
+ if self.user != "litebmc" or self.channel != "release":
76
+ self.base_cmd += f" --user {self.user} --channel {self.channel}"
77
+
75
78
  self.base_cmd += f" -pr {self.profile} -s build_type={self.build_type} -r " + self.options.remote
76
79
  self.base_cmd += f" -pr:b {self.profile_build}"
77
80
  if self.options.cov:
@@ -126,8 +129,9 @@ class BuildComponent():
126
129
  self.name = pkg.get("name")
127
130
  self.version = pkg.get("version")
128
131
 
129
- self.package = self.name + "/" + self.version + \
130
- "@" + self.user + "/" + self.channel
132
+ self.package = self.name + "/" + self.version
133
+ if self.user != "litebmc" or self.channel != "release":
134
+ self.package += "@" + self.user + "/" + self.channel
131
135
  # 准备部署依赖
132
136
  requires = pkg.get("requires")
133
137
  deps = []
@@ -190,8 +194,12 @@ class BuildComponent():
190
194
  def build(self):
191
195
  log.info(os.getcwd())
192
196
 
193
- export_cmd = f"conan export . --user={self.user} --channel={self.channel}"
197
+ export_cmd = "conan export . "
198
+ if self.user != "litebmc" or self.channel != "release":
199
+ export_cmd += f"--user={self.user} --channel={self.channel}"
194
200
  tools.run(export_cmd, capture_output=False)
201
+ # import sys
202
+ # sys.exit(-1)
195
203
 
196
204
  lockfile = os.path.join(cwd, ".temp", "conan.lock")
197
205
  graphfile = os.path.join(cwd, ".temp", "graph.info")
@@ -28,8 +28,11 @@ libs = pkg.get("package_info", {}).get("libs", [])
28
28
  class LiteBmcConan(ConanFile):
29
29
  name = "${pkg_name}"
30
30
  version = "${pkg["version"]}"
31
+ % if pkg["user"] != "litebmc" or pkg["channel"] != "release":
32
+ ## @litebmc/release则生成的包名不带@user/channel
31
33
  user = "${pkg["user"]}"
32
34
  channel = "${pkg["channel"]}"
35
+ % endif
33
36
  settings = "os", "arch", "compiler", "build_type"
34
37
  description = "${pkg["description"]}"
35
38
  url = "${pkg["url"]}"
@@ -78,16 +81,12 @@ class LiteBmcConan(ConanFile):
78
81
  return
79
82
 
80
83
  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
84
+ scm_commit = git.get_commit()
85
+ branches = git.run("branch -r --contains {}".format(scm_commit))
86
+ remotes = git.run("remote")
87
+ for remote in remotes.splitlines():
88
+ if "{}/".format(remote) in branches:
89
+ scm_url = git.get_remote_url(remote)
91
90
  break
92
91
  if not scm_url:
93
92
  files.update_conandata(self, {"sources": {"commit": None, "url": None, "pwd": os.getcwd()}})
@@ -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
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,18 +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
108
93
  strip = self.get_manifest_config("metadata/strip")
109
94
  if strip:
110
- cmds = [f"file {name}", "grep \"not stripped\", "f"{self.config.strip} -s {name}"]
95
+ cmds = [f"file {name}", "grep \"not stripped\"", f"{self.config.strip} -s {name}"]
111
96
  self.pipe(cmds, error_log="", ignore_error=True)
112
97
  per_file = os.path.join(src_dir, "permissions")
113
98
  self.do_permission(per_file)
114
99
 
115
- def merge_rootfs(self, rootfs_img):
100
+ def merge_rootfs(self):
116
101
  """将产品依赖的所有组件安装到rootfs镜像中"""
117
102
  mnt_path = self.config.mnt_path
118
103
  self.exec("umount " + mnt_path, ignore_error=True)
@@ -120,13 +105,20 @@ class BuildRootfs(Task):
120
105
  os.makedirs(mnt_path)
121
106
  # 按manifest配置的大小调整rootfs
122
107
  rootfs_size = self.get_manifest_config("metadata/rootfs_size")
123
- 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)
124
111
  # 挂载rootfs镜像
125
- 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)
126
119
  # 切换到rootfs挂载目录
127
120
  os.chdir(mnt_path)
128
121
  log.info("Copy customization rootfs......")
129
- per_files = []
130
122
  for src_dir in self.config.conan_install:
131
123
  self.copy_conan_install(src_dir, mnt_path)
132
124
 
@@ -135,8 +127,6 @@ class BuildRootfs(Task):
135
127
  if os.path.isdir(product_rootfs):
136
128
  self.copy_conan_install(product_rootfs, mnt_path)
137
129
 
138
- for per_file in per_files:
139
- self.do_permission(per_file)
140
130
  # 执行rootfs定制化脚本
141
131
  os.chdir(self.config.work_dir)
142
132
  hook_name = "hook.post_rootfs"
@@ -156,13 +146,8 @@ class BuildRootfs(Task):
156
146
  self.exec("umount " + mnt_path)
157
147
 
158
148
  def run(self):
159
- rootfs_img = os.path.join(self.config.download_path, IMG_FILE)
160
- if os.path.isfile(rootfs_img):
161
- os.unlink(rootfs_img)
162
149
  # 任务入口
163
- self.download_rootfs(rootfs_img)
164
- self.merge_rootfs(rootfs_img)
165
- os.rename(rootfs_img, self.config.rootfs_img)
150
+ self.merge_rootfs()
166
151
  log.success(f"Create image {self.config.rootfs_img} successfully")
167
152
 
168
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:
@@ -0,0 +1,2 @@
1
+
2
+ __version__ = '0.6.0'
@@ -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.1
3
+ Version: 0.6.3
4
4
  Summary: Tools provided by litebmc.com
5
5
  Home-page: https://www.litebmc.com
6
6
  Author: xuhj@litebmc.com
@@ -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,2 +0,0 @@
1
-
2
- __version__ = '0.6.1'
@@ -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
File without changes
File without changes
File without changes