mirror of
https://git.launchpad.net/livecd-rootfs
synced 2026-03-29 05:01:06 +00:00
Compare commits
No commits in common. "ubuntu/master" and "26.04.19" have entirely different histories.
ubuntu/mas
...
26.04.19
78
debian/changelog
vendored
78
debian/changelog
vendored
@ -1,81 +1,3 @@
|
||||
livecd-rootfs (26.04.26) resolute; urgency=medium
|
||||
|
||||
* Ensure snapd tracks stable and not edge anymore.
|
||||
We did remove it from multiple places, but this one was left and as a
|
||||
consequence, the latest iso was still having snapd edge.
|
||||
|
||||
-- Didier Roche-Tolomelli <didrocks@ubuntu.com> Fri, 27 Mar 2026 15:31:21 +0100
|
||||
|
||||
livecd-rootfs (26.04.25) resolute; urgency=medium
|
||||
|
||||
* bake LIVECD_ROOTFS_ROOT into config/functions, fixing some build failures
|
||||
(for at least ubuntu and some ubuntu-cpc configurations).
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Fri, 20 Mar 2026 06:47:44 +1300
|
||||
|
||||
livecd-rootfs (26.04.24) resolute; urgency=medium
|
||||
|
||||
[ Allen Abraham ]
|
||||
* Added a hook to produce a working minimal Ubuntu image using imagecraft
|
||||
|
||||
[ Michael Hudson-Doyle ]
|
||||
* Various quality of life improvements for hacking on livecd-rootfs:
|
||||
- Add a "ubuntu-test-iso" project that builds a not very useful ISO in 2-5 minutes.
|
||||
- Add a build-livefs script that takes care of copying the auto scripts and
|
||||
invoking lb clean/config/build with the right environment.
|
||||
- Add a build-livefs-lxd script to run the above script in a lxd vm.
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Mon, 16 Mar 2026 11:05:13 +1300
|
||||
|
||||
livecd-rootfs (26.04.23) resolute; urgency=medium
|
||||
|
||||
[ Tobias Heider ]
|
||||
* Fix ISO builds when KERNEL_FLAVOUR != generic.
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Mon, 02 Mar 2026 10:51:47 +1300
|
||||
|
||||
livecd-rootfs (26.04.22) resolute; urgency=medium
|
||||
|
||||
[ Oliver Gayot ]
|
||||
* Pull the model from Launchpad's lp:canonical-models
|
||||
repo, instead of having it uploaded as part of livecd-rootfs. This
|
||||
indirection makes it possible to update the models without requiring a new
|
||||
upload of livecd-rootfs every time.
|
||||
|
||||
[ Michael Hudson-Doyle ]
|
||||
* Fix two more problems with livefs-built ISOs:
|
||||
- Generate the for-iso squashfs in the right place for Kubuntu.
|
||||
- Fix confusion about the kernel path on the ISO on riscv64.
|
||||
|
||||
[ Tobias Heider ]
|
||||
* Fix pool generation when using extra_ppas.
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Thu, 26 Feb 2026 10:56:42 +1300
|
||||
|
||||
livecd-rootfs (26.04.21) resolute; urgency=medium
|
||||
|
||||
[ Dan Bungert ]
|
||||
* Update new signed models to ship latest nvidia drivers for ubuntu hybrid.
|
||||
|
||||
-- Didier Roche-Tolomelli <didrocks@ubuntu.com> Wed, 25 Feb 2026 08:38:32 +0100
|
||||
|
||||
livecd-rootfs (26.04.20) resolute; urgency=medium
|
||||
|
||||
[ Michael Raymond ]
|
||||
* Bug-fix: Only use main archive keyring when building with debootstrap
|
||||
so EOL release signatures can be verified after EOL.
|
||||
|
||||
[ Allen Abraham ]
|
||||
* Make SBOM generation optional in create_manifest function.
|
||||
|
||||
[ Michael Hudson-Doyle ]
|
||||
* 030-ubuntu-live-system-seed.binary: do not run if there is no layer to
|
||||
install the system, in particular on arm64.
|
||||
* Fix some path confusion in the new isobuilder.boot package and refactor
|
||||
grub config generation to be more string based.
|
||||
|
||||
-- Michael Hudson-Doyle <michael.hudson@ubuntu.com> Fri, 20 Feb 2026 12:45:41 +1300
|
||||
|
||||
livecd-rootfs (26.04.19) resolute; urgency=medium
|
||||
|
||||
* Translate the debian-cd tools/boot/$series/boot-$arch scripts to Python
|
||||
|
||||
1
debian/livecd-rootfs.links
vendored
1
debian/livecd-rootfs.links
vendored
@ -1 +0,0 @@
|
||||
usr/share/livecd-rootfs/live-build/build-livefs usr/bin/build-livefs
|
||||
@ -375,7 +375,7 @@ EOF
|
||||
(cd chroot && find usr/share/doc -maxdepth 1 -type d | xargs du -s | sort -nr)
|
||||
echo END docdirs
|
||||
|
||||
${LIVECD_ROOTFS_ROOT}/minimize-manual chroot
|
||||
/usr/share/livecd-rootfs/minimize-manual chroot
|
||||
|
||||
clean_debian_chroot
|
||||
fi
|
||||
@ -576,7 +576,7 @@ if [ "${MAKE_ISO}" = "yes" ]; then
|
||||
# create a for-iso.filesystem.squashfs that does.
|
||||
if [ -z "$PASSES" ]; then
|
||||
isobuild generate-sources --mountpoint=/cdrom > chroot/etc/apt/sources.list.d/cdrom.sources
|
||||
create_squashfs chroot ${PWD}/for-iso.filesystem.squashfs
|
||||
create_squashfs chroot for-iso.filesystem.squashfs
|
||||
fi
|
||||
# Link kernel and initrd files. The ${thing#${PREFIX}} expansion strips
|
||||
# the PREFIX, so "livecd.ubuntu-server.kernel-generic" becomes
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
LIVECD_ROOTFS_ROOT=${LIVECD_ROOTFS_ROOT:-/usr/share/livecd-rootfs}
|
||||
|
||||
case $ARCH:$SUBARCH in
|
||||
amd64:|amd64:generic|amd64:intel-iot|\
|
||||
arm64:|arm64:generic|arm64:raspi|arm64:snapdragon|arm64:nvidia|\
|
||||
@ -49,14 +47,12 @@ if [ -z "$MIRROR" ]; then
|
||||
fi
|
||||
|
||||
mkdir -p config
|
||||
echo "LIVECD_ROOTFS_ROOT=\"$LIVECD_ROOTFS_ROOT\"" > config/functions
|
||||
chmod --reference=${LIVECD_ROOTFS_ROOT}/live-build/functions config/functions
|
||||
cat ${LIVECD_ROOTFS_ROOT}/live-build/functions >> config/functions
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/lb_*_layered config/
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/snap-seed-parse.py config/snap-seed-parse
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/snap-seed-missing-providers.py config/snap-seed-missing-providers
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/expand-task config/expand-task
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/squashfs-exclude-files config/
|
||||
cp -af /usr/share/livecd-rootfs/live-build/functions config/functions
|
||||
cp -af /usr/share/livecd-rootfs/live-build/lb_*_layered config/
|
||||
cp -af /usr/share/livecd-rootfs/live-build/snap-seed-parse.py config/snap-seed-parse
|
||||
cp -af /usr/share/livecd-rootfs/live-build/snap-seed-missing-providers.py config/snap-seed-missing-providers
|
||||
cp -af /usr/share/livecd-rootfs/live-build/expand-task config/expand-task
|
||||
cp -af /usr/share/livecd-rootfs/live-build/squashfs-exclude-files config/
|
||||
|
||||
mkdir -p config/package-lists
|
||||
|
||||
@ -394,7 +390,7 @@ if [ -z "${IMAGEFORMAT:-}" ]; then
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
ubuntu-server:live|ubuntu-mini-iso:|ubuntu-test-iso:|ubuntu-core-installer:*)
|
||||
ubuntu-server:live|ubuntu-mini-iso:|ubuntu-core-installer:*)
|
||||
IMAGEFORMAT=plain
|
||||
;;
|
||||
esac
|
||||
@ -430,7 +426,7 @@ case $IMAGEFORMAT in
|
||||
ubuntu-server:live|ubuntu-core-installer:*)
|
||||
touch config/universe-enabled
|
||||
;;
|
||||
ubuntu-mini-iso:|ubuntu-test-iso:)
|
||||
ubuntu-mini-iso:)
|
||||
fs=none
|
||||
;;
|
||||
*)
|
||||
@ -640,7 +636,7 @@ case $PROJECT in
|
||||
esac
|
||||
|
||||
case $PROJECT in
|
||||
ubuntu-mini-iso|ubuntu-test-iso)
|
||||
ubuntu-mini-iso)
|
||||
COMPONENTS='main'
|
||||
;;
|
||||
edubuntu|ubuntu-budgie|ubuntucinnamon|ubuntukylin)
|
||||
@ -657,13 +653,6 @@ case $SUBPROJECT in
|
||||
;;
|
||||
esac
|
||||
|
||||
case $PROJECT in
|
||||
ubuntu-test-iso)
|
||||
# ubuntu-test-iso uses only add_package (not add_task) and has no
|
||||
# pool, so germinate output is never needed.
|
||||
touch config/germinate-output/structure
|
||||
;;
|
||||
*)
|
||||
if ! [ -e config/germinate-output/structure ]; then
|
||||
echo "Running germinate..."
|
||||
if [ -n "$COMPONENTS" ]; then
|
||||
@ -673,8 +662,6 @@ case $PROJECT in
|
||||
-S $SEEDMIRROR -m $MIRROR -d $SUITE,$SUITE-updates \
|
||||
-s $FLAVOUR.$SUITE $GERMINATE_ARG -a ${ARCH_VARIANT:-$ARCH})
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
# ISO build configuration. These defaults are overridden per-project below.
|
||||
#
|
||||
@ -687,9 +674,6 @@ MAKE_ISO=no
|
||||
# - "server-ship-live" for Ubuntu Server (includes server-specific packages)
|
||||
# - "" (empty) for images without a pool, like Ubuntu Core Installer
|
||||
POOL_SEED_NAME=ship-live
|
||||
# SQUASHFS_COMP: compression algorithm for squashfs images. lz4 is ~10x
|
||||
# faster than xz and useful for test builds that don't need small images.
|
||||
SQUASHFS_COMP=xz
|
||||
|
||||
# Common functionality for layered desktop images
|
||||
common_layered_desktop_image() {
|
||||
@ -820,7 +804,7 @@ do_layered_desktop_image() {
|
||||
DEFAULT_KERNEL="linux-$KERNEL_FLAVOURS"
|
||||
|
||||
if [ "$LOCALE_SUPPORT" != none ]; then
|
||||
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
|
||||
/usr/share/livecd-rootfs/checkout-translations-branch \
|
||||
https://git.launchpad.net/subiquity po \
|
||||
config/catalog-translations
|
||||
fi
|
||||
@ -1140,7 +1124,7 @@ case $PROJECT in
|
||||
NO_SQUASHFS_PASSES=ubuntu-server-minimal.ubuntu-server.installer.$flavor.netboot
|
||||
|
||||
DEFAULT_KERNEL="$kernel_metapkg"
|
||||
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
|
||||
/usr/share/livecd-rootfs/checkout-translations-branch \
|
||||
https://git.launchpad.net/subiquity po config/catalog-translations
|
||||
;;
|
||||
*)
|
||||
@ -1158,7 +1142,7 @@ case $PROJECT in
|
||||
# created in ubuntu-core-installer/hooks/05-prepare-image.binary, which
|
||||
# subiquity knows how to install.
|
||||
if [ ${SUBPROJECT} == "desktop" ]; then
|
||||
cp ${LIVECD_ROOTFS_ROOT}/live-build/${PROJECT}/ubuntu-core-desktop-24-amd64.model-assertion config/
|
||||
cp /usr/share/livecd-rootfs/live-build/${PROJECT}/ubuntu-core-desktop-24-amd64.model-assertion config/
|
||||
fi
|
||||
OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal"
|
||||
PASSES_TO_LAYERS=true
|
||||
@ -1172,7 +1156,7 @@ case $PROJECT in
|
||||
USE_BRIDGE_KERNEL=false
|
||||
DEFAULT_KERNEL="snap:pc-kernel"
|
||||
|
||||
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
|
||||
/usr/share/livecd-rootfs/checkout-translations-branch \
|
||||
https://git.launchpad.net/subiquity po config/catalog-translations
|
||||
;;
|
||||
|
||||
@ -1195,22 +1179,6 @@ case $PROJECT in
|
||||
esac
|
||||
;;
|
||||
|
||||
ubuntu-test-iso)
|
||||
OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal"
|
||||
KERNEL_FLAVOURS=virtual
|
||||
BINARY_REMOVE_LINUX=false
|
||||
MAKE_ISO=yes
|
||||
POOL_SEED_NAME=
|
||||
SQUASHFS_COMP=lz4
|
||||
PASSES_TO_LAYERS=true
|
||||
add_package base linux-$KERNEL_FLAVOURS
|
||||
add_package base.live casper
|
||||
case $ARCH in
|
||||
amd64) ;;
|
||||
*) echo "ubuntu-test-iso only supports amd64"; exit 1 ;;
|
||||
esac
|
||||
;;
|
||||
|
||||
ubuntu-base|ubuntu-oci)
|
||||
OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal"
|
||||
;;
|
||||
@ -1310,7 +1278,7 @@ case $SUBPROJECT in
|
||||
# and a variety of things fail without it.
|
||||
add_package install tzdata
|
||||
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/make-lxd-metadata.py config/make-lxd-metadata
|
||||
cp -af /usr/share/livecd-rootfs/live-build/make-lxd-metadata.py config/make-lxd-metadata
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -1429,19 +1397,15 @@ if [ -n "$PASSES" ] && [ -z "$LIVE_PASSES" ]; then
|
||||
"Either set \$LIVE_PASSES or add a pass ending with '.live'."
|
||||
fi
|
||||
|
||||
echo "DEBOOTSTRAP_OPTIONS=\"--keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg\"" >> config/bootstrap
|
||||
|
||||
echo "LB_CHROOT_HOOKS=\"$CHROOT_HOOKS\"" >> config/chroot
|
||||
echo "SUBPROJECT=\"${SUBPROJECT:-}\"" >> config/chroot
|
||||
echo "LB_DISTRIBUTION=\"$SUITE\"" >> config/chroot
|
||||
echo "IMAGEFORMAT=\"$IMAGEFORMAT\"" >> config/chroot
|
||||
echo "LIVECD_ROOTFS_ROOT=\"$LIVECD_ROOTFS_ROOT\"" >> config/common
|
||||
if [ -n "$PASSES" ]; then
|
||||
echo "PASSES=\"$PASSES\"" >> config/common
|
||||
fi
|
||||
echo "MAKE_ISO=\"$MAKE_ISO\"" >> config/common
|
||||
echo "POOL_SEED_NAME=\"$POOL_SEED_NAME\"" >> config/common
|
||||
echo "SQUASHFS_COMP=\"$SQUASHFS_COMP\"" >> config/common
|
||||
if [ -n "$NO_SQUASHFS_PASSES" ]; then
|
||||
echo "NO_SQUASHFS_PASSES=\"$NO_SQUASHFS_PASSES\"" >> config/common
|
||||
fi
|
||||
@ -1477,7 +1441,7 @@ rm -fv /etc/ssl/private/ssl-cert-snakeoil.key \
|
||||
EOF
|
||||
|
||||
case $PROJECT in
|
||||
ubuntu-cpc|ubuntu-core|ubuntu-base|ubuntu-oci|ubuntu-wsl|ubuntu-mini-iso|ubuntu-test-iso)
|
||||
ubuntu-cpc|ubuntu-core|ubuntu-base|ubuntu-oci|ubuntu-wsl|ubuntu-mini-iso)
|
||||
# ubuntu-cpc gets this added in 025-create-groups.chroot, and we do
|
||||
# not want this group in projects that are effectively just chroots
|
||||
;;
|
||||
@ -1565,11 +1529,11 @@ fi
|
||||
|
||||
case $PROJECT:${SUBPROJECT:-} in
|
||||
ubuntu-cpc:*|ubuntu-server:live|ubuntu:desktop-preinstalled| \
|
||||
ubuntu-wsl:*|ubuntu-mini-iso:*|ubuntu-test-iso:*|ubuntu:|ubuntu:dangerous|ubuntu-oem:*| \
|
||||
ubuntu-wsl:*|ubuntu-mini-iso:*|ubuntu:|ubuntu:dangerous|ubuntu-oem:*| \
|
||||
ubuntustudio:*|edubuntu:*|ubuntu-budgie:*|ubuntucinnamon:*|xubuntu:*| \
|
||||
ubuntukylin:*|ubuntu-mate:*|ubuntu-core-installer:*|lubuntu:*)
|
||||
# Ensure that most things e.g. includes.chroot are copied as is
|
||||
for entry in ${LIVECD_ROOTFS_ROOT}/live-build/${PROJECT}/*; do
|
||||
for entry in /usr/share/livecd-rootfs/live-build/${PROJECT}/*; do
|
||||
case $entry in
|
||||
*hooks*)
|
||||
# But hooks are shared across the projects with symlinks
|
||||
@ -1604,11 +1568,11 @@ esac
|
||||
case $PROJECT in
|
||||
ubuntu-oem|ubuntustudio|edubuntu|ubuntu-budgie|ubuntucinnamon| \
|
||||
xubuntu|ubuntukylin|ubuntu-mate|lubuntu)
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/ubuntu/includes.chroot \
|
||||
cp -af /usr/share/livecd-rootfs/live-build/ubuntu/includes.chroot \
|
||||
config/includes.chroot
|
||||
|
||||
LIVE_LAYER=${LIVE_PREFIX}live
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/ubuntu/includes.chroot.minimal.standard.live \
|
||||
cp -af /usr/share/livecd-rootfs/live-build/ubuntu/includes.chroot.minimal.standard.live \
|
||||
config/includes.chroot.$LIVE_LAYER
|
||||
|
||||
if [ $PROJECT != ubuntu-oem ]; then
|
||||
@ -1624,7 +1588,7 @@ esac
|
||||
|
||||
case $SUBPROJECT in
|
||||
buildd)
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/buildd/* config/
|
||||
cp -af /usr/share/livecd-rootfs/live-build/buildd/* config/
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -1648,7 +1612,7 @@ if [ "$EXTRA_PPAS" ]; then
|
||||
extra_ppa=${extra_ppa%:*}
|
||||
;;
|
||||
esac
|
||||
extra_ppa_fingerprint="$(${LIVECD_ROOTFS_ROOT}/get-ppa-fingerprint "$extra_ppa")"
|
||||
extra_ppa_fingerprint="$(/usr/share/livecd-rootfs/get-ppa-fingerprint "$extra_ppa")"
|
||||
|
||||
cat >> config/archives/extra-ppas.list.chroot <<EOF
|
||||
deb https://ppa.launchpadcontent.net/$extra_ppa/ubuntu @DISTRIBUTION@ main
|
||||
@ -1738,19 +1702,8 @@ fi
|
||||
|
||||
if [ "${MAKE_ISO}" = "yes" ]; then
|
||||
# XXX should pass --build-type here.
|
||||
${LIVECD_ROOTFS_ROOT}/live-build/gen-iso-ids \
|
||||
/usr/share/livecd-rootfs/live-build/gen-iso-ids \
|
||||
--project $PROJECT ${SUBPROJECT:+--subproject $SUBPROJECT} \
|
||||
--arch $ARCH ${SUBARCH:+--subarch $SUBARCH} ${NOW+--serial $NOW} \
|
||||
--output-dir config/iso-ids/
|
||||
fi
|
||||
|
||||
if [ -n "$http_proxy" ]; then
|
||||
mkdir -p /etc/systemd/system/snapd.service.d/
|
||||
cat > /etc/systemd/system/snapd.service.d/snap_proxy.conf <<EOF
|
||||
[Service]
|
||||
Environment="HTTP_PROXY=${http_proxy}"
|
||||
Environment="HTTPS_PROXY=${http_proxy}"
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl restart snapd.service
|
||||
fi
|
||||
|
||||
@ -1,218 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import configparser
|
||||
import os
|
||||
import pathlib
|
||||
import platform
|
||||
import subprocess
|
||||
|
||||
import click
|
||||
|
||||
|
||||
_CONFIG_FILE = pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"
|
||||
|
||||
|
||||
def _read_config() -> dict[str, str]:
|
||||
"""Read default values from the user config file if it exists.
|
||||
|
||||
The config file uses INI format with a [defaults] section, e.g.:
|
||||
|
||||
[defaults]
|
||||
http-proxy = http://squid.internal:3128/
|
||||
mirror = http://ftpmaster.internal/ubuntu/
|
||||
"""
|
||||
cp = configparser.ConfigParser()
|
||||
cp.read(_CONFIG_FILE)
|
||||
return dict(cp["defaults"]) if "defaults" in cp else {}
|
||||
|
||||
|
||||
_MACHINE_TO_ARCH = {
|
||||
"x86_64": "amd64",
|
||||
"aarch64": "arm64",
|
||||
"ppc64le": "ppc64el",
|
||||
"s390x": "s390x",
|
||||
"riscv64": "riscv64",
|
||||
"armv7l": "armhf",
|
||||
}
|
||||
|
||||
|
||||
def _default_arch():
|
||||
machine = platform.machine()
|
||||
try:
|
||||
return _MACHINE_TO_ARCH[machine]
|
||||
except KeyError:
|
||||
raise click.UsageError(
|
||||
f"Cannot determine default arch for machine {machine!r}; use --arch"
|
||||
)
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.option(
|
||||
"--work-dir",
|
||||
default=".",
|
||||
type=click.Path(file_okay=False, path_type=pathlib.Path),
|
||||
help="Working directory for the build (default: current directory)",
|
||||
)
|
||||
@click.option("--project", required=True, help="Project name (e.g. ubuntu, ubuntu-cpc)")
|
||||
@click.option("--suite", required=True, help="Ubuntu suite/series (e.g. noble)")
|
||||
@click.option("--arch", default=None, help="Target architecture (default: host arch)")
|
||||
@click.option("--arch-variant", default=None, help="Architecture variant")
|
||||
@click.option("--subproject", default=None, help="Subproject")
|
||||
@click.option("--subarch", default=None, help="Sub-architecture")
|
||||
@click.option("--channel", default=None, help="Channel")
|
||||
@click.option(
|
||||
"--image-target",
|
||||
"image_targets",
|
||||
multiple=True,
|
||||
help="Image target (may be repeated)",
|
||||
)
|
||||
@click.option("--repo-snapshot-stamp", default=None, help="Repository snapshot stamp")
|
||||
@click.option(
|
||||
"--snapshot-service-timestamp", default=None, help="Snapshot service timestamp"
|
||||
)
|
||||
@click.option("--cohort-key", default=None, help="Cohort key")
|
||||
@click.option("--datestamp", default=None, help="Datestamp (sets NOW)")
|
||||
@click.option("--image-format", default=None, help="Image format (sets IMAGEFORMAT)")
|
||||
@click.option(
|
||||
"--proposed",
|
||||
is_flag=True,
|
||||
default=False,
|
||||
help="Enable proposed pocket (sets PROPOSED=1)",
|
||||
)
|
||||
@click.option(
|
||||
"--extra-ppa", "extra_ppas", multiple=True, help="Extra PPA (may be repeated)"
|
||||
)
|
||||
@click.option(
|
||||
"--extra-snap", "extra_snaps", multiple=True, help="Extra snap (may be repeated)"
|
||||
)
|
||||
@click.option("--build-type", default=None, help="Build type")
|
||||
@click.option(
|
||||
"--http-proxy",
|
||||
default=None,
|
||||
help="HTTP proxy (sets http_proxy, HTTP_PROXY, LB_APT_HTTP_PROXY)",
|
||||
)
|
||||
@click.option(
|
||||
"--mirror",
|
||||
default=None,
|
||||
help="Ubuntu archive mirror URL (sets MIRROR)",
|
||||
)
|
||||
@click.option(
|
||||
"--debug", is_flag=True, default=False, help="Enable debug mode (set -x in lb scripts)"
|
||||
)
|
||||
def main(
|
||||
work_dir,
|
||||
project,
|
||||
suite,
|
||||
arch,
|
||||
arch_variant,
|
||||
subproject,
|
||||
subarch,
|
||||
channel,
|
||||
image_targets,
|
||||
repo_snapshot_stamp,
|
||||
snapshot_service_timestamp,
|
||||
cohort_key,
|
||||
datestamp,
|
||||
image_format,
|
||||
proposed,
|
||||
extra_ppas,
|
||||
extra_snaps,
|
||||
build_type,
|
||||
http_proxy,
|
||||
mirror,
|
||||
debug,
|
||||
):
|
||||
cfg = _read_config()
|
||||
if http_proxy is None:
|
||||
http_proxy = cfg.get("http-proxy")
|
||||
if mirror is None:
|
||||
mirror = cfg.get("mirror")
|
||||
|
||||
if arch is None:
|
||||
arch = _default_arch()
|
||||
|
||||
# Locate auto/ scripts relative to this script, following symlinks.
|
||||
# Works for: git checkout, installed deb, and /usr/bin/build-livefs symlink.
|
||||
live_build_dir = pathlib.Path(__file__).resolve().parent
|
||||
auto_source = live_build_dir / "auto"
|
||||
|
||||
# base_env is passed to both lb config and lb build
|
||||
base_env = {
|
||||
"PROJECT": project,
|
||||
"ARCH": arch,
|
||||
"LIVECD_ROOTFS_ROOT": str(live_build_dir.parent),
|
||||
}
|
||||
if arch_variant is not None:
|
||||
base_env["ARCH_VARIANT"] = arch_variant
|
||||
if subproject is not None:
|
||||
base_env["SUBPROJECT"] = subproject
|
||||
if subarch is not None:
|
||||
base_env["SUBARCH"] = subarch
|
||||
if channel is not None:
|
||||
base_env["CHANNEL"] = channel
|
||||
if image_targets:
|
||||
base_env["IMAGE_TARGETS"] = " ".join(image_targets)
|
||||
if repo_snapshot_stamp is not None:
|
||||
base_env["REPO_SNAPSHOT_STAMP"] = repo_snapshot_stamp
|
||||
if snapshot_service_timestamp is not None:
|
||||
base_env["SNAPSHOT_SERVICE_TIMESTAMP"] = snapshot_service_timestamp
|
||||
if cohort_key is not None:
|
||||
base_env["COHORT_KEY"] = cohort_key
|
||||
if http_proxy is not None:
|
||||
base_env["http_proxy"] = http_proxy
|
||||
base_env["HTTP_PROXY"] = http_proxy
|
||||
base_env["LB_APT_HTTP_PROXY"] = http_proxy
|
||||
|
||||
# config_env adds lb-config-only vars on top of base_env
|
||||
config_env = {
|
||||
**base_env,
|
||||
"SUITE": suite,
|
||||
}
|
||||
if datestamp is not None:
|
||||
config_env["NOW"] = datestamp
|
||||
if image_format is not None:
|
||||
config_env["IMAGEFORMAT"] = image_format
|
||||
if proposed:
|
||||
config_env["PROPOSED"] = "1"
|
||||
if extra_ppas:
|
||||
config_env["EXTRA_PPAS"] = " ".join(extra_ppas)
|
||||
if extra_snaps:
|
||||
config_env["EXTRA_SNAPS"] = " ".join(extra_snaps)
|
||||
if build_type is not None:
|
||||
config_env["BUILD_TYPE"] = build_type
|
||||
if mirror is not None:
|
||||
config_env["MIRROR"] = mirror
|
||||
|
||||
work_dir = work_dir.resolve()
|
||||
work_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Create/replace auto/ symlinks
|
||||
auto_dir = work_dir / "auto"
|
||||
auto_dir.mkdir(exist_ok=True)
|
||||
for script in ("config", "build", "clean"):
|
||||
link = auto_dir / script
|
||||
if link.is_symlink() or link.exists():
|
||||
link.unlink()
|
||||
link.symlink_to(auto_source / script)
|
||||
|
||||
# Write debug.sh if requested
|
||||
if debug:
|
||||
debug_dir = work_dir / "local" / "functions"
|
||||
debug_dir.mkdir(parents=True, exist_ok=True)
|
||||
(debug_dir / "debug.sh").write_text("set -x\n")
|
||||
|
||||
def run(cmd, env_extra):
|
||||
env = os.environ.copy()
|
||||
env.update(env_extra)
|
||||
if os.getuid() != 0:
|
||||
env_args = [f"{k}={v}" for k, v in env_extra.items()]
|
||||
cmd = ["sudo", "env"] + env_args + cmd
|
||||
subprocess.run(cmd, cwd=work_dir, env=env, check=True)
|
||||
|
||||
run(["lb", "clean", "--purge"], base_env)
|
||||
run(["lb", "config"], config_env)
|
||||
run(["lb", "build"], base_env)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -1,150 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import configparser
|
||||
import pathlib
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
import click
|
||||
|
||||
|
||||
_CONFIG_FILE = pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"
|
||||
|
||||
|
||||
def _read_config() -> dict[str, str]:
|
||||
cp = configparser.ConfigParser()
|
||||
cp.read(_CONFIG_FILE)
|
||||
return dict(cp["defaults"]) if "defaults" in cp else {}
|
||||
|
||||
|
||||
@click.command(
|
||||
context_settings={"ignore_unknown_options": True, "allow_extra_args": True}
|
||||
)
|
||||
@click.option("--suite", required=True, help="Ubuntu suite/series (e.g. noble)")
|
||||
@click.option(
|
||||
"--vm-name",
|
||||
default=None,
|
||||
help="LXD VM name (default: livefs-builder-{suite})",
|
||||
)
|
||||
@click.option(
|
||||
"--http-proxy",
|
||||
default=None,
|
||||
help="HTTP proxy URL for apt inside the VM (also read from build-livefs.conf)",
|
||||
)
|
||||
@click.argument("extra_args", nargs=-1, type=click.UNPROCESSED)
|
||||
def main(suite, vm_name, http_proxy, extra_args):
|
||||
livecd_rootfs_root = pathlib.Path(__file__).resolve().parent.parent
|
||||
vm_name = vm_name or f"livefs-builder-{suite}"
|
||||
host_conf = (
|
||||
pathlib.Path.home() / ".config" / "livecd-rootfs" / "build-livefs.conf"
|
||||
)
|
||||
|
||||
if http_proxy is None:
|
||||
http_proxy = _read_config().get("http-proxy")
|
||||
|
||||
result = subprocess.run(["lxc", "info", vm_name], capture_output=True)
|
||||
if result.returncode != 0:
|
||||
launch_cmd = [
|
||||
"lxc", "launch", f"ubuntu-daily:{suite}", vm_name, "--vm",
|
||||
"--config", "limits.cpu=4",
|
||||
"--config", "limits.memory=8GiB",
|
||||
"--device", "root,size=100GiB",
|
||||
]
|
||||
user_data = "#cloud-config\npackage_update: true\n"
|
||||
if http_proxy is not None:
|
||||
user_data += (
|
||||
"apt:\n"
|
||||
f" http_proxy: {http_proxy}\n"
|
||||
f" https_proxy: {http_proxy}\n"
|
||||
)
|
||||
launch_cmd += ["--config", f"user.user-data={user_data}"]
|
||||
subprocess.run(launch_cmd, check=True)
|
||||
|
||||
device_info = subprocess.run(
|
||||
["lxc", "config", "device", "show", vm_name],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
).stdout
|
||||
if "livecd-rootfs" not in device_info:
|
||||
subprocess.run(
|
||||
[
|
||||
"lxc",
|
||||
"config",
|
||||
"device",
|
||||
"add",
|
||||
vm_name,
|
||||
"livecd-rootfs",
|
||||
"disk",
|
||||
f"source={livecd_rootfs_root}",
|
||||
"path=/srv/livecd-rootfs",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
|
||||
info = subprocess.run(
|
||||
["lxc", "info", vm_name], capture_output=True, text=True, check=True
|
||||
).stdout
|
||||
if "Status: STOPPED" in info:
|
||||
subprocess.run(["lxc", "start", vm_name], check=True)
|
||||
|
||||
for _ in range(30):
|
||||
result = subprocess.run(
|
||||
["lxc", "exec", vm_name, "--", "true"], capture_output=True
|
||||
)
|
||||
if result.returncode == 0:
|
||||
break
|
||||
time.sleep(2)
|
||||
else:
|
||||
raise click.ClickException(f"VM {vm_name!r} did not become ready in time")
|
||||
|
||||
subprocess.run(
|
||||
["lxc", "exec", vm_name, "--", "cloud-init", "status", "--wait"], check=True
|
||||
)
|
||||
|
||||
subprocess.run(
|
||||
["lxc", "exec", vm_name, "--", "apt-get", "install", "-y", "livecd-rootfs"],
|
||||
check=True,
|
||||
)
|
||||
|
||||
if host_conf.exists():
|
||||
subprocess.run(
|
||||
[
|
||||
"lxc",
|
||||
"exec",
|
||||
vm_name,
|
||||
"--",
|
||||
"mkdir",
|
||||
"-p",
|
||||
"/root/.config/livecd-rootfs",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
subprocess.run(
|
||||
[
|
||||
"lxc",
|
||||
"file",
|
||||
"push",
|
||||
str(host_conf),
|
||||
f"{vm_name}/root/.config/livecd-rootfs/build-livefs.conf",
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
|
||||
subprocess.run(
|
||||
[
|
||||
"lxc",
|
||||
"exec",
|
||||
vm_name,
|
||||
"--",
|
||||
"/srv/livecd-rootfs/live-build/build-livefs",
|
||||
"--suite",
|
||||
suite,
|
||||
*extra_args,
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -44,7 +44,6 @@ create_manifest() {
|
||||
local base_default_sbom_name="ubuntu-cloud-image-$(grep "VERSION_ID" $chroot_root/etc/os-release | cut --delimiter "=" --field 2 | tr -d '"')-${ARCH}-$(date +%Y%m%dT%H:%M:%S)"
|
||||
local sbom_file_name=${3:-"${base_default_sbom_name}.spdx"}
|
||||
local sbom_document_name=${4:-"${base_default_sbom_name}"}
|
||||
local should_include_sbom=${5:-"true"}
|
||||
local sbom_log=${sbom_document_name}.log
|
||||
echo "create_manifest chroot_root: ${chroot_root}"
|
||||
dpkg-query --show --admindir="${chroot_root}/var/lib/dpkg" > ${target_file}
|
||||
@ -55,7 +54,6 @@ create_manifest() {
|
||||
echo "create_manifest creating file listing."
|
||||
local target_filelist=${2%.manifest}.filelist
|
||||
(cd "${chroot_root}" && find -xdev) | sort > "${target_filelist}"
|
||||
if [ "$should_include_sbom" = "true" ]; then
|
||||
# only creating sboms for CPC project at this time
|
||||
if [[ ! $(which cpc-sbom) ]]; then
|
||||
# ensure the tool is installed
|
||||
@ -72,9 +70,6 @@ create_manifest() {
|
||||
else
|
||||
echo "SBOM generation succeeded. see ${sbom_log} for details"
|
||||
fi
|
||||
else
|
||||
echo "SBOM generation skipped"
|
||||
fi
|
||||
fi
|
||||
echo "create_manifest finished"
|
||||
}
|
||||
@ -188,8 +183,8 @@ setup_mountpoint() {
|
||||
mount sysfs-live -t sysfs "$mountpoint/sys"
|
||||
mount securityfs -t securityfs "$mountpoint/sys/kernel/security"
|
||||
# Provide more up to date apparmor features, matching target kernel
|
||||
mount -o bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/generic "$mountpoint/sys/kernel/security/apparmor/features/"
|
||||
mount -o bind ${LIVECD_ROOTFS_ROOT}/live-build/seccomp/generic.actions_avail "$mountpoint/proc/sys/kernel/seccomp/actions_avail"
|
||||
mount -o bind /usr/share/livecd-rootfs/live-build/apparmor/generic "$mountpoint/sys/kernel/security/apparmor/features/"
|
||||
mount -o bind /usr/share/livecd-rootfs/live-build/seccomp/generic.actions_avail "$mountpoint/proc/sys/kernel/seccomp/actions_avail"
|
||||
# cgroup2 mount for LP: 1944004
|
||||
mount -t cgroup2 none "$mountpoint/sys/fs/cgroup"
|
||||
mount -t tmpfs none "$mountpoint/tmp"
|
||||
@ -408,7 +403,7 @@ create_squashfs() {
|
||||
squashfs_file="$2"
|
||||
config_dir="$PWD/config"
|
||||
(cd $rootfs_dir &&
|
||||
mksquashfs . $squashfs_file -no-progress -xattrs -comp "${SQUASHFS_COMP:-xz}" \
|
||||
mksquashfs . $squashfs_file -no-progress -xattrs -comp xz \
|
||||
-ef "$config_dir/squashfs-exclude-files")
|
||||
|
||||
}
|
||||
@ -573,7 +568,7 @@ _snap_post_process() {
|
||||
# If the 'core' snap is not present, assume we are coreXX-only and
|
||||
# install the snapd snap.
|
||||
channel=stable
|
||||
if [ "$SUBPROJECT" = "dangerous" ]; then
|
||||
if [ "$PROJECT" = "ubuntu" -o "$SUBPROJECT" = "dangerous" ]; then
|
||||
channel=edge
|
||||
fi
|
||||
if [ ! -f ${snaps_dir}/core_[0-9]*.snap ]; then
|
||||
@ -860,7 +855,7 @@ snap_validate_seed() {
|
||||
fi
|
||||
if [ ${boot_filename} != undefined ]; then # we have a known boot file so we can proceed with checking for features to mount
|
||||
kern_major_min=$(readlink --canonicalize --no-newline ${CHROOT_ROOT}/boot/${boot_filename} | grep --extended-regexp --only-matching --max-count 1 '[0-9]+\.[0-9]+')
|
||||
if [ -d ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/${kern_major_min} ]; then
|
||||
if [ -d /usr/share/livecd-rootfs/live-build/apparmor/${kern_major_min} ]; then
|
||||
# if an Ubuntu version has different kernel apparmor features between LTS and HWE kernels
|
||||
# a snap pre-seeding issue can occur, where the incorrect apparmor features are reported
|
||||
# basic copy of a directory structure overriding the "generic" feature set
|
||||
@ -868,7 +863,7 @@ snap_validate_seed() {
|
||||
|
||||
# Bind kernel apparmor directory to feature directory for snap preseeding
|
||||
umount "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
mount --bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/${kern_major_min} "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
mount --bind /usr/share/livecd-rootfs/live-build/apparmor/${kern_major_min} "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -894,7 +889,7 @@ snap_validate_seed() {
|
||||
# mount generic apparmor feature again (cleanup)
|
||||
if [ -d /build/config/hooks.d/extra/apparmor/${kern_major_min} ]; then
|
||||
umount "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
mount -o bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/generic "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
mount -o bind /usr/share/livecd-rootfs/live-build/apparmor/generic "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
fi
|
||||
|
||||
}
|
||||
@ -1254,7 +1249,7 @@ setup_cidata() {
|
||||
local mountpoint=$(mktemp -d)
|
||||
mkfs.vfat -F 32 -n CIDATA ${cidata_dev}
|
||||
mount ${cidata_dev} ${mountpoint}
|
||||
cp ${LIVECD_ROOTFS_ROOT}/live-build/cidata/* ${mountpoint}
|
||||
cp /usr/share/livecd-rootfs/live-build/cidata/* ${mountpoint}
|
||||
cat >>${mountpoint}/meta-data.sample <<END
|
||||
#instance-id: iid-$(openssl rand -hex 8)
|
||||
|
||||
@ -1454,5 +1449,5 @@ gpt_root_partition_uuid() {
|
||||
# is importable, and uses config/iso-dir as the standard working directory
|
||||
# for ISO metadata and intermediate files.
|
||||
isobuild () {
|
||||
PYTHONPATH=${LIVECD_ROOTFS_ROOT}/live-build/ ${LIVECD_ROOTFS_ROOT}/live-build/isobuild --workdir config/iso-dir "$@"
|
||||
PYTHONPATH=/usr/share/livecd-rootfs/live-build/ /usr/share/livecd-rootfs/live-build/isobuild --workdir config/iso-dir "$@"
|
||||
}
|
||||
|
||||
@ -42,7 +42,6 @@ project_to_capproject_map = {
|
||||
"ubuntu-core-installer": "Ubuntu-Core-Installer",
|
||||
"ubuntu-mate": "Ubuntu-MATE",
|
||||
"ubuntu-mini-iso": "Ubuntu-Mini-ISO",
|
||||
"ubuntu-test-iso": "Ubuntu-Test-ISO",
|
||||
"ubuntu-oem": "Ubuntu OEM",
|
||||
"ubuntu-server": "Ubuntu-Server",
|
||||
"ubuntu-unity": "Ubuntu-Unity",
|
||||
|
||||
@ -108,10 +108,10 @@ class AptStateManager:
|
||||
def in_release_path(self) -> pathlib.Path:
|
||||
"""Return the path to the InRelease file.
|
||||
|
||||
This ignores all but the first path.
|
||||
Will raise Error if there isn't at least one match.
|
||||
This assumes exactly one InRelease file matches the pattern.
|
||||
Will raise ValueError if there are 0 or multiple matches.
|
||||
"""
|
||||
[path] = self.apt_root.joinpath("var/lib/apt/lists").glob(
|
||||
f"*ubuntu.com*_dists_{self.series}_InRelease"
|
||||
f"*_dists_{self.series}_InRelease"
|
||||
)
|
||||
return path
|
||||
|
||||
@ -17,7 +17,6 @@ def make_boot_configurator_for_arch(
|
||||
arch: str,
|
||||
logger: "Logger",
|
||||
apt_state: "AptStateManager",
|
||||
workdir: pathlib.Path,
|
||||
iso_root: pathlib.Path,
|
||||
) -> "BaseBootConfigurator":
|
||||
"""Factory function to create boot configurator for a specific architecture."""
|
||||
@ -25,23 +24,23 @@ def make_boot_configurator_for_arch(
|
||||
case "amd64":
|
||||
from .amd64 import AMD64BootConfigurator
|
||||
|
||||
return AMD64BootConfigurator(logger, apt_state, workdir, iso_root)
|
||||
return AMD64BootConfigurator(logger, apt_state, iso_root)
|
||||
case "arm64":
|
||||
from .arm64 import ARM64BootConfigurator
|
||||
|
||||
return ARM64BootConfigurator(logger, apt_state, workdir, iso_root)
|
||||
return ARM64BootConfigurator(logger, apt_state, iso_root)
|
||||
case "ppc64el":
|
||||
from .ppc64el import PPC64ELBootConfigurator
|
||||
|
||||
return PPC64ELBootConfigurator(logger, apt_state, workdir, iso_root)
|
||||
return PPC64ELBootConfigurator(logger, apt_state, iso_root)
|
||||
case "riscv64":
|
||||
from .riscv64 import RISCV64BootConfigurator
|
||||
|
||||
return RISCV64BootConfigurator(logger, apt_state, workdir, iso_root)
|
||||
return RISCV64BootConfigurator(logger, apt_state, iso_root)
|
||||
case "s390x":
|
||||
from .s390x import S390XBootConfigurator
|
||||
|
||||
return S390XBootConfigurator(logger, apt_state, workdir, iso_root)
|
||||
return S390XBootConfigurator(logger, apt_state, iso_root)
|
||||
case _:
|
||||
raise ValueError(f"Unsupported architecture: {arch}")
|
||||
|
||||
|
||||
@ -3,9 +3,8 @@
|
||||
import pathlib
|
||||
import shutil
|
||||
|
||||
from .base import default_kernel_params
|
||||
from .grub import copy_grub_modules
|
||||
from .uefi import UEFIBootConfigurator
|
||||
from .base import default_kernel_params
|
||||
|
||||
|
||||
CALAMARES_PROJECTS = ["kubuntu", "lubuntu"]
|
||||
@ -52,13 +51,16 @@ class AMD64BootConfigurator(UEFIBootConfigurator):
|
||||
opts.extend(
|
||||
[
|
||||
"--grub2-mbr",
|
||||
self.scratch.joinpath("boot_hybrid.img"),
|
||||
self.grub_dir.joinpath("usr/lib/grub/i386-pc/boot_hybrid.img"),
|
||||
]
|
||||
)
|
||||
|
||||
# ## Set up the mkisofs options for UEFI boot.
|
||||
opts.extend(self.get_uefi_mkisofs_opts())
|
||||
|
||||
# ## Add cd-boot-tree to the ISO
|
||||
opts.append(str(self.boot_tree))
|
||||
|
||||
return opts
|
||||
|
||||
def extract_files(self) -> None:
|
||||
@ -69,113 +71,115 @@ class AMD64BootConfigurator(UEFIBootConfigurator):
|
||||
|
||||
# AMD64-specific: Add BIOS/legacy boot files
|
||||
with self.logger.logged("adding BIOS/legacy boot files"):
|
||||
grub_pc_pkg_dir = self.scratch.joinpath("grub-pc-pkg")
|
||||
self.download_and_extract_package("grub-pc-bin", grub_pc_pkg_dir)
|
||||
self.download_and_extract_package("grub-pc-bin", self.grub_dir)
|
||||
|
||||
grub_boot_dir = self.iso_root.joinpath("boot", "grub", "i386-pc")
|
||||
grub_boot_dir = self.boot_tree.joinpath("boot", "grub", "i386-pc")
|
||||
grub_boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
src_grub_dir = grub_pc_pkg_dir.joinpath("usr", "lib", "grub", "i386-pc")
|
||||
src_grub_dir = self.grub_dir.joinpath("usr", "lib", "grub", "i386-pc")
|
||||
|
||||
shutil.copy(src_grub_dir.joinpath("eltorito.img"), grub_boot_dir)
|
||||
shutil.copy(src_grub_dir.joinpath("boot_hybrid.img"), self.scratch)
|
||||
|
||||
copy_grub_modules(
|
||||
grub_pc_pkg_dir,
|
||||
self.iso_root,
|
||||
"i386-pc",
|
||||
["*.mod", "*.lst", "*.o"],
|
||||
self.copy_grub_modules(
|
||||
src_grub_dir, grub_boot_dir, ["*.mod", "*.lst", "*.o"]
|
||||
)
|
||||
|
||||
def generate_grub_config(self) -> str:
|
||||
"""Generate grub.cfg content for AMD64."""
|
||||
result = self.grub_header()
|
||||
def generate_grub_config(self) -> None:
|
||||
"""Generate grub.cfg and loopback.cfg for the boot tree."""
|
||||
boot_grub_dir = self.boot_tree.joinpath("boot", "grub")
|
||||
boot_grub_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
grub_cfg = boot_grub_dir.joinpath("grub.cfg")
|
||||
|
||||
if self.project == "ubuntu-mini-iso":
|
||||
result += """\
|
||||
menuentry "Choose an Ubuntu version to install" {
|
||||
self.write_grub_header(grub_cfg)
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
"""menuentry "Choose an Ubuntu version to install" {
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz iso-chooser-menu ip=dhcp ---
|
||||
initrd /casper/initrd
|
||||
}
|
||||
"""
|
||||
return result
|
||||
)
|
||||
return
|
||||
|
||||
# Generate grub.cfg
|
||||
kernel_params = default_kernel_params(self.project)
|
||||
|
||||
# Write common GRUB header
|
||||
self.write_grub_header(grub_cfg)
|
||||
|
||||
# Main menu entry
|
||||
result += f"""\
|
||||
menuentry "Try or Install {self.humanproject}" {{
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
f"""menuentry "Try or Install {self.humanproject}" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz {kernel_params}
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
# All but server get safe-graphics mode
|
||||
if self.project != "ubuntu-server":
|
||||
result += f"""\
|
||||
menuentry "{self.humanproject} (safe graphics)" {{
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
f"""menuentry "{self.humanproject} (safe graphics)" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz nomodeset {kernel_params}
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
# ubiquity based projects get OEM mode
|
||||
if "maybe-ubiquity" in kernel_params:
|
||||
oem_kernel_params = kernel_params.replace(
|
||||
"maybe-ubiquity", "only-ubiquity oem-config/enable=true"
|
||||
)
|
||||
result += f"""\
|
||||
menuentry "OEM install (for manufacturers)" {{
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
f"""menuentry "OEM install (for manufacturers)" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz {oem_kernel_params}
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
# Calamares-based projects get OEM mode
|
||||
if self.project in CALAMARES_PROJECTS:
|
||||
result += f"""\
|
||||
menuentry "OEM install (for manufacturers)" {{
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
f"""menuentry "OEM install (for manufacturers)" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz {kernel_params} oem-config/enable=true
|
||||
initrd /casper/initrd
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
# Currently only server is built with HWE, hence no safe-graphics/OEM
|
||||
if self.hwe:
|
||||
result += f"""\
|
||||
menuentry "{self.humanproject} with the HWE kernel" {{
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
f"""menuentry "{self.humanproject} with the HWE kernel" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/hwe-vmlinuz {kernel_params}
|
||||
initrd /casper/hwe-initrd
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
# UEFI Entries (wrapped in grub_platform check for dual BIOS/UEFI support)
|
||||
uefi_menu_entries = self.uefi_menu_entries()
|
||||
# Create the loopback config, based on the main config
|
||||
with grub_cfg.open("r") as f:
|
||||
content = f.read()
|
||||
|
||||
result += f"""\
|
||||
grub_platform
|
||||
if [ "$grub_platform" = "efi" ]; then
|
||||
{uefi_menu_entries}\
|
||||
fi
|
||||
"""
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def generate_loopback_config(grub_content: str) -> str:
|
||||
"""Derive loopback.cfg from grub.cfg content.
|
||||
|
||||
Strips the header (up to menu_color_highlight) and the UEFI
|
||||
trailer (from grub_platform to end), and adds iso-scan/filename
|
||||
to linux lines.
|
||||
"""
|
||||
lines = grub_content.split("\n")
|
||||
# sed: delete from line 1 to menu_color_highlight, delete from
|
||||
# grub_platform to end and replace '---' with
|
||||
# 'iso-scan/filename=${iso_path} ---' in lines with 'linux'
|
||||
lines = content.split("\n")
|
||||
start_idx = 0
|
||||
for i, line in enumerate(lines):
|
||||
if "menu_color_highlight" in line:
|
||||
@ -198,19 +202,16 @@ fi
|
||||
for line in loopback_lines
|
||||
]
|
||||
|
||||
return "\n".join(loopback_lines)
|
||||
loopback_cfg = boot_grub_dir.joinpath("loopback.cfg")
|
||||
with loopback_cfg.open("w") as f:
|
||||
f.write("\n".join(loopback_lines))
|
||||
|
||||
def make_bootable(
|
||||
self,
|
||||
project: str,
|
||||
capproject: str,
|
||||
subarch: str,
|
||||
hwe: bool,
|
||||
) -> None:
|
||||
"""Make the ISO bootable, including generating loopback.cfg."""
|
||||
super().make_bootable(project, capproject, subarch, hwe)
|
||||
grub_cfg = self.iso_root.joinpath("boot", "grub", "grub.cfg")
|
||||
grub_content = grub_cfg.read_text()
|
||||
self.iso_root.joinpath("boot", "grub", "loopback.cfg").write_text(
|
||||
self.generate_loopback_config(grub_content)
|
||||
)
|
||||
# UEFI Entries (wrapped in grub_platform check for dual BIOS/UEFI support)
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write("grub_platform\n")
|
||||
f.write('if [ "$grub_platform" = "efi" ]; then\n')
|
||||
|
||||
self.write_uefi_menu_entries(grub_cfg)
|
||||
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write("fi\n")
|
||||
|
||||
@ -26,6 +26,7 @@ class ARM64BootConfigurator(UEFIBootConfigurator):
|
||||
opts.extend(self.get_uefi_mkisofs_opts())
|
||||
# ARM64-specific: partition cylinder alignment
|
||||
opts.extend(["-partition_cyl_align", "all"])
|
||||
opts.append(self.boot_tree)
|
||||
return opts
|
||||
|
||||
def extract_files(self) -> None:
|
||||
@ -33,15 +34,19 @@ class ARM64BootConfigurator(UEFIBootConfigurator):
|
||||
with self.logger.logged("extracting ARM64 boot files"):
|
||||
self.extract_uefi_files()
|
||||
|
||||
def generate_grub_config(self) -> str:
|
||||
def generate_grub_config(self) -> None:
|
||||
"""Generate grub.cfg for ARM64."""
|
||||
kernel_params = default_kernel_params(self.project)
|
||||
|
||||
result = self.grub_header()
|
||||
grub_cfg = self.grub_dir.joinpath("grub.cfg")
|
||||
|
||||
# Write common GRUB header
|
||||
self.write_grub_header(grub_cfg)
|
||||
|
||||
# ARM64-specific: Snapdragon workarounds
|
||||
result += f"""\
|
||||
set cmdline=
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
"""set cmdline=
|
||||
smbios --type 4 --get-string 5 --set proc_version
|
||||
regexp "Snapdragon.*" "$proc_version"
|
||||
if [ $? = 0 ]; then
|
||||
@ -54,14 +59,16 @@ if [ $? = 0 ]; then
|
||||
fi
|
||||
|
||||
menuentry "Try or Install {self.humanproject}" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz $cmdline {kernel_params} console=tty0
|
||||
initrd /casper/initrd
|
||||
\tset gfxpayload=keep
|
||||
\tlinux\t/casper/vmlinuz $cmdline {kernel_params} console=tty0
|
||||
\tinitrd\t/casper/initrd
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
# HWE kernel option if available
|
||||
result += self.hwe_menu_entry(
|
||||
self.write_hwe_menu_entry(
|
||||
grub_cfg,
|
||||
"vmlinuz",
|
||||
f"{kernel_params} console=tty0",
|
||||
extra_params="$cmdline ",
|
||||
@ -71,6 +78,4 @@ menuentry "Try or Install {self.humanproject}" {{
|
||||
# but it's not actually set anywhere in the grub.cfg, so we omit it here
|
||||
|
||||
# UEFI Entries (ARM64 is UEFI-only, no grub_platform check needed)
|
||||
result += self.uefi_menu_entries()
|
||||
|
||||
return result
|
||||
self.write_uefi_menu_entries(grub_cfg)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
"""Base classes and helper functions for boot configuration."""
|
||||
|
||||
import pathlib
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
from abc import ABC, abstractmethod
|
||||
@ -33,14 +34,17 @@ class BaseBootConfigurator(ABC):
|
||||
self,
|
||||
logger: Logger,
|
||||
apt_state: AptStateManager,
|
||||
workdir: pathlib.Path,
|
||||
iso_root: pathlib.Path,
|
||||
) -> None:
|
||||
self.logger = logger
|
||||
self.apt_state = apt_state
|
||||
self.scratch = workdir.joinpath("boot-stuff")
|
||||
self.iso_root = iso_root
|
||||
|
||||
def create_dirs(self, workdir):
|
||||
self.scratch = workdir.joinpath("boot-stuff")
|
||||
self.scratch.mkdir(exist_ok=True)
|
||||
self.boot_tree = self.scratch.joinpath("cd-boot-tree")
|
||||
|
||||
def download_and_extract_package(
|
||||
self, pkg_name: str, target_dir: pathlib.Path
|
||||
) -> None:
|
||||
@ -61,6 +65,14 @@ class BaseBootConfigurator(ABC):
|
||||
dpkg_proc.stdout.close()
|
||||
tar_proc.communicate()
|
||||
|
||||
def copy_grub_modules(
|
||||
self, src_dir: pathlib.Path, dest_dir: pathlib.Path, extensions: list[str]
|
||||
) -> None:
|
||||
"""Copy GRUB module files matching given extensions from src to dest."""
|
||||
for ext in extensions:
|
||||
for file in src_dir.glob(ext):
|
||||
shutil.copy(file, dest_dir)
|
||||
|
||||
@abstractmethod
|
||||
def extract_files(self) -> None:
|
||||
"""Download and extract bootloader packages to the boot tree.
|
||||
@ -83,6 +95,7 @@ class BaseBootConfigurator(ABC):
|
||||
|
||||
def make_bootable(
|
||||
self,
|
||||
workdir: pathlib.Path,
|
||||
project: str,
|
||||
capproject: str,
|
||||
subarch: str,
|
||||
@ -93,6 +106,6 @@ class BaseBootConfigurator(ABC):
|
||||
self.humanproject = capproject.replace("-", " ")
|
||||
self.subarch = subarch
|
||||
self.hwe = hwe
|
||||
self.scratch.mkdir(exist_ok=True)
|
||||
self.create_dirs(workdir)
|
||||
with self.logger.logged("configuring boot"):
|
||||
self.extract_files()
|
||||
|
||||
@ -7,31 +7,17 @@ from abc import abstractmethod
|
||||
from .base import BaseBootConfigurator
|
||||
|
||||
|
||||
def copy_grub_common_files(grub_pkg_dir: pathlib.Path, iso_root: pathlib.Path) -> None:
|
||||
fonts_dir = iso_root.joinpath("boot", "grub", "fonts")
|
||||
def copy_grub_common_files_to_boot_tree(
|
||||
grub_dir: pathlib.Path, boot_tree: pathlib.Path
|
||||
) -> None:
|
||||
fonts_dir = boot_tree.joinpath("boot", "grub", "fonts")
|
||||
fonts_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
src = grub_pkg_dir.joinpath("usr", "share", "grub", "unicode.pf2")
|
||||
src = grub_dir.joinpath("usr", "share", "grub", "unicode.pf2")
|
||||
dst = fonts_dir.joinpath("unicode.pf2")
|
||||
shutil.copy(src, dst)
|
||||
|
||||
|
||||
def copy_grub_modules(
|
||||
grub_pkg_dir: pathlib.Path,
|
||||
iso_root: pathlib.Path,
|
||||
grub_target: str,
|
||||
patterns: list[str],
|
||||
) -> None:
|
||||
"""Copy GRUB module files matching given patterns from src to dest."""
|
||||
src_dir = grub_pkg_dir.joinpath("usr", "lib", "grub", grub_target)
|
||||
dest_dir = iso_root.joinpath("boot", "grub", grub_target)
|
||||
dest_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
for pat in patterns:
|
||||
for file in src_dir.glob(pat):
|
||||
shutil.copy(file, dest_dir)
|
||||
|
||||
|
||||
class GrubBootConfigurator(BaseBootConfigurator):
|
||||
"""Base class for architectures that use GRUB (all except S390X).
|
||||
|
||||
@ -39,66 +25,79 @@ class GrubBootConfigurator(BaseBootConfigurator):
|
||||
Subclasses must implement generate_grub_config().
|
||||
"""
|
||||
|
||||
def grub_header(self, include_loadfont: bool = True) -> str:
|
||||
"""Return common GRUB config header (timeout, colors).
|
||||
def create_dirs(self, workdir):
|
||||
super().create_dirs(workdir)
|
||||
self.grub_dir = self.boot_tree.joinpath("grub")
|
||||
|
||||
def setup_grub_common_files(self) -> None:
|
||||
"""Copy common GRUB files (fonts, etc.) to boot tree."""
|
||||
copy_grub_common_files_to_boot_tree(self.grub_dir, self.boot_tree)
|
||||
|
||||
def write_grub_header(
|
||||
self, grub_cfg: pathlib.Path, include_loadfont: bool = True
|
||||
) -> None:
|
||||
"""Write common GRUB config header (timeout, colors).
|
||||
|
||||
Args:
|
||||
grub_cfg: Path to grub.cfg file
|
||||
include_loadfont: Whether to include 'loadfont unicode'
|
||||
(not needed for RISC-V)
|
||||
"""
|
||||
result = "set timeout=30\n\n"
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write("set timeout=30\n\n")
|
||||
if include_loadfont:
|
||||
result += "loadfont unicode\n\n"
|
||||
result += """\
|
||||
set menu_color_normal=white/black
|
||||
f.write("loadfont unicode\n\n")
|
||||
f.write(
|
||||
"""set menu_color_normal=white/black
|
||||
set menu_color_highlight=black/light-gray
|
||||
|
||||
"""
|
||||
return result
|
||||
)
|
||||
|
||||
def hwe_menu_entry(
|
||||
def write_hwe_menu_entry(
|
||||
self,
|
||||
grub_cfg: pathlib.Path,
|
||||
kernel_name: str,
|
||||
kernel_params: str,
|
||||
extra_params: str = "",
|
||||
) -> str:
|
||||
"""Return HWE kernel menu entry if HWE is enabled.
|
||||
) -> None:
|
||||
"""Write HWE kernel menu entry if HWE is enabled.
|
||||
|
||||
Args:
|
||||
grub_cfg: Path to grub.cfg file
|
||||
kernel_name: Kernel binary name (vmlinuz or vmlinux)
|
||||
kernel_params: Kernel parameters to append
|
||||
extra_params: Additional parameters (e.g., console=tty0, $cmdline)
|
||||
"""
|
||||
if not self.hwe:
|
||||
return ""
|
||||
return f"""\
|
||||
menuentry "{self.humanproject} with the HWE kernel" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/hwe-{kernel_name} {extra_params}{kernel_params}
|
||||
initrd /casper/hwe-initrd
|
||||
if self.hwe:
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
f"""menuentry "{self.humanproject} with the HWE kernel" {{
|
||||
\tset gfxpayload=keep
|
||||
\tlinux\t/casper/hwe-{kernel_name} {extra_params}{kernel_params}
|
||||
\tinitrd\t/casper/hwe-initrd
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def generate_grub_config(self) -> str:
|
||||
"""Generate grub.cfg content.
|
||||
def generate_grub_config(self) -> None:
|
||||
"""Generate grub.cfg configuration file.
|
||||
|
||||
Each GRUB-based architecture must implement this to return the
|
||||
GRUB configuration.
|
||||
Each GRUB-based architecture must implement this to create its
|
||||
specific GRUB configuration.
|
||||
"""
|
||||
...
|
||||
|
||||
def make_bootable(
|
||||
self,
|
||||
workdir: pathlib.Path,
|
||||
project: str,
|
||||
capproject: str,
|
||||
subarch: str,
|
||||
hwe: bool,
|
||||
) -> None:
|
||||
"""Make the ISO bootable by extracting files and generating GRUB config."""
|
||||
super().make_bootable(project, capproject, subarch, hwe)
|
||||
super().make_bootable(workdir, project, capproject, subarch, hwe)
|
||||
with self.logger.logged("generating grub config"):
|
||||
content = self.generate_grub_config()
|
||||
grub_dir = self.iso_root.joinpath("boot", "grub")
|
||||
grub_dir.mkdir(parents=True, exist_ok=True)
|
||||
grub_dir.joinpath("grub.cfg").write_text(content)
|
||||
self.generate_grub_config()
|
||||
|
||||
@ -3,11 +3,7 @@
|
||||
import pathlib
|
||||
import shutil
|
||||
|
||||
from .grub import (
|
||||
copy_grub_common_files,
|
||||
copy_grub_modules,
|
||||
GrubBootConfigurator,
|
||||
)
|
||||
from .grub import GrubBootConfigurator
|
||||
from .base import default_kernel_params
|
||||
|
||||
|
||||
@ -16,26 +12,28 @@ class PPC64ELBootConfigurator(GrubBootConfigurator):
|
||||
|
||||
def mkisofs_opts(self) -> list[str | pathlib.Path]:
|
||||
"""Return mkisofs options for PPC64EL."""
|
||||
return []
|
||||
# Add cd-boot-tree to the ISO
|
||||
return [self.boot_tree]
|
||||
|
||||
def extract_files(self) -> None:
|
||||
"""Download and extract bootloader packages for PPC64EL."""
|
||||
self.logger.log("extracting PPC64EL boot files")
|
||||
|
||||
grub_pkg_dir = self.scratch.joinpath("grub-pkg")
|
||||
|
||||
# Download and extract bootloader packages
|
||||
self.download_and_extract_package("grub2-common", grub_pkg_dir)
|
||||
self.download_and_extract_package("grub-ieee1275-bin", grub_pkg_dir)
|
||||
self.download_and_extract_package("grub2-common", self.grub_dir)
|
||||
self.download_and_extract_package("grub-ieee1275-bin", self.grub_dir)
|
||||
|
||||
# Add common files for GRUB to tree
|
||||
copy_grub_common_files(grub_pkg_dir, self.iso_root)
|
||||
self.setup_grub_common_files()
|
||||
|
||||
# Add IEEE1275 ppc boot files
|
||||
ppc_dir = self.iso_root.joinpath("ppc")
|
||||
ppc_dir.mkdir()
|
||||
ppc_dir = self.boot_tree.joinpath("ppc")
|
||||
ppc_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
src_grub_dir = grub_pkg_dir.joinpath("usr", "lib", "grub", "powerpc-ieee1275")
|
||||
grub_boot_dir = self.boot_tree.joinpath("boot", "grub", "powerpc-ieee1275")
|
||||
grub_boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
src_grub_dir = self.grub_dir.joinpath("usr", "lib", "grub", "powerpc-ieee1275")
|
||||
|
||||
# Copy bootinfo.txt to ppc directory
|
||||
shutil.copy(
|
||||
@ -45,30 +43,33 @@ class PPC64ELBootConfigurator(GrubBootConfigurator):
|
||||
# Copy eltorito.elf to boot/grub as powerpc.elf
|
||||
shutil.copy(
|
||||
src_grub_dir.joinpath("eltorito.elf"),
|
||||
self.iso_root.joinpath("boot", "grub", "powerpc.elf"),
|
||||
self.boot_tree.joinpath("boot", "grub", "powerpc.elf"),
|
||||
)
|
||||
|
||||
# Copy GRUB modules
|
||||
copy_grub_modules(
|
||||
grub_pkg_dir, self.iso_root, "powerpc-ieee1275", ["*.mod", "*.lst"]
|
||||
)
|
||||
self.copy_grub_modules(src_grub_dir, grub_boot_dir, ["*.mod", "*.lst"])
|
||||
|
||||
def generate_grub_config(self) -> str:
|
||||
def generate_grub_config(self) -> None:
|
||||
"""Generate grub.cfg for PPC64EL."""
|
||||
kernel_params = default_kernel_params(self.project)
|
||||
|
||||
result = self.grub_header()
|
||||
grub_cfg = self.grub_dir.joinpath("grub.cfg")
|
||||
|
||||
# Write common GRUB header
|
||||
self.write_grub_header(grub_cfg)
|
||||
|
||||
# Main menu entry
|
||||
result += f"""\
|
||||
menuentry "Try or Install {self.humanproject}" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinux quiet {kernel_params}
|
||||
initrd /casper/initrd
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
f"""menuentry "Try or Install {self.humanproject}" {{
|
||||
\tset gfxpayload=keep
|
||||
\tlinux\t/casper/vmlinux quiet {kernel_params}
|
||||
\tinitrd\t/casper/initrd
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
# HWE kernel option if available
|
||||
result += self.hwe_menu_entry("vmlinux", kernel_params, extra_params="quiet ")
|
||||
|
||||
return result
|
||||
self.write_hwe_menu_entry(
|
||||
grub_cfg, "vmlinux", kernel_params, extra_params="quiet "
|
||||
)
|
||||
|
||||
@ -3,31 +3,35 @@
|
||||
import pathlib
|
||||
import shutil
|
||||
|
||||
from .grub import GrubBootConfigurator, copy_grub_common_files, copy_grub_modules
|
||||
from .grub import GrubBootConfigurator
|
||||
|
||||
|
||||
def copy_unsigned_monolithic_grub(
|
||||
grub_pkg_dir: pathlib.Path,
|
||||
efi_suffix: str,
|
||||
grub_target: str,
|
||||
iso_root: pathlib.Path,
|
||||
def copy_unsigned_monolithic_grub_to_boot_tree(
|
||||
grub_dir: pathlib.Path, efi_suffix: str, grub_target: str, boot_tree: pathlib.Path
|
||||
) -> None:
|
||||
efi_boot_dir = iso_root.joinpath("EFI", "boot")
|
||||
efi_boot_dir = boot_tree.joinpath("EFI", "boot")
|
||||
efi_boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
shutil.copy(
|
||||
grub_pkg_dir.joinpath(
|
||||
grub_dir.joinpath(
|
||||
"usr",
|
||||
"lib",
|
||||
"grub",
|
||||
grub_target,
|
||||
f"{grub_target}-efi",
|
||||
"monolithic",
|
||||
f"gcd{efi_suffix}.efi",
|
||||
),
|
||||
efi_boot_dir.joinpath(f"boot{efi_suffix}.efi"),
|
||||
)
|
||||
|
||||
copy_grub_modules(grub_pkg_dir, iso_root, grub_target, ["*.mod", "*.lst"])
|
||||
grub_boot_dir = boot_tree.joinpath("boot", "grub", f"{grub_target}-efi")
|
||||
grub_boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
src_grub_dir = grub_dir.joinpath("usr", "lib", "grub", f"{grub_target}-efi")
|
||||
for mod_file in src_grub_dir.glob("*.mod"):
|
||||
shutil.copy(mod_file, grub_boot_dir)
|
||||
for lst_file in src_grub_dir.glob("*.lst"):
|
||||
shutil.copy(lst_file, grub_boot_dir)
|
||||
|
||||
|
||||
class RISCV64BootConfigurator(GrubBootConfigurator):
|
||||
@ -70,19 +74,16 @@ class RISCV64BootConfigurator(GrubBootConfigurator):
|
||||
self.logger.log("extracting RISC-V64 boot files")
|
||||
u_boot_dir = self.scratch.joinpath("u-boot-sifive")
|
||||
|
||||
grub_pkg_dir = self.scratch.joinpath("grub-pkg")
|
||||
|
||||
# Download and extract bootloader packages
|
||||
self.download_and_extract_package("grub2-common", grub_pkg_dir)
|
||||
self.download_and_extract_package("grub-efi-riscv64-bin", grub_pkg_dir)
|
||||
self.download_and_extract_package("grub-efi-riscv64-unsigned", grub_pkg_dir)
|
||||
self.download_and_extract_package("grub2-common", self.grub_dir)
|
||||
self.download_and_extract_package("grub-efi-riscv64-bin", self.grub_dir)
|
||||
self.download_and_extract_package("grub-efi-riscv64-unsigned", self.grub_dir)
|
||||
self.download_and_extract_package("u-boot-sifive", u_boot_dir)
|
||||
|
||||
# Add GRUB to tree
|
||||
copy_grub_common_files(grub_pkg_dir, self.iso_root)
|
||||
|
||||
copy_unsigned_monolithic_grub(
|
||||
grub_pkg_dir, "riscv64", "riscv64-efi", self.iso_root
|
||||
self.setup_grub_common_files()
|
||||
copy_unsigned_monolithic_grub_to_boot_tree(
|
||||
self.grub_dir, "riscv64", "riscv64", self.boot_tree
|
||||
)
|
||||
|
||||
# Extract DTBs to tree
|
||||
@ -106,15 +107,23 @@ class RISCV64BootConfigurator(GrubBootConfigurator):
|
||||
)
|
||||
|
||||
# Copy DTBs if they exist
|
||||
dtb_dir = self.iso_root.joinpath("dtb")
|
||||
dtb_dir = self.boot_tree.joinpath("dtb")
|
||||
dtb_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
firmware_dir = kernel_layer.joinpath("usr", "lib", "firmware")
|
||||
device_tree_files = list(firmware_dir.glob("*/device-tree/*"))
|
||||
|
||||
for dtb_file in firmware_dir.glob("*/device-tree/*"):
|
||||
if device_tree_files:
|
||||
for dtb_file in device_tree_files:
|
||||
if dtb_file.is_file():
|
||||
shutil.copy(dtb_file, dtb_dir)
|
||||
|
||||
# Clean up kernel layer
|
||||
shutil.rmtree(kernel_layer)
|
||||
|
||||
# Copy tree contents to live-media rootfs
|
||||
self.logger.run(["cp", "-aT", self.boot_tree, self.iso_root], check=True)
|
||||
|
||||
# Create ESP image with GRUB and dtbs
|
||||
efi_img = self.scratch.joinpath("efi.img")
|
||||
self.logger.run(
|
||||
@ -122,34 +131,41 @@ class RISCV64BootConfigurator(GrubBootConfigurator):
|
||||
)
|
||||
|
||||
# Add EFI files to ESP
|
||||
efi_dir = self.iso_root.joinpath("EFI")
|
||||
efi_dir = self.boot_tree.joinpath("EFI")
|
||||
self.logger.run(["mcopy", "-s", "-i", efi_img, efi_dir, "::/."], check=True)
|
||||
|
||||
# Add DTBs to ESP
|
||||
self.logger.run(["mcopy", "-s", "-i", efi_img, dtb_dir, "::/."], check=True)
|
||||
|
||||
def generate_grub_config(self) -> str:
|
||||
def generate_grub_config(self) -> None:
|
||||
"""Generate grub.cfg for RISC-V64."""
|
||||
result = self.grub_header(include_loadfont=False)
|
||||
grub_dir = self.iso_root.joinpath("boot", "grub")
|
||||
grub_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
grub_cfg = grub_dir.joinpath("grub.cfg")
|
||||
|
||||
# Write GRUB header (without loadfont for RISC-V)
|
||||
self.write_grub_header(grub_cfg, include_loadfont=False)
|
||||
|
||||
# Main menu entry
|
||||
result += f"""\
|
||||
menuentry "Try or Install {self.humanproject}" {{
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinux efi=debug sysctl.kernel.watchdog_thresh=60 ---
|
||||
initrd /casper/initrd
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
f"""menuentry "Try or Install {self.humanproject}" {{
|
||||
\tset gfxpayload=keep
|
||||
\tlinux\t/casper/vmlinux efi=debug sysctl.kernel.watchdog_thresh=60 ---
|
||||
\tinitrd\t/casper/initrd
|
||||
}}
|
||||
"""
|
||||
)
|
||||
|
||||
# HWE kernel option if available
|
||||
result += self.hwe_menu_entry(
|
||||
self.write_hwe_menu_entry(
|
||||
grub_cfg,
|
||||
"vmlinux",
|
||||
"---",
|
||||
extra_params="efi=debug sysctl.kernel.watchdog_thresh=60 ",
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
def post_process_iso(self, iso_path: pathlib.Path) -> None:
|
||||
"""Add GPT partitions with U-Boot for SiFive Unmatched board.
|
||||
|
||||
|
||||
@ -4,31 +4,29 @@ import pathlib
|
||||
import shutil
|
||||
|
||||
from ..builder import Logger
|
||||
from .grub import copy_grub_common_files, GrubBootConfigurator
|
||||
from .grub import GrubBootConfigurator
|
||||
|
||||
|
||||
def copy_signed_shim_grub(
|
||||
shim_pkg_dir: pathlib.Path,
|
||||
grub_pkg_dir: pathlib.Path,
|
||||
def copy_signed_shim_grub_to_boot_tree(
|
||||
shim_dir: pathlib.Path,
|
||||
grub_dir: pathlib.Path,
|
||||
efi_suffix: str,
|
||||
grub_target: str,
|
||||
iso_root: pathlib.Path,
|
||||
boot_tree: pathlib.Path,
|
||||
) -> None:
|
||||
efi_boot_dir = iso_root.joinpath("EFI", "boot")
|
||||
efi_boot_dir = boot_tree.joinpath("EFI", "boot")
|
||||
efi_boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
shutil.copy(
|
||||
shim_pkg_dir.joinpath(
|
||||
"usr", "lib", "shim", f"shim{efi_suffix}.efi.signed.latest"
|
||||
),
|
||||
shim_dir.joinpath("usr", "lib", "shim", f"shim{efi_suffix}.efi.signed.latest"),
|
||||
efi_boot_dir.joinpath(f"boot{efi_suffix}.efi"),
|
||||
)
|
||||
shutil.copy(
|
||||
shim_pkg_dir.joinpath("usr", "lib", "shim", f"mm{efi_suffix}.efi"),
|
||||
shim_dir.joinpath("usr", "lib", "shim", f"mm{efi_suffix}.efi"),
|
||||
efi_boot_dir.joinpath(f"mm{efi_suffix}.efi"),
|
||||
)
|
||||
shutil.copy(
|
||||
grub_pkg_dir.joinpath(
|
||||
grub_dir.joinpath(
|
||||
"usr",
|
||||
"lib",
|
||||
"grub",
|
||||
@ -38,10 +36,10 @@ def copy_signed_shim_grub(
|
||||
efi_boot_dir.joinpath(f"grub{efi_suffix}.efi"),
|
||||
)
|
||||
|
||||
grub_boot_dir = iso_root.joinpath("boot", "grub", f"{grub_target}-efi")
|
||||
grub_boot_dir = boot_tree.joinpath("boot", "grub", f"{grub_target}-efi")
|
||||
grub_boot_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
src_grub_dir = grub_pkg_dir.joinpath("usr", "lib", "grub", f"{grub_target}-efi")
|
||||
src_grub_dir = grub_dir.joinpath("usr", "lib", "grub", f"{grub_target}-efi")
|
||||
for mod_file in src_grub_dir.glob("*.mod"):
|
||||
shutil.copy(mod_file, grub_boot_dir)
|
||||
for lst_file in src_grub_dir.glob("*.lst"):
|
||||
@ -49,10 +47,10 @@ def copy_signed_shim_grub(
|
||||
|
||||
|
||||
def create_eltorito_esp_image(
|
||||
logger: Logger, iso_root: pathlib.Path, target_file: pathlib.Path
|
||||
logger: Logger, boot_tree: pathlib.Path, target_file: pathlib.Path
|
||||
) -> None:
|
||||
logger.log("creating El Torito ESP image")
|
||||
efi_dir = iso_root.joinpath("EFI")
|
||||
efi_dir = boot_tree.joinpath("EFI")
|
||||
|
||||
# Calculate size: du -s --apparent-size --block-size=1024 + 1024
|
||||
result = logger.run(
|
||||
@ -86,6 +84,10 @@ class UEFIBootConfigurator(GrubBootConfigurator):
|
||||
grub_target: str = ""
|
||||
arch: str = ""
|
||||
|
||||
def create_dirs(self, workdir):
|
||||
super().create_dirs(workdir)
|
||||
self.shim_dir = self.boot_tree.joinpath("shim")
|
||||
|
||||
def get_uefi_grub_packages(self) -> list[str]:
|
||||
"""Return list of UEFI GRUB packages to download."""
|
||||
return [
|
||||
@ -96,42 +98,40 @@ class UEFIBootConfigurator(GrubBootConfigurator):
|
||||
|
||||
def extract_uefi_files(self) -> None:
|
||||
"""Extract common UEFI files to boot tree."""
|
||||
|
||||
shim_pkg_dir = self.scratch.joinpath("shim-pkg")
|
||||
grub_pkg_dir = self.scratch.joinpath("grub-pkg")
|
||||
|
||||
# Download UEFI packages
|
||||
self.download_and_extract_package("shim-signed", shim_pkg_dir)
|
||||
self.download_and_extract_package("shim-signed", self.shim_dir)
|
||||
for pkg in self.get_uefi_grub_packages():
|
||||
self.download_and_extract_package(pkg, grub_pkg_dir)
|
||||
self.download_and_extract_package(pkg, self.grub_dir)
|
||||
|
||||
# Add common files for GRUB to tree
|
||||
copy_grub_common_files(grub_pkg_dir, self.iso_root)
|
||||
self.setup_grub_common_files()
|
||||
|
||||
# Add EFI GRUB to tree
|
||||
copy_signed_shim_grub(
|
||||
shim_pkg_dir,
|
||||
grub_pkg_dir,
|
||||
copy_signed_shim_grub_to_boot_tree(
|
||||
self.shim_dir,
|
||||
self.grub_dir,
|
||||
self.efi_suffix,
|
||||
self.grub_target,
|
||||
self.iso_root,
|
||||
self.boot_tree,
|
||||
)
|
||||
|
||||
# Create ESP image for El-Torito catalog and hybrid boot
|
||||
create_eltorito_esp_image(
|
||||
self.logger, self.iso_root, self.scratch.joinpath("cd-boot-efi.img")
|
||||
self.logger, self.boot_tree, self.scratch.joinpath("cd-boot-efi.img")
|
||||
)
|
||||
|
||||
def uefi_menu_entries(self) -> str:
|
||||
"""Return UEFI firmware menu entries."""
|
||||
return """\
|
||||
menuentry 'Boot from next volume' {
|
||||
exit 1
|
||||
def write_uefi_menu_entries(self, grub_cfg: pathlib.Path) -> None:
|
||||
"""Write UEFI firmware menu entries."""
|
||||
with grub_cfg.open("a") as f:
|
||||
f.write(
|
||||
"""menuentry 'Boot from next volume' {
|
||||
\texit 1
|
||||
}
|
||||
menuentry 'UEFI Firmware Settings' {
|
||||
fwsetup
|
||||
\tfwsetup
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
def get_uefi_mkisofs_opts(self) -> list[str | pathlib.Path]:
|
||||
"""Return common UEFI mkisofs options."""
|
||||
|
||||
@ -268,7 +268,7 @@ class ISOBuilder:
|
||||
target.hardlink_to(src)
|
||||
|
||||
kernel_name = "vmlinuz"
|
||||
if self.arch in ("ppc64el", "riscv64"):
|
||||
if self.arch == "ppc64el":
|
||||
kernel_name = "vmlinux"
|
||||
|
||||
with self.logger.logged(
|
||||
@ -278,10 +278,11 @@ class ISOBuilder:
|
||||
for path in artifact_dir.glob(f"{filename_prefix}*.{ext}"):
|
||||
newname = path.name[len(filename_prefix) :]
|
||||
link(path, newname)
|
||||
|
||||
for kernel_path in artifact_dir.glob(f"{filename_prefix}kernel*"):
|
||||
suffix = kernel_path.name[len(filename_prefix) + len("kernel") :]
|
||||
prefix = "hwe-" if suffix.endswith("-hwe") else ""
|
||||
for suffix, prefix in (
|
||||
("-generic", ""),
|
||||
("-generic-hwe", "hwe-"),
|
||||
):
|
||||
if artifact_dir.joinpath(f"{filename_prefix}kernel{suffix}").exists():
|
||||
link(
|
||||
artifact_dir.joinpath(f"{filename_prefix}kernel{suffix}"),
|
||||
f"{prefix}{kernel_name}",
|
||||
@ -297,10 +298,10 @@ class ISOBuilder:
|
||||
self.arch,
|
||||
self.logger,
|
||||
self.apt_state,
|
||||
self.workdir,
|
||||
self.iso_root,
|
||||
)
|
||||
configurator.make_bootable(
|
||||
self.workdir,
|
||||
project,
|
||||
capproject,
|
||||
subarch,
|
||||
@ -340,9 +341,9 @@ class ISOBuilder:
|
||||
self.arch,
|
||||
self.logger,
|
||||
self.apt_state,
|
||||
self.workdir,
|
||||
self.iso_root,
|
||||
)
|
||||
configurator.create_dirs(self.workdir)
|
||||
mkisofs_opts = configurator.mkisofs_opts()
|
||||
cmd: list[str | pathlib.Path] = ["xorriso"]
|
||||
if self.arch == "riscv64":
|
||||
|
||||
@ -180,7 +180,7 @@ build_layered_squashfs () {
|
||||
# Operate on the upperdir directly, so that we are only
|
||||
# modifying mtime on files that are actually changed in
|
||||
# this layer. LP: #2107332
|
||||
${LIVECD_ROOTFS_ROOT}/sync-mtime chroot "$overlay_dir"
|
||||
/usr/share/livecd-rootfs/sync-mtime chroot "$overlay_dir"
|
||||
fi
|
||||
|
||||
create_squashfs "${overlay_dir}" ${squashfs_f}
|
||||
@ -206,7 +206,7 @@ build_layered_squashfs () {
|
||||
if [ -f config/seeded-languages ]; then
|
||||
usc_opts="$usc_opts --langs $(cat config/seeded-languages)"
|
||||
fi
|
||||
${LIVECD_ROOTFS_ROOT}/update-source-catalog source $usc_opts
|
||||
/usr/share/livecd-rootfs/update-source-catalog source $usc_opts
|
||||
else
|
||||
echo "No catalog entry template for $pass"
|
||||
fi
|
||||
@ -227,7 +227,7 @@ done
|
||||
|
||||
if [ -n "$DEFAULT_KERNEL" -a -f livecd.${PROJECT_FULL}.install-sources.yaml ]; then
|
||||
write_kernel_yaml "$DEFAULT_KERNEL" "$BRIDGE_KERNEL_REASONS"
|
||||
${LIVECD_ROOTFS_ROOT}/update-source-catalog merge \
|
||||
/usr/share/livecd-rootfs/update-source-catalog merge \
|
||||
--output livecd.${PROJECT_FULL}.install-sources.yaml \
|
||||
--template config/kernel.yaml
|
||||
fi
|
||||
|
||||
@ -237,7 +237,7 @@ create_chroot_pass () {
|
||||
lb chroot_interactive ${*}
|
||||
|
||||
# Misc ubuntu cleanup and post-layer configuration
|
||||
${LIVECD_ROOTFS_ROOT}/minimize-manual chroot
|
||||
/usr/share/livecd-rootfs/minimize-manual chroot
|
||||
clean_debian_chroot
|
||||
|
||||
Chroot chroot "dpkg-query -W" > chroot.packages.${pass}
|
||||
|
||||
@ -11,7 +11,6 @@ case ${PASS:-} in
|
||||
esac
|
||||
|
||||
. config/binary
|
||||
. config/common
|
||||
. config/functions
|
||||
|
||||
case ${SUBPROJECT} in
|
||||
@ -57,4 +56,4 @@ PROJECT_FULL=$PROJECT${SUBARCH:+-$SUBARCH}
|
||||
usc_opts="--output livecd.${PROJECT_FULL}.install-sources.yaml \
|
||||
--template config/edge.catalog-in.yaml \
|
||||
--size 0"
|
||||
${LIVECD_ROOTFS_ROOT}/update-source-catalog source $usc_opts
|
||||
/usr/share/livecd-rootfs/update-source-catalog source $usc_opts
|
||||
|
||||
@ -1 +0,0 @@
|
||||
datasource_list: [ OpenStack, None ]
|
||||
@ -1,2 +0,0 @@
|
||||
dsmode: local
|
||||
instance_id: ubuntu-server
|
||||
@ -1,104 +0,0 @@
|
||||
name: ubuntu-minimal
|
||||
version: "0.1"
|
||||
base: bare
|
||||
build-base: devel
|
||||
summary: Minimal Ubuntu image for CPC
|
||||
description: A minimal Ubuntu image to be built using livecd-rootfs by CPC
|
||||
|
||||
platforms:
|
||||
amd64:
|
||||
|
||||
volumes:
|
||||
pc:
|
||||
schema: gpt
|
||||
structure:
|
||||
# 1. BIOS Boot
|
||||
- name: bios-boot
|
||||
type: 21686148-6449-6E6F-744E-656564454649
|
||||
role: system-boot
|
||||
filesystem: vfat
|
||||
size: 4M
|
||||
partition-number: 14
|
||||
# 2. EFI System Partition
|
||||
- name: efi
|
||||
type: C12A7328-F81F-11D2-BA4B-00A0C93EC93B
|
||||
filesystem: vfat
|
||||
filesystem-label: UEFI
|
||||
role: system-boot
|
||||
size: 106M
|
||||
partition-number: 15
|
||||
# 3. Linux Extended Boot
|
||||
- name: boot
|
||||
type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4
|
||||
filesystem: ext4
|
||||
filesystem-label: BOOT
|
||||
role: system-data
|
||||
size: 1G
|
||||
partition-number: 13
|
||||
# 4. Root Filesystem
|
||||
- name: rootfs
|
||||
type: 0FC63DAF-8483-4772-8E79-3D69D8477DE4
|
||||
filesystem: ext4
|
||||
filesystem-label: cloudimg-rootfs
|
||||
role: system-data
|
||||
size: 3G
|
||||
partition-number: 1
|
||||
|
||||
filesystems:
|
||||
default:
|
||||
- mount: "/"
|
||||
device: "(volume/pc/rootfs)"
|
||||
- mount: "/boot"
|
||||
device: "(volume/pc/boot)"
|
||||
- mount: "/boot/efi"
|
||||
device: "(volume/pc/efi)"
|
||||
|
||||
parts:
|
||||
rootfs:
|
||||
plugin: nil
|
||||
build-packages: ["mmdebstrap"]
|
||||
override-build: |
|
||||
mmdebstrap --arch $CRAFT_ARCH_BUILD_FOR \
|
||||
--mode=sudo \
|
||||
--format=dir \
|
||||
--variant=minbase \
|
||||
--include=apt \
|
||||
resolute \
|
||||
$CRAFT_PART_INSTALL/ \
|
||||
http://archive.ubuntu.com/ubuntu/
|
||||
rm -r $CRAFT_PART_INSTALL/dev/*
|
||||
mkdir $CRAFT_PART_INSTALL/boot/efi
|
||||
organize:
|
||||
'*': (overlay)/
|
||||
|
||||
packages:
|
||||
plugin: nil
|
||||
overlay-packages:
|
||||
- ubuntu-server-minimal
|
||||
- grub2-common
|
||||
- grub-pc
|
||||
- shim-signed
|
||||
- linux-image-generic
|
||||
overlay-script: |
|
||||
rm $CRAFT_OVERLAY/etc/cloud/cloud.cfg.d/90_dpkg.cfg
|
||||
|
||||
snaps:
|
||||
plugin: nil
|
||||
after: [packages]
|
||||
overlay-script: |
|
||||
env SNAPPY_STORE_NO_CDN=1 snap prepare-image --classic \
|
||||
--arch=amd64 --snap snapd --snap core24 "" $CRAFT_OVERLAY
|
||||
|
||||
fstab:
|
||||
plugin: nil
|
||||
after: [snaps]
|
||||
overlay-script: |
|
||||
cat << EOF > $CRAFT_OVERLAY/etc/fstab
|
||||
LABEL=cloudimg-rootfs / ext4 discard,errors=remount-ro 0 1
|
||||
LABEL=BOOT /boot ext4 defaults 0 2
|
||||
LABEL=UEFI /boot/efi vfat umask=0077 0 1
|
||||
EOF
|
||||
|
||||
cloud-init:
|
||||
plugin: dump
|
||||
source: cloud-init/
|
||||
@ -1,81 +0,0 @@
|
||||
#!/bin/bash -eux
|
||||
|
||||
. config/functions
|
||||
|
||||
ARCH="${ARCH:-}"
|
||||
SUBPROJECT="${SUBPROJECT:-}"
|
||||
|
||||
# We want to start off imagecraft builds with just amd64 support right now
|
||||
case $ARCH in
|
||||
amd64)
|
||||
;;
|
||||
*)
|
||||
echo "imagecraft build is currently not implemented for ARCH=${ARCH:-unset}."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
case ${SUBPROJECT} in
|
||||
minimized)
|
||||
;;
|
||||
*)
|
||||
echo "imagecraft build is currently not implemented for SUBPROJECT=${SUBPROJECT:-unset}."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
_src_d=$(dirname $(readlink -f ${0}))
|
||||
|
||||
snap install imagecraft --classic --channel latest/edge
|
||||
|
||||
cp -r "$_src_d"/imagecraft-configs/* .
|
||||
|
||||
CRAFT_BUILD_ENVIRONMENT=host imagecraft --verbosity debug pack
|
||||
|
||||
# We are using this function instead of mount_disk_image from functions
|
||||
# because imagecraft doesn't currently support XBOOTLDR's GUID and
|
||||
# mount_disk_image has an explicit check for the XBOOTLDR GUID
|
||||
# TODO: Use mount_disk_image once imagecraft supports XBOOTLDR's GUID
|
||||
mount_image_partitions() {
|
||||
mount_image "${disk_image}" "$ROOT_PARTITION"
|
||||
|
||||
# Making sure that the loop device is ready
|
||||
partprobe "${loop_device}"
|
||||
udevadm settle
|
||||
mount_partition "${rootfs_dev_mapper}" "$mountpoint"
|
||||
mount "${loop_device}p13" "$mountpoint/boot"
|
||||
mount "${loop_device}p15" "$mountpoint/boot/efi"
|
||||
}
|
||||
|
||||
install_grub_on_image() {
|
||||
divert_grub "$mountpoint"
|
||||
chroot "$mountpoint" grub-install --target=i386-pc "${loop_device}"
|
||||
chroot "$mountpoint" update-grub
|
||||
undivert_grub "$mountpoint"
|
||||
|
||||
echo "GRUB for BIOS boot installed successfully."
|
||||
}
|
||||
|
||||
unmount_image_partitions() {
|
||||
umount "$mountpoint/boot/efi"
|
||||
umount "$mountpoint/boot"
|
||||
|
||||
umount_partition "$mountpoint"
|
||||
rmdir "$mountpoint"
|
||||
}
|
||||
|
||||
disk_image="pc.img"
|
||||
ROOT_PARTITION=1
|
||||
mountpoint=$(mktemp -d)
|
||||
|
||||
mount_image_partitions
|
||||
|
||||
install_grub_on_image
|
||||
create_manifest "$mountpoint/" "$PWD/livecd.ubuntu-cpc.imagecraft.manifest" "$PWD/livecd.ubuntu-cpc.imagecraft.spdx" "cloud-image-$ARCH-$(date +%Y%m%dT%H:%M:%S)" "false"
|
||||
|
||||
unmount_image_partitions
|
||||
|
||||
clean_loops
|
||||
trap - EXIT
|
||||
|
||||
qemu-img convert -f raw -O qcow2 "${disk_image}" livecd.ubuntu-cpc.imagecraft.img
|
||||
@ -6,4 +6,3 @@ depends qcow2
|
||||
depends vmdk
|
||||
depends vagrant
|
||||
depends wsl
|
||||
depends imagecraft-image
|
||||
|
||||
@ -1,5 +0,0 @@
|
||||
base/imagecraft-image.binary
|
||||
|
||||
provides livecd.ubuntu-cpc.imagecraft.img
|
||||
provides livecd.ubuntu-cpc.imagecraft.manifest
|
||||
provides livecd.ubuntu-cpc.imagecraft.filelist
|
||||
@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
mkdir -p "etc/initramfs-tools/conf.d"
|
||||
cat > etc/initramfs-tools/conf.d/casperize.conf <<EOF
|
||||
export CASPER_GENERATE_UUID=1
|
||||
EOF
|
||||
@ -1,15 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Copy kernel/initrd artifacts for isobuilder to consume.
|
||||
# The MAKE_ISO flow in auto/build expects ${PREFIX}.kernel-* and
|
||||
# ${PREFIX}.initrd-* files. With --linux-packages=none live-build won't
|
||||
# create them, so we do it here (mirroring ubuntu-mini-iso's approach).
|
||||
# This hook runs for every pass; exit early when the kernel isn't present.
|
||||
|
||||
set -eu
|
||||
|
||||
[ -e chroot/boot/vmlinuz ] || exit 0
|
||||
[ -e chroot/boot/initrd.img ] || exit 0
|
||||
|
||||
PREFIX="livecd.${PROJECT}"
|
||||
cp chroot/boot/vmlinuz "${PREFIX}.kernel-generic"
|
||||
cp chroot/boot/initrd.img "${PREFIX}.initrd-generic"
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
# create the system seed for TPM-backed FDE in the live layer of the installer.
|
||||
|
||||
set -eu
|
||||
set -eux
|
||||
|
||||
case ${PASS:-} in
|
||||
*.live)
|
||||
@ -13,15 +13,8 @@ case ${PASS:-} in
|
||||
esac
|
||||
|
||||
. config/binary
|
||||
. config/common
|
||||
. config/functions
|
||||
|
||||
set -x
|
||||
|
||||
if ! echo $PASSES | grep --quiet enhanced-secureboot; then
|
||||
# Only run this hook if there is going to be a layer that installs it...
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Naive conversion from YAML to JSON. This is needed because yq is in universe
|
||||
# (but jq is not).
|
||||
@ -133,25 +126,8 @@ get_components()
|
||||
|
||||
# env SNAPPY_STORE_NO_CDN=1 snap known --remote model series=16 brand-id=canonical model=ubuntu-classic-2410-amd64 > config/classic-model.model
|
||||
#
|
||||
|
||||
# We used to have the models included in livecd-rootfs itself, but now we pull
|
||||
# them from the Launchpad git mirror.
|
||||
canonical_models_tree=$(mktemp -d)
|
||||
git clone --depth 1 https://git.launchpad.net/canonical-models -- "${canonical_models_tree}"
|
||||
|
||||
cleanup_repo()
|
||||
{
|
||||
rm -rf -- "${canonical_models_tree}"
|
||||
}
|
||||
|
||||
trap cleanup_repo EXIT
|
||||
|
||||
echo 'Checked out canonical-models revision' "$(git -C "${canonical_models_tree}" rev-parse HEAD)"
|
||||
|
||||
model_version=$(release_ver | sed 's/\.//')
|
||||
|
||||
dangerous_model="${canonical_models_tree}"/ubuntu-classic-"${model_version}"-amd64-dangerous.model
|
||||
stable_model="${canonical_models_tree}"/ubuntu-classic-"${model_version}"-amd64.model
|
||||
dangerous_model=/usr/share/livecd-rootfs/live-build/${PROJECT}/ubuntu-classic-amd64-dangerous.model
|
||||
stable_model=/usr/share/livecd-rootfs/live-build/${PROJECT}/ubuntu-classic-amd64.model
|
||||
|
||||
prepare_args=()
|
||||
|
||||
|
||||
109
live-build/ubuntu/ubuntu-classic-amd64-dangerous.model
Normal file
109
live-build/ubuntu/ubuntu-classic-amd64-dangerous.model
Normal file
@ -0,0 +1,109 @@
|
||||
type: model
|
||||
authority-id: canonical
|
||||
series: 16
|
||||
brand-id: canonical
|
||||
model: ubuntu-classic-2604-amd64-dangerous
|
||||
architecture: amd64
|
||||
base: core24
|
||||
classic: true
|
||||
distribution: ubuntu
|
||||
grade: dangerous
|
||||
snaps:
|
||||
-
|
||||
default-channel: classic-26.04/edge
|
||||
id: UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH
|
||||
name: pc
|
||||
type: gadget
|
||||
-
|
||||
components:
|
||||
nvidia-580-uda-ko:
|
||||
presence: optional
|
||||
nvidia-580-uda-user:
|
||||
presence: optional
|
||||
default-channel: 26.04/beta
|
||||
id: pYVQrBcKmBa0mZ4CCN7ExT6jH8rY1hza
|
||||
name: pc-kernel
|
||||
type: kernel
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: amcUKQILKXHHTlmSa7NMdnXSx02dNeeT
|
||||
name: core22
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: dwTAh7MZZ01zyriOZErqd1JynQLiOGvM
|
||||
name: core24
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: cUqM61hRuZAJYmIS898Ux66VY61gBbZf
|
||||
name: core26
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4
|
||||
name: snapd
|
||||
type: snapd
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: EISPgh06mRh1vordZY9OZ34QHdd7OrdR
|
||||
name: bare
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: HyhSEBPv3vHsW6uOHkQR384NgI7S6zpj
|
||||
name: mesa-2404
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/edge
|
||||
id: EI0D1KHjP8XiwMZKqSjuh6W8zvcowUVP
|
||||
name: firmware-updater
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/edge
|
||||
id: FppXWunWzuRT2NUT9CwoBPNJNZBYOCk0
|
||||
name: desktop-security-center
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/edge
|
||||
id: aoc5lfC8aUd2VL8VpvynUJJhGXp5K6Dj
|
||||
name: prompting-client
|
||||
type: app
|
||||
-
|
||||
default-channel: 2/edge
|
||||
id: gjf3IPXoRiipCu9K0kVu52f0H56fIksg
|
||||
name: snap-store
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: jZLfBRzf1cYlYysIjD2bwSzNtngY0qit
|
||||
name: gtk-common-themes
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: 3wdHCAVyZEmYsCMFDE9qt92UV8rC8Wdk
|
||||
name: firefox
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: ew7OxpbRTxfK7ImpIygRR85lkxvU7Pzt
|
||||
name: gnome-46-2404
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/edge
|
||||
id: IrwRHakqtzhFRHJOOPxKVPU0Kk7Erhcu
|
||||
name: snapd-desktop-integration
|
||||
type: app
|
||||
timestamp: 2025-12-09T12:00:00.0Z
|
||||
sign-key-sha3-384: 9tydnLa6MTJ-jaQTFUXEwHl1yRx7ZS4K5cyFDhYDcPzhS7uyEkDxdUjg9g08BtNn
|
||||
|
||||
AcLBXAQAAQoABgUCaUFt7QAKCRDgT5vottzAEhdnD/92LBcQm3iw/kPao4KqGE0OhfXDFd7Z6+Qv
|
||||
A1Dlzz6Cw0tuj0r5aZH7vJQCx4kC1Eaoi8apg3XhqAyhr74/MsIwMhPPL8qcSNv8ZWruoGwFp/rx
|
||||
M6NSBKc6hrYqACYfEkBwfq9SgmIDQKFeBVudwswLK2SN58wrDNJjuWz/eJ5hUIIe3ga5ScfzO4Jr
|
||||
jTWS4kh5lpttCPFX8ouLkMgLUxijQpxFbHoF1trXJndFvavStT0yuC0y5TXzb3wJbbiF/MXZWyjV
|
||||
/4U+oQLodO77MhaD01kk2y5bZ62YuQ3MPL0fQGypon12GPHeNNcEcYWRZlFv+JkWAduWlnuefj1D
|
||||
dVWV8dQQmSZGZNiGTsIJxkY9+4B+t/OhosGDc6jEmEZcKNVi9fnl0+awkzK6scNNmupZ8NwJl8ZR
|
||||
mJSsfaBcH4paYV1x31y4uTELv+OuDWAJ3D0RoCR8H0djTBxRhsF2/JpSJasxVmSbzWHPSeM3f1aO
|
||||
ChZGwbD6J2SpzsrdogUP/9z6o8YuVnJkOxoBYuXhT1pEYTd93/hE++j3MpOqey/xw8UDbYmq5oJf
|
||||
uKaYLOMphqDm5hUCZmxQp8gTzDleZGjxYS2fOS4qFUJlvyVwsSoJMXU+6YfA6tgEQ4Dbh6zp6r78
|
||||
MjEqfWn4lL16xW2Zzr6e8xWwUrM7T3Gp4WTA7/xOeA==
|
||||
104
live-build/ubuntu/ubuntu-classic-amd64.model
Normal file
104
live-build/ubuntu/ubuntu-classic-amd64.model
Normal file
@ -0,0 +1,104 @@
|
||||
type: model
|
||||
authority-id: canonical
|
||||
series: 16
|
||||
brand-id: canonical
|
||||
model: ubuntu-classic-2604-amd64
|
||||
architecture: amd64
|
||||
base: core24
|
||||
classic: true
|
||||
distribution: ubuntu
|
||||
grade: signed
|
||||
snaps:
|
||||
-
|
||||
default-channel: classic-26.04/stable
|
||||
id: UqFziVZDHLSyO3TqSWgNBoAdHbLI4dAH
|
||||
name: pc
|
||||
type: gadget
|
||||
-
|
||||
components:
|
||||
nvidia-580-uda-ko:
|
||||
presence: optional
|
||||
nvidia-580-uda-user:
|
||||
presence: optional
|
||||
default-channel: 26.04/stable
|
||||
id: pYVQrBcKmBa0mZ4CCN7ExT6jH8rY1hza
|
||||
name: pc-kernel
|
||||
type: kernel
|
||||
-
|
||||
default-channel: latest/stable
|
||||
id: amcUKQILKXHHTlmSa7NMdnXSx02dNeeT
|
||||
name: core22
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/stable
|
||||
id: dwTAh7MZZ01zyriOZErqd1JynQLiOGvM
|
||||
name: core24
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/stable
|
||||
id: PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4
|
||||
name: snapd
|
||||
type: snapd
|
||||
-
|
||||
default-channel: latest/stable
|
||||
id: EISPgh06mRh1vordZY9OZ34QHdd7OrdR
|
||||
name: bare
|
||||
type: base
|
||||
-
|
||||
default-channel: latest/stable/ubuntu-26.04
|
||||
id: HyhSEBPv3vHsW6uOHkQR384NgI7S6zpj
|
||||
name: mesa-2404
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/stable/ubuntu-26.04
|
||||
id: EI0D1KHjP8XiwMZKqSjuh6W8zvcowUVP
|
||||
name: firmware-updater
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/stable/ubuntu-26.04
|
||||
id: FppXWunWzuRT2NUT9CwoBPNJNZBYOCk0
|
||||
name: desktop-security-center
|
||||
type: app
|
||||
-
|
||||
default-channel: 1/stable/ubuntu-26.04
|
||||
id: aoc5lfC8aUd2VL8VpvynUJJhGXp5K6Dj
|
||||
name: prompting-client
|
||||
type: app
|
||||
-
|
||||
default-channel: 2/stable/ubuntu-26.04
|
||||
id: gjf3IPXoRiipCu9K0kVu52f0H56fIksg
|
||||
name: snap-store
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/stable/ubuntu-26.04
|
||||
id: jZLfBRzf1cYlYysIjD2bwSzNtngY0qit
|
||||
name: gtk-common-themes
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/stable/ubuntu-26.04
|
||||
id: 3wdHCAVyZEmYsCMFDE9qt92UV8rC8Wdk
|
||||
name: firefox
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/stable/ubuntu-26.04
|
||||
id: ew7OxpbRTxfK7ImpIygRR85lkxvU7Pzt
|
||||
name: gnome-46-2404
|
||||
type: app
|
||||
-
|
||||
default-channel: latest/stable/ubuntu-26.04
|
||||
id: IrwRHakqtzhFRHJOOPxKVPU0Kk7Erhcu
|
||||
name: snapd-desktop-integration
|
||||
type: app
|
||||
timestamp: 2025-12-09T12:00:00.0Z
|
||||
sign-key-sha3-384: 9tydnLa6MTJ-jaQTFUXEwHl1yRx7ZS4K5cyFDhYDcPzhS7uyEkDxdUjg9g08BtNn
|
||||
|
||||
AcLBXAQAAQoABgUCaYzP9QAKCRDgT5vottzAEus2D/4jJVutpoPmDrLjNQLn2KNf/f1L2zU8ESSe
|
||||
VpFjy+9Ff7AxXckALM4eEy/J5mc+UNhHQ/7Thp4XYy2NiH14n9Lv5kVqZCz8udiEfcfLy5gGveio
|
||||
oXyGX7J5x9sq3YXV1IHS84aqJS0si80TTLCRQXUN8oUZIVRkgFOGIVVneQkn1ppNs87kNgvBT1ow
|
||||
nwr9fVvZnt5bTprCxs4R5cEUlWTJMN4l96Eh530Q+wqCjFxbTs6FADUYielsFnBDl/Q1M0fozg4F
|
||||
Ct4gBbvFGWZhp8LXiCbJvTd3PAAV1HYAgtKDKZT0NQp8qaU5DpgTDiUzIjaAJP7feSU5AYDLuVSH
|
||||
V3zD8sosg1nmPvVtuSi2q5Z+/zd6gmG+vLn5d16whNqELDnX0O9Hxarc/3DD3ANZrrbXlq/PEJNB
|
||||
Lor5osHLN4utW7CUC5MIEQ5/Z/6cSuav6rQ+bBiAOzQSHRCbhfyCGSMMINX2CE3ePw3moi9gwXeh
|
||||
vKw1iItEOxywEKbeBNEvddnGsvmzoqf9Jg53/X0yrQQVZTHYFsQlTRk9ggajdZnPjJMTqlAqjXnP
|
||||
QCsgnprvln0akW4IfEzc+IgoF5eiShJd4IidkBbbdNXRRYlHfmOG7ZvR9upJwe1M73Zfu1nQFEvT
|
||||
fly59e2Vw8O50ljOVW3jT5fW36z8h1+ttxkKwVsQJg==
|
||||
@ -7,12 +7,10 @@
|
||||
|
||||
set -e
|
||||
|
||||
. config/common
|
||||
|
||||
chroot_directory=$1
|
||||
|
||||
auto_packages=$(${LIVECD_ROOTFS_ROOT}/auto-markable-pkgs $chroot_directory)
|
||||
auto_packages=$(/usr/share/livecd-rootfs/auto-markable-pkgs $chroot_directory)
|
||||
if [ -n "$auto_packages" ]; then
|
||||
chroot $chroot_directory apt-mark auto $auto_packages
|
||||
fi
|
||||
[ -z "$(${LIVECD_ROOTFS_ROOT}/auto-markable-pkgs $chroot_directory 2> /dev/null)" ]
|
||||
[ -z "$(/usr/share/livecd-rootfs/auto-markable-pkgs $chroot_directory 2> /dev/null)" ]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user