pmbootstrap install --ondev: new option
Add initial support for the on-device installer in pmbootstrap. Let pmbootstrap create a regular split image, then prepare a new installer rootfs and copy the previously generated rootfs image into the installer rootfs. Put the installer rootfs into a new image, with reserved space. There is more to do from here, such as disabling the generation of the user account when using --ondev. But this requires support in postmarketos-ondev first, so let's build that iteratively. Related: https://wiki.postmarketos.org/wiki/On-device_installer Related: https://gitlab.com/postmarketOS/postmarketos-ondev/-/issues
This commit is contained in:
parent
8d0f3a1c55
commit
ed4072956d
|
@ -67,10 +67,11 @@ def shutdown(args, only_install_related=False):
|
||||||
path = path_outside[len(chroot):]
|
path = path_outside[len(chroot):]
|
||||||
pmb.install.losetup.umount(args, path, auto_init=False)
|
pmb.install.losetup.umount(args, path, auto_init=False)
|
||||||
|
|
||||||
# Umount device rootfs chroot
|
# Umount device rootfs and installer chroots
|
||||||
chroot_rootfs = args.work + "/chroot_rootfs_" + args.device
|
for prefix in ["rootfs", "installer"]:
|
||||||
if os.path.exists(chroot_rootfs):
|
path = f"{args.work}/chroot_{prefix}_{args.device}"
|
||||||
pmb.helpers.mount.umount_all(args, chroot_rootfs)
|
if os.path.exists(path):
|
||||||
|
pmb.helpers.mount.umount_all(args, path)
|
||||||
|
|
||||||
if not only_install_related:
|
if not only_install_related:
|
||||||
# Umount all folders inside args.work
|
# Umount all folders inside args.work
|
||||||
|
|
|
@ -53,6 +53,7 @@ def zap(args, confirm=True, dry=False, pkgs_local=False, http=False,
|
||||||
patterns = [
|
patterns = [
|
||||||
"chroot_native",
|
"chroot_native",
|
||||||
"chroot_buildroot_*",
|
"chroot_buildroot_*",
|
||||||
|
"chroot_installer_*",
|
||||||
"chroot_rootfs_*",
|
"chroot_rootfs_*",
|
||||||
]
|
]
|
||||||
if pkgs_local:
|
if pkgs_local:
|
||||||
|
|
|
@ -204,6 +204,24 @@ def install(args):
|
||||||
if args.rsync and not args.sdcard:
|
if args.rsync and not args.sdcard:
|
||||||
raise ValueError("Installation using rsync only works on sdcard.")
|
raise ValueError("Installation using rsync only works on sdcard.")
|
||||||
|
|
||||||
|
# On-device installer checks
|
||||||
|
# Note that this can't be in the mutually exclusive group that has most of
|
||||||
|
# the conflicting options, because then it would not work with --sdcard.
|
||||||
|
if args.on_device_installer:
|
||||||
|
if args.full_disk_encryption:
|
||||||
|
raise ValueError("--on-device-installer cannot be combined with"
|
||||||
|
" --fde. The user can choose to encrypt their"
|
||||||
|
" installation later in the on-device installer.")
|
||||||
|
if args.android_recovery_zip:
|
||||||
|
raise ValueError("--on-device-installer cannot be combined with"
|
||||||
|
" --android-recovery-zip (patches welcome)")
|
||||||
|
if args.no_image:
|
||||||
|
raise ValueError("--on-device-installer cannot be combined with"
|
||||||
|
" --no-image")
|
||||||
|
if args.rsync:
|
||||||
|
raise ValueError("--on-device-installer cannot be combined with"
|
||||||
|
" --rsync")
|
||||||
|
|
||||||
if not args.sdcard and args.split is None:
|
if not args.sdcard and args.split is None:
|
||||||
# Default to split if the flash method requires it
|
# Default to split if the flash method requires it
|
||||||
flasher = pmb.config.flashers.get(args.deviceinfo["flash_method"], {})
|
flasher = pmb.config.flashers.get(args.deviceinfo["flash_method"], {})
|
||||||
|
|
|
@ -11,6 +11,7 @@ import pmb.chroot.apk
|
||||||
import pmb.chroot.other
|
import pmb.chroot.other
|
||||||
import pmb.chroot.initfs
|
import pmb.chroot.initfs
|
||||||
import pmb.config
|
import pmb.config
|
||||||
|
import pmb.config.pmaports
|
||||||
import pmb.helpers.devices
|
import pmb.helpers.devices
|
||||||
import pmb.helpers.run
|
import pmb.helpers.run
|
||||||
import pmb.install.blockdevice
|
import pmb.install.blockdevice
|
||||||
|
@ -500,6 +501,56 @@ def install_recovery_zip(args):
|
||||||
logging.info("<https://postmarketos.org/recoveryzip>")
|
logging.info("<https://postmarketos.org/recoveryzip>")
|
||||||
|
|
||||||
|
|
||||||
|
def install_on_device_installer(args, step, steps):
|
||||||
|
# Generate the rootfs image
|
||||||
|
suffix_rootfs = f"rootfs_{args.device}"
|
||||||
|
install_system_image(args, 0, suffix_rootfs, step=step, steps=steps,
|
||||||
|
split=True)
|
||||||
|
step += 2
|
||||||
|
|
||||||
|
# Prepare the installer chroot
|
||||||
|
logging.info(f"*** ({step}/{steps}) CREATE ON-DEVICE INSTALLER ROOTFS ***")
|
||||||
|
step += 1
|
||||||
|
packages = ([f"device-{args.device}",
|
||||||
|
"postmarketos-ondev"] +
|
||||||
|
get_kernel_package(args, args.device) +
|
||||||
|
get_nonfree_packages(args, args.device))
|
||||||
|
suffix_installer = f"installer_{args.device}"
|
||||||
|
pmb.chroot.apk.install(args, packages, suffix_installer)
|
||||||
|
|
||||||
|
# Move rootfs image into installer chroot
|
||||||
|
img = f"{args.device}-root.img"
|
||||||
|
img_path_src = f"{args.work}/chroot_native/home/pmos/rootfs/{img}"
|
||||||
|
img_path_dest = f"{args.work}/chroot_{suffix_installer}/var/lib/rootfs.img"
|
||||||
|
logging.info(f"({suffix_installer}) add {img} as /var/lib/rootfs.img")
|
||||||
|
pmb.install.losetup.umount(args, img_path_src)
|
||||||
|
pmb.helpers.run.root(args, ["mv", img_path_src, img_path_dest])
|
||||||
|
|
||||||
|
# Run ondev-prepare, so it may generate nice configs from the channel
|
||||||
|
# properties (e.g. to display the version number), or transform the image
|
||||||
|
# file into another format. This can all be done without pmbootstrap
|
||||||
|
# changes in the postmarketos-ondev package.
|
||||||
|
logging.info(f"({suffix_installer}) ondev-prepare-image")
|
||||||
|
channel = pmb.config.pmaports.read_config(args)["channel"]
|
||||||
|
channel_cfg = pmb.config.pmaports.read_config_channel(args)
|
||||||
|
pmb.chroot.root(args, ["ondev-prepare", channel,
|
||||||
|
channel_cfg["description"],
|
||||||
|
channel_cfg["branch_pmaports"],
|
||||||
|
channel_cfg["branch_aports"],
|
||||||
|
channel_cfg["mirrordir_alpine"]], suffix_installer)
|
||||||
|
|
||||||
|
# Remove $DEVICE-boot.img (we will generate a new one if --split was
|
||||||
|
# specified, otherwise the separate boot image is not needed)
|
||||||
|
img_boot = f"{args.device}-boot.img"
|
||||||
|
logging.info(f"(native) rm {img_boot}")
|
||||||
|
pmb.chroot.root(args, ["rm", f"/home/pmos/rootfs/{img_boot}"])
|
||||||
|
|
||||||
|
# Generate installer image
|
||||||
|
size_reserve = round(os.path.getsize(img_path_dest) / 1024 / 1024) + 200
|
||||||
|
install_system_image(args, size_reserve, suffix_installer, "pmOS_install",
|
||||||
|
step, steps, args.split, args.sdcard)
|
||||||
|
|
||||||
|
|
||||||
def install(args):
|
def install(args):
|
||||||
# Sanity checks
|
# Sanity checks
|
||||||
if not args.android_recovery_zip and args.sdcard:
|
if not args.android_recovery_zip and args.sdcard:
|
||||||
|
@ -510,6 +561,8 @@ def install(args):
|
||||||
steps = 2
|
steps = 2
|
||||||
elif args.android_recovery_zip:
|
elif args.android_recovery_zip:
|
||||||
steps = 4
|
steps = 4
|
||||||
|
elif args.on_device_installer:
|
||||||
|
steps = 8
|
||||||
else:
|
else:
|
||||||
steps = 5
|
steps = 5
|
||||||
|
|
||||||
|
@ -572,6 +625,10 @@ def install(args):
|
||||||
elif args.android_recovery_zip:
|
elif args.android_recovery_zip:
|
||||||
return install_recovery_zip(args)
|
return install_recovery_zip(args)
|
||||||
|
|
||||||
install_system_image(args, 0, f"rootfs_{args.device}", split=args.split,
|
if args.on_device_installer:
|
||||||
sdcard=args.sdcard)
|
# Runs install_system_image twice
|
||||||
print_flash_info(args)
|
install_on_device_installer(args, 3, steps)
|
||||||
|
else:
|
||||||
|
install_system_image(args, 0, f"rootfs_{args.device}",
|
||||||
|
split=args.split, sdcard=args.sdcard)
|
||||||
|
print_flash_info(args, steps)
|
||||||
|
|
|
@ -25,7 +25,7 @@ def alpine_native():
|
||||||
def from_chroot_suffix(args, suffix):
|
def from_chroot_suffix(args, suffix):
|
||||||
if suffix == "native":
|
if suffix == "native":
|
||||||
return args.arch_native
|
return args.arch_native
|
||||||
if suffix == "rootfs_" + args.device:
|
if suffix in [f"rootfs_{args.device}", f"installer_{args.device}"]:
|
||||||
return args.deviceinfo["arch"]
|
return args.deviceinfo["arch"]
|
||||||
if suffix.startswith("buildroot_"):
|
if suffix.startswith("buildroot_"):
|
||||||
return suffix.split("_", 1)[1]
|
return suffix.split("_", 1)[1]
|
||||||
|
|
|
@ -557,6 +557,11 @@ def arguments():
|
||||||
install.add_argument("--no-base",
|
install.add_argument("--no-base",
|
||||||
help="do not install postmarketos-base (advanced)",
|
help="do not install postmarketos-base (advanced)",
|
||||||
action="store_false", dest="install_base")
|
action="store_false", dest="install_base")
|
||||||
|
install.add_argument("--on-device-installer", "--ondev",
|
||||||
|
action="store_true",
|
||||||
|
help="wrap the resulting image in a graphical"
|
||||||
|
" on-device installer, so the installation can"
|
||||||
|
" be customized after flashing")
|
||||||
group = install.add_mutually_exclusive_group()
|
group = install.add_mutually_exclusive_group()
|
||||||
group.add_argument("--sparse", help="generate sparse image file"
|
group.add_argument("--sparse", help="generate sparse image file"
|
||||||
" (even if unsupported by device)", default=None,
|
" (even if unsupported by device)", default=None,
|
||||||
|
|
Loading…
Reference in New Issue