mirror of
https://git.launchpad.net/livecd-rootfs
synced 2026-03-18 13:37:42 +00:00
Merge branch 'better-local-experience' into ubuntu/master
This commit is contained in:
commit
5e4e502c76
12
debian/changelog
vendored
12
debian/changelog
vendored
@ -1,8 +1,16 @@
|
||||
livecd-rootfs (26.04.24) resolute; urgency=medium
|
||||
livecd-rootfs (26.04.24) UNRELEASED; urgency=medium
|
||||
|
||||
[ Allen Abraham ]
|
||||
* Added a hook to produce a working minimal Ubuntu image using imagecraft
|
||||
|
||||
-- Allen Abraham <allen.abraham@canonical.com> Tue, 03 Mar 2026 10:54:22 -0500
|
||||
[ 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, 23 Feb 2026 15:02:42 +1300
|
||||
|
||||
livecd-rootfs (26.04.23) resolute; urgency=medium
|
||||
|
||||
|
||||
1
debian/livecd-rootfs.links
vendored
Normal file
1
debian/livecd-rootfs.links
vendored
Normal file
@ -0,0 +1 @@
|
||||
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
|
||||
|
||||
/usr/share/livecd-rootfs/minimize-manual chroot
|
||||
${LIVECD_ROOTFS_ROOT}/minimize-manual chroot
|
||||
|
||||
clean_debian_chroot
|
||||
fi
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#!/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|\
|
||||
@ -47,12 +49,12 @@ if [ -z "$MIRROR" ]; then
|
||||
fi
|
||||
|
||||
mkdir -p 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/
|
||||
cp -af ${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/
|
||||
|
||||
mkdir -p config/package-lists
|
||||
|
||||
@ -390,7 +392,7 @@ if [ -z "${IMAGEFORMAT:-}" ]; then
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
ubuntu-server:live|ubuntu-mini-iso:|ubuntu-core-installer:*)
|
||||
ubuntu-server:live|ubuntu-mini-iso:|ubuntu-test-iso:|ubuntu-core-installer:*)
|
||||
IMAGEFORMAT=plain
|
||||
;;
|
||||
esac
|
||||
@ -426,7 +428,7 @@ case $IMAGEFORMAT in
|
||||
ubuntu-server:live|ubuntu-core-installer:*)
|
||||
touch config/universe-enabled
|
||||
;;
|
||||
ubuntu-mini-iso:)
|
||||
ubuntu-mini-iso:|ubuntu-test-iso:)
|
||||
fs=none
|
||||
;;
|
||||
*)
|
||||
@ -636,7 +638,7 @@ case $PROJECT in
|
||||
esac
|
||||
|
||||
case $PROJECT in
|
||||
ubuntu-mini-iso)
|
||||
ubuntu-mini-iso|ubuntu-test-iso)
|
||||
COMPONENTS='main'
|
||||
;;
|
||||
edubuntu|ubuntu-budgie|ubuntucinnamon|ubuntukylin)
|
||||
@ -653,15 +655,24 @@ case $SUBPROJECT in
|
||||
;;
|
||||
esac
|
||||
|
||||
if ! [ -e config/germinate-output/structure ]; then
|
||||
echo "Running germinate..."
|
||||
if [ -n "$COMPONENTS" ]; then
|
||||
GERMINATE_ARG="-c $(echo $COMPONENTS | sed -e's/ \+/,/g')"
|
||||
fi
|
||||
(cd config/germinate-output && germinate --no-rdepends --no-installer \
|
||||
-S $SEEDMIRROR -m $MIRROR -d $SUITE,$SUITE-updates \
|
||||
-s $FLAVOUR.$SUITE $GERMINATE_ARG -a ${ARCH_VARIANT:-$ARCH})
|
||||
fi
|
||||
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
|
||||
GERMINATE_ARG="-c $(echo $COMPONENTS | sed -e's/ \+/,/g')"
|
||||
fi
|
||||
(cd config/germinate-output && germinate --no-rdepends --no-installer \
|
||||
-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.
|
||||
#
|
||||
@ -674,6 +685,9 @@ 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() {
|
||||
@ -804,7 +818,7 @@ do_layered_desktop_image() {
|
||||
DEFAULT_KERNEL="linux-$KERNEL_FLAVOURS"
|
||||
|
||||
if [ "$LOCALE_SUPPORT" != none ]; then
|
||||
/usr/share/livecd-rootfs/checkout-translations-branch \
|
||||
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
|
||||
https://git.launchpad.net/subiquity po \
|
||||
config/catalog-translations
|
||||
fi
|
||||
@ -1124,7 +1138,7 @@ case $PROJECT in
|
||||
NO_SQUASHFS_PASSES=ubuntu-server-minimal.ubuntu-server.installer.$flavor.netboot
|
||||
|
||||
DEFAULT_KERNEL="$kernel_metapkg"
|
||||
/usr/share/livecd-rootfs/checkout-translations-branch \
|
||||
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
|
||||
https://git.launchpad.net/subiquity po config/catalog-translations
|
||||
;;
|
||||
*)
|
||||
@ -1142,7 +1156,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 /usr/share/livecd-rootfs/live-build/${PROJECT}/ubuntu-core-desktop-24-amd64.model-assertion config/
|
||||
cp ${LIVECD_ROOTFS_ROOT}/live-build/${PROJECT}/ubuntu-core-desktop-24-amd64.model-assertion config/
|
||||
fi
|
||||
OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal"
|
||||
PASSES_TO_LAYERS=true
|
||||
@ -1156,7 +1170,7 @@ case $PROJECT in
|
||||
USE_BRIDGE_KERNEL=false
|
||||
DEFAULT_KERNEL="snap:pc-kernel"
|
||||
|
||||
/usr/share/livecd-rootfs/checkout-translations-branch \
|
||||
${LIVECD_ROOTFS_ROOT}/checkout-translations-branch \
|
||||
https://git.launchpad.net/subiquity po config/catalog-translations
|
||||
;;
|
||||
|
||||
@ -1179,6 +1193,22 @@ 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"
|
||||
;;
|
||||
@ -1278,7 +1308,7 @@ case $SUBPROJECT in
|
||||
# and a variety of things fail without it.
|
||||
add_package install tzdata
|
||||
|
||||
cp -af /usr/share/livecd-rootfs/live-build/make-lxd-metadata.py config/make-lxd-metadata
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/make-lxd-metadata.py config/make-lxd-metadata
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -1403,11 +1433,13 @@ 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
|
||||
@ -1443,7 +1475,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-cpc|ubuntu-core|ubuntu-base|ubuntu-oci|ubuntu-wsl|ubuntu-mini-iso|ubuntu-test-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
|
||||
;;
|
||||
@ -1531,11 +1563,11 @@ fi
|
||||
|
||||
case $PROJECT:${SUBPROJECT:-} in
|
||||
ubuntu-cpc:*|ubuntu-server:live|ubuntu:desktop-preinstalled| \
|
||||
ubuntu-wsl:*|ubuntu-mini-iso:*|ubuntu:|ubuntu:dangerous|ubuntu-oem:*| \
|
||||
ubuntu-wsl:*|ubuntu-mini-iso:*|ubuntu-test-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 /usr/share/livecd-rootfs/live-build/${PROJECT}/*; do
|
||||
for entry in ${LIVECD_ROOTFS_ROOT}/live-build/${PROJECT}/*; do
|
||||
case $entry in
|
||||
*hooks*)
|
||||
# But hooks are shared across the projects with symlinks
|
||||
@ -1570,11 +1602,11 @@ esac
|
||||
case $PROJECT in
|
||||
ubuntu-oem|ubuntustudio|edubuntu|ubuntu-budgie|ubuntucinnamon| \
|
||||
xubuntu|ubuntukylin|ubuntu-mate|lubuntu)
|
||||
cp -af /usr/share/livecd-rootfs/live-build/ubuntu/includes.chroot \
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/ubuntu/includes.chroot \
|
||||
config/includes.chroot
|
||||
|
||||
LIVE_LAYER=${LIVE_PREFIX}live
|
||||
cp -af /usr/share/livecd-rootfs/live-build/ubuntu/includes.chroot.minimal.standard.live \
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/ubuntu/includes.chroot.minimal.standard.live \
|
||||
config/includes.chroot.$LIVE_LAYER
|
||||
|
||||
if [ $PROJECT != ubuntu-oem ]; then
|
||||
@ -1590,7 +1622,7 @@ esac
|
||||
|
||||
case $SUBPROJECT in
|
||||
buildd)
|
||||
cp -af /usr/share/livecd-rootfs/live-build/buildd/* config/
|
||||
cp -af ${LIVECD_ROOTFS_ROOT}/live-build/buildd/* config/
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -1614,7 +1646,7 @@ if [ "$EXTRA_PPAS" ]; then
|
||||
extra_ppa=${extra_ppa%:*}
|
||||
;;
|
||||
esac
|
||||
extra_ppa_fingerprint="$(/usr/share/livecd-rootfs/get-ppa-fingerprint "$extra_ppa")"
|
||||
extra_ppa_fingerprint="$(${LIVECD_ROOTFS_ROOT}/get-ppa-fingerprint "$extra_ppa")"
|
||||
|
||||
cat >> config/archives/extra-ppas.list.chroot <<EOF
|
||||
deb https://ppa.launchpadcontent.net/$extra_ppa/ubuntu @DISTRIBUTION@ main
|
||||
@ -1704,8 +1736,19 @@ fi
|
||||
|
||||
if [ "${MAKE_ISO}" = "yes" ]; then
|
||||
# XXX should pass --build-type here.
|
||||
/usr/share/livecd-rootfs/live-build/gen-iso-ids \
|
||||
${LIVECD_ROOTFS_ROOT}/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
|
||||
|
||||
218
live-build/build-livefs
Executable file
218
live-build/build-livefs
Executable file
@ -0,0 +1,218 @@
|
||||
#!/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()
|
||||
150
live-build/build-livefs-lxd
Executable file
150
live-build/build-livefs-lxd
Executable file
@ -0,0 +1,150 @@
|
||||
#!/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()
|
||||
@ -188,8 +188,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 /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"
|
||||
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"
|
||||
# cgroup2 mount for LP: 1944004
|
||||
mount -t cgroup2 none "$mountpoint/sys/fs/cgroup"
|
||||
mount -t tmpfs none "$mountpoint/tmp"
|
||||
@ -408,7 +408,7 @@ create_squashfs() {
|
||||
squashfs_file="$2"
|
||||
config_dir="$PWD/config"
|
||||
(cd $rootfs_dir &&
|
||||
mksquashfs . $squashfs_file -no-progress -xattrs -comp xz \
|
||||
mksquashfs . $squashfs_file -no-progress -xattrs -comp "${SQUASHFS_COMP:-xz}" \
|
||||
-ef "$config_dir/squashfs-exclude-files")
|
||||
|
||||
}
|
||||
@ -860,7 +860,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 /usr/share/livecd-rootfs/live-build/apparmor/${kern_major_min} ]; then
|
||||
if [ -d ${LIVECD_ROOTFS_ROOT}/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 +868,7 @@ snap_validate_seed() {
|
||||
|
||||
# Bind kernel apparmor directory to feature directory for snap preseeding
|
||||
umount "${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/"
|
||||
mount --bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/${kern_major_min} "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -894,7 +894,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 /usr/share/livecd-rootfs/live-build/apparmor/generic "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
mount -o bind ${LIVECD_ROOTFS_ROOT}/live-build/apparmor/generic "${CHROOT_ROOT}/sys/kernel/security/apparmor/features/"
|
||||
fi
|
||||
|
||||
}
|
||||
@ -1254,7 +1254,7 @@ setup_cidata() {
|
||||
local mountpoint=$(mktemp -d)
|
||||
mkfs.vfat -F 32 -n CIDATA ${cidata_dev}
|
||||
mount ${cidata_dev} ${mountpoint}
|
||||
cp /usr/share/livecd-rootfs/live-build/cidata/* ${mountpoint}
|
||||
cp ${LIVECD_ROOTFS_ROOT}/live-build/cidata/* ${mountpoint}
|
||||
cat >>${mountpoint}/meta-data.sample <<END
|
||||
#instance-id: iid-$(openssl rand -hex 8)
|
||||
|
||||
@ -1454,5 +1454,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=/usr/share/livecd-rootfs/live-build/ /usr/share/livecd-rootfs/live-build/isobuild --workdir config/iso-dir "$@"
|
||||
PYTHONPATH=${LIVECD_ROOTFS_ROOT}/live-build/ ${LIVECD_ROOTFS_ROOT}/live-build/isobuild --workdir config/iso-dir "$@"
|
||||
}
|
||||
|
||||
@ -42,6 +42,7 @@ 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",
|
||||
|
||||
@ -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
|
||||
/usr/share/livecd-rootfs/sync-mtime chroot "$overlay_dir"
|
||||
${LIVECD_ROOTFS_ROOT}/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
|
||||
/usr/share/livecd-rootfs/update-source-catalog source $usc_opts
|
||||
${LIVECD_ROOTFS_ROOT}/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"
|
||||
/usr/share/livecd-rootfs/update-source-catalog merge \
|
||||
${LIVECD_ROOTFS_ROOT}/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
|
||||
/usr/share/livecd-rootfs/minimize-manual chroot
|
||||
${LIVECD_ROOTFS_ROOT}/minimize-manual chroot
|
||||
clean_debian_chroot
|
||||
|
||||
Chroot chroot "dpkg-query -W" > chroot.packages.${pass}
|
||||
|
||||
@ -11,6 +11,7 @@ case ${PASS:-} in
|
||||
esac
|
||||
|
||||
. config/binary
|
||||
. config/common
|
||||
. config/functions
|
||||
|
||||
case ${SUBPROJECT} in
|
||||
@ -56,4 +57,4 @@ PROJECT_FULL=$PROJECT${SUBARCH:+-$SUBARCH}
|
||||
usc_opts="--output livecd.${PROJECT_FULL}.install-sources.yaml \
|
||||
--template config/edge.catalog-in.yaml \
|
||||
--size 0"
|
||||
/usr/share/livecd-rootfs/update-source-catalog source $usc_opts
|
||||
${LIVECD_ROOTFS_ROOT}/update-source-catalog source $usc_opts
|
||||
|
||||
8
live-build/ubuntu-test-iso/hooks/01-test-iso.chroot_early
Executable file
8
live-build/ubuntu-test-iso/hooks/01-test-iso.chroot_early
Executable file
@ -0,0 +1,8 @@
|
||||
#!/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
|
||||
15
live-build/ubuntu-test-iso/hooks/02-test-iso-kernel.binary
Executable file
15
live-build/ubuntu-test-iso/hooks/02-test-iso-kernel.binary
Executable file
@ -0,0 +1,15 @@
|
||||
#!/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"
|
||||
@ -7,10 +7,12 @@
|
||||
|
||||
set -e
|
||||
|
||||
. config/common
|
||||
|
||||
chroot_directory=$1
|
||||
|
||||
auto_packages=$(/usr/share/livecd-rootfs/auto-markable-pkgs $chroot_directory)
|
||||
auto_packages=$(${LIVECD_ROOTFS_ROOT}/auto-markable-pkgs $chroot_directory)
|
||||
if [ -n "$auto_packages" ]; then
|
||||
chroot $chroot_directory apt-mark auto $auto_packages
|
||||
fi
|
||||
[ -z "$(/usr/share/livecd-rootfs/auto-markable-pkgs $chroot_directory 2> /dev/null)" ]
|
||||
[ -z "$(${LIVECD_ROOTFS_ROOT}/auto-markable-pkgs $chroot_directory 2> /dev/null)" ]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user