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.
- {lbkit-0.6.1/lbkit.egg-info → lbkit-0.6.3}/PKG-INFO +1 -1
- lbkit-0.6.3/lbkit/__init__.py +2 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/build_conan_parallel.py +3 -2
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/ci_robot/gitee.py +4 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/build.py +12 -4
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/template/conanbase.mako +9 -10
- lbkit-0.6.3/lbkit/integration/build_image.py +49 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/build_manifest.py +24 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/build_prepare.py +1 -1
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/build_rootfs.py +28 -43
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/config.py +23 -6
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/task.py +3 -11
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/misc.py +5 -2
- lbkit-0.6.3/lbkit/utils/__init__.py +2 -0
- lbkit-0.6.3/lbkit/utils/images/__init__.py +2 -0
- lbkit-0.6.3/lbkit/utils/images/emmc.py +109 -0
- {lbkit-0.6.1 → lbkit-0.6.3/lbkit.egg-info}/PKG-INFO +1 -1
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit.egg-info/SOURCES.txt +3 -0
- lbkit-0.6.1/lbkit/__init__.py +0 -2
- lbkit-0.6.1/lbkit/integration/build_image.py +0 -89
- {lbkit-0.6.1 → lbkit-0.6.3}/AUTHORS +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/LICENSE +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/MANIFEST.in +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/README.md +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/ci_robot/__init__.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/cli.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/__init__.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/codegen.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/ctype_defination.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/idf_interface.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/renderer.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/client.c.mako +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/client.h.mako +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/interface.c.mako +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/interface.introspect.xml.mako +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/public.c.mako +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/public.h.mako +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/server.c.mako +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/codegen/template/server.h.mako +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/__init__.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/arg_parser.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/template/deploy.mako +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/component/test.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/errors.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/helper.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/__init__.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/integration/template/conanfile.py.mako +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/lbkit.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/log.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit/tools.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit.egg-info/dependency_links.txt +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit.egg-info/entry_points.txt +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit.egg-info/requires.txt +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/lbkit.egg-info/top_level.txt +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/setup.cfg +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/setup.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/test/__init__.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/test/test_codegen.py +0 -0
- {lbkit-0.6.1 → lbkit-0.6.3}/test/test_helper.py +0 -0
|
@@ -85,9 +85,10 @@ class BuildConanParallel(object):
|
|
|
85
85
|
cmd += " --build=missing"
|
|
86
86
|
cmd += f" --lockfile={self.lockfile}"
|
|
87
87
|
try:
|
|
88
|
-
|
|
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=
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if
|
|
86
|
-
|
|
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()
|
|
@@ -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 '
|
|
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\",
|
|
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
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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,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")
|
|
@@ -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
|
lbkit-0.6.1/lbkit/__init__.py
DELETED
|
@@ -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
|
|
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
|