mirror of
https://github.com/BigfootACA/arch-image-builder.git
synced 2024-11-15 01:03:25 +08:00
124 lines
3.9 KiB
Python
124 lines
3.9 KiB
Python
import os
|
|
import io
|
|
import gzip
|
|
from logging import getLogger
|
|
from tempfile import mkstemp
|
|
from builder.disk.content import ImageContentBuilder
|
|
from builder.lib.config import ArchBuilderConfigError
|
|
from external.mkbootimg import main as mkbootimg
|
|
log = getLogger(__name__)
|
|
|
|
|
|
class AndroidBootBuilder(ImageContentBuilder):
|
|
temps: list[str] = []
|
|
|
|
def to_list(self, val: str | list[str] | None) -> list[str]:
|
|
if type(val) is str: return [val]
|
|
if type(val) is None: return []
|
|
if type(val) is list[str]: return val
|
|
raise TypeError("bad type for list")
|
|
|
|
def get_input_file(self, name: str):
|
|
ctx = self.builder.ctx
|
|
if name.startswith("/"): return name
|
|
in_root = os.path.join(ctx.get_rootfs(), name)
|
|
in_out = os.path.join(ctx.get_output(), name)
|
|
return in_root if os.path.exists(in_root) else in_out
|
|
|
|
def parse_config(self, cfg: dict) -> list:
|
|
ret: list[str] = []
|
|
def add_option(key: str, file: bool = False):
|
|
if key not in cfg: return
|
|
val = str(cfg[key])
|
|
key = "--" + key.replace("-", "_")
|
|
if file: val = self.get_input_file(val)
|
|
ret.extend([key, val])
|
|
file_in = [
|
|
"kernel", "ramdisk", "second", "dtb", "recovery-dtbo",
|
|
"recovery-acpio", "vendor-ramdisk", "vendor-bootconfig",
|
|
]
|
|
fields = [
|
|
"header-version", "cmdline", "vendor-cmdline", "base",
|
|
"kernel-offset", "ramdisk-offset", "second-offset",
|
|
"dtb-offset", "os-version", "os-patch-level", "tags-offset",
|
|
"board", "pagesize", "header-version",
|
|
]
|
|
for arg in fields: add_option(arg)
|
|
for arg in file_in: add_option(arg, True)
|
|
return ret
|
|
|
|
def resolve_kernel(self, files: list[str] | str) -> list[str]:
|
|
ret: list[str] = []
|
|
if files is None: return ret
|
|
ctx = self.builder.ctx
|
|
rootfs = ctx.get_rootfs()
|
|
path: str = ctx.get("kernel.path", "")
|
|
if path.startswith("/"): path = path[1:]
|
|
for file in self.to_list(files):
|
|
if file.startswith("/"): file = file[1:]
|
|
ret.append(os.path.join(rootfs, path, file))
|
|
return ret
|
|
|
|
def merge_fp(self, files: list[str], fp: io.FileIO):
|
|
for f in files:
|
|
inp = self.get_input_file(f)
|
|
with open(inp, "rb") as fi:
|
|
fp.write(fi.read())
|
|
fp.flush()
|
|
|
|
def merge_files(self, files: list[str]):
|
|
fd, file = mkstemp()
|
|
with os.fdopen(fd, "wb") as fo:
|
|
self.merge_fp(files, fo)
|
|
return file
|
|
|
|
def load_initramfs(self, cfg: dict):
|
|
ctx = self.builder.ctx
|
|
initramfs = self.resolve_kernel(ctx.get("kernel.initramfs"))
|
|
if "ramdisk" in cfg: initramfs = self.to_list(cfg["ramdisk"])
|
|
if len(initramfs) <= 0: return
|
|
file = self.merge_files(initramfs)
|
|
self.temps.append(file)
|
|
cfg["ramdisk"] = file
|
|
|
|
def load_kernel(self, cfg: dict):
|
|
ctx = self.builder.ctx
|
|
if "image-gzip-dtb" not in cfg or not cfg["image-gzip-dtb"]: return
|
|
kernel = self.resolve_kernel(ctx.get("kernel.kernel"))
|
|
dtb = self.resolve_kernel(ctx.get("kernel.devicetree"))
|
|
if "kernel" in cfg: kernel = self.to_list(cfg["kernel"])
|
|
if "dtb" in cfg: dtb = self.to_list(cfg["dtb"])
|
|
if len(kernel) != 1: raise ArchBuilderConfigError("bad number of kernel")
|
|
if len(dtb) < 1: raise ArchBuilderConfigError("no device tree found")
|
|
fd, file = mkstemp()
|
|
log.debug("creating Image.gz-dtb...")
|
|
with os.fdopen(fd, "wb") as fo:
|
|
with open(kernel[0], "rb") as fi:
|
|
fo.write(gzip.compress(fi.read()))
|
|
for d in dtb:
|
|
with open(d, "rb") as fi:
|
|
fo.write(fi.read())
|
|
size = fo.tell()
|
|
log.debug("size: %u bytes", size)
|
|
cfg.pop("dtb", None)
|
|
cfg["kernel"] = file
|
|
self.temps.append(file)
|
|
|
|
def build(self):
|
|
try:
|
|
self.temps = []
|
|
cfg = self.builder.config.copy()
|
|
self.load_initramfs(cfg)
|
|
self.load_kernel(cfg)
|
|
args = self.parse_config(cfg)
|
|
match self.builder.type:
|
|
case "aboot": key = "--output"
|
|
case "avndboot": key = "--vendor_boot"
|
|
case _: raise ArchBuilderConfigError("bad type for abootimg")
|
|
args.extend([key, self.builder.device])
|
|
log.debug("run mkbootimg with %s", " ".join(args))
|
|
mkbootimg(args)
|
|
finally:
|
|
for temp in self.temps:
|
|
os.remove(temp)
|