#! /bin/sh set -e if [ -e config/germinate-output ]; then mv -T config/germinate-output germ-tmp rm -rf config mkdir config mv -T germ-tmp config/germinate-output else rm -rf config fi echo "Building on $(hostname --fqdn)" SEEDMIRROR=https://ubuntu-archive-team.ubuntu.com/seeds/ if [ -z "$MIRROR" ]; then case $(hostname --fqdn) in *.ubuntu.com|*.buildd|*.ppa|*.scalingstack) MIRROR=http://ftpmaster.internal/ubuntu/ SEEDMIRROR=http://archive-team.internal/seeds/ ;; *) case $ARCH in i386|amd64) MIRROR=http://archive.ubuntu.com/ubuntu/ ;; *) MIRROR=http://ports.ubuntu.com/ubuntu-ports/ ;; esac ;; esac 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/expand-task config/expand-task cp -af /usr/share/livecd-rootfs/live-build/squashfs-exclude-files config/ mkdir -p config/package-lists . config/functions OPTS= COMPONENTS= BINARY_REMOVE_LINUX=: BINARY_IMAGES=none MEMTEST=none SOURCE='--source false' BOOTLOADER=none BOOTAPPEND_LIVE= LIVE_TASK= PREINSTALLED=false PREINSTALL_POOL= PREINSTALL_POOL_SEEDS= PREFIX="livecd.$PROJECT${SUBARCH:+-$SUBARCH}" CHROOT_HOOKS= BINARY_HOOKS= APT_OPTIONS=" --yes -oDebug::pkgDepCache::AutoInstall=yes " PASSES_TO_LAYERS=false _PASSES_TO_LAYERS= # Stores the initial value of PASSES_TO_LAYERS PASSES= _check_immutable_passes_to_layers () { # Check that PASSES_TO_LAYERS didn't change ie we didn't switch from layer # to non-layer image format and vice versa. if [ -z "$_PASSES_TO_LAYERS" ]; then _PASSES_TO_LAYERS=$PASSES_TO_LAYERS fi if [ "$_PASSES_TO_LAYERS" != "$PASSES_TO_LAYERS" ]; then echo "ERROR: PASSES_TO_LAYERS has changed from $_PASSES_TO_LAYERS to $PASSES_TO_LAYERS between 2 API calls. Please set it first." exit 1 fi } _check_layers_only_API () { # Check if a function is designed only for layered mode # $1 name of the function if [ "$PASSES_TO_LAYERS" != "true" ]; then echo "$1 should only be used in layered mode, with PASSES_TO_LAYERS set to true" exit 1 fi } _register_pass () { # In layer mode, record a pass into the list of passes # $1 Name of the pass [ "$PASSES_TO_LAYERS" != "true" ] && return PASSES="$PASSES $1" } add_pass () { local pass="$1" _check_immutable_passes_to_layers _register_pass "$pass" } add_task () { local pass="$1" shift local file pkg_file snap_file task _check_immutable_passes_to_layers _register_pass "$pass" if [ ! -e config/germinate-output/structure ]; then echo "add_task too soon" >&2 exit 1 fi pkg_file="config/package-lists/livecd-rootfs.list.chroot_$pass" if [ $PASSES_TO_LAYERS = "true" ]; then snap_file="config/package-lists/livecd-rootfs.snaplist.chroot_$pass.full" else snap_file="config/seeded-snaps" fi for task; do ./config/expand-task config/germinate-output $FLAVOUR $task packages >> "$pkg_file" ./config/expand-task config/germinate-output $FLAVOUR $task snaps >> "$snap_file" done for file in $pkg_file $snap_file; do if [ -s $file ]; then sort -u -o $file $file else rm -f $file fi done } add_package () { # Adds a pass named pass_name composed of packages to install # $1 pass # $@ list of packages local pass="$1" shift local pkg _check_immutable_passes_to_layers _register_pass "$pass" for pkg; do echo "$pkg" >> "config/package-lists/livecd-rootfs.list.chroot_$pass" done } remove_package () { # Adds a pass named pass_name composed of packages to remove # $1 pass # $@ list of packages local pass="$1" shift local pkg _check_immutable_passes_to_layers _check_layers_only_API "remove_package" _register_pass "$pass" for pkg; do echo "$pkg" >> "config/package-lists/livecd-rootfs.removal-list.chroot_$pass" done } add_snap () { # Adds a pass named pass_name composed of snaps to install # $1 pass # $@ list of snaps local pass="$1" shift local pkg _check_immutable_passes_to_layers _register_pass "$pass" local channel="" if [ -n "$CHANNEL" ] ; then channel="=$CHANNEL" fi for pkg; do echo "$pkg$channel" >> "config/package-lists/livecd-rootfs.snaplist.chroot_$pass.full" done } get_seeded_languages () { # We assume any seed name of the form ${no_lang_seed}-${foo} where # ${foo} is only two or three characters long is a default language # seed. langs='' for no_lang_seed in "$@"; do seed_regex="${no_lang_seed}"'-[^-.]{2,3}$' for seed in $(ls config/germinate-output | grep -E "${seed_regex}"); do lang=$(echo "${seed}" | grep -oE '[^-.]{2,3}$') langs="$langs $lang" done done echo $langs | tr ' ' '\n' | sort -u | tr '\n' ' ' } derive_language_layers () { # create special layers for each default language # # $1 base pass # $2 base seed (without any languages) # $3 default language seed # $4 space separated list of default languages # e.g.: # derive_language_layers minimal desktop-minimal desktop-minimal-default-languages # derive_language_layers minimal.standard desktop desktop-default-languages # # The way this works is perhaps a little counterintuitive. # # The first goal here is that the installed system should contain # language support for the language the user selected. One way to do # this using layers would be to have a layer that contained no # language support and a derived layer for each (default) language. So # something like: # # filesystem.squashfs (contains no language support) # filesystem.en.squashfs (contains English language support) # filesystem.fr.squashfs (contains French language support) # ... # # Then if the user selects French as their language, we just copy # filesystem.fr.squashfs to the target system. # # But we want the live session to support these languages too and # simply adding all the language support to the live layer would mean # we'd have the each language's support files on the ISO twice (once # in filesystem.$LANG.squashfs and once in filesystem.live.squashfs). # # So what is done instead is that we add support for all the default # languages to the base layer and then create derived layers that # _remove_ support for all languages but the desired language and # because file removals are cheap to represent in overlays, this all # ends up taking way less space, and filesystem.live.squashfs gets # support for all languages from the base layer. We also create a # layer than has support for all languages removed, which can be used # for the base of an install for a non-default language. local pass base_pass=$1 no_lang_seed=$2 def_lang_seed=$3 langs=$4 _check_immutable_passes_to_layers _check_layers_only_API "derive_language_layers" for lang in $langs; do pass="${base_pass}.${lang}" _register_pass ${pass} # Remove packages from the default language seed that are not # in the language specific seed from the language specific layer. # I find this expression helps a little to make this make sense: # ((base) + (en fr de)) - ( (en fr de) - (fr)) == (base + fr) # `layer will all langs' `def_lang_seed' `lang' `what we want to install' subtract_package_lists ${def_lang_seed} ${no_lang_seed}-${lang} >> config/package-lists/livecd-rootfs.removal-list.chroot_$pass done no_lang_pass=$base_pass.no-languages _register_pass ${no_lang_pass} # Remove all packages from the default language seed that are not in # the no_lang_seed from the no-languages layer. subtract_package_lists ${def_lang_seed} ${no_lang_seed} >> config/package-lists/livecd-rootfs.removal-list.chroot_${no_lang_pass} } add_chroot_hook () { CHROOT_HOOKS="${CHROOT_HOOKS:+$CHROOT_HOOKS }$1" } add_binary_hook () { BINARY_HOOKS="${BINARY_HOOKS:+$BINARY_HOOKS }$1" } _sanitize_passes () { # Returns an uniquely ordered list of passes and ensure dependency tree is coherent # $1 list of passes local passes="$1" [ -z "$passes" ] && return passes=$(echo $passes | tr ' ' '\n' | sort -u) for pass in $passes; do parent=$(get_parent_pass $pass) # if root pass, no parent to find [ -z "$parent" ] && continue if [ $(echo "$passes"|grep -cE "^$parent\$") -ne 1 ]; then echo "ERROR: '$parent' is required by '$pass' but is missing. Registered passes are:\n$passes" >&2 exit 1 fi done # return the list of passes echo $passes } _get_live_passes () { # Returns a list of all passes that ends with .live for automated live passes detection # $1 list of passes local passes="$1" local livepasses="" [ -z "$passes" ] && return for pass in $passes; do if echo $pass | grep -Eq '\.live$'; then livepasses="$pass $livepasses" fi done echo $livepasses } if [ -z "${IMAGEFORMAT:-}" ]; then case $PROJECT:${SUBPROJECT:-} in ubuntu-cpc:*|ubuntu:desktop-preinstalled|ubuntu-wsl:*) case $ARCH+${SUBARCH:-} in *+raspi) # All raspi images use ubuntu-image. IMAGEFORMAT=ubuntu-image ;; arm64+tegra|arm64+tegra-igx) # Pre-installed Tegra images use # ubuntu-image IMAGEFORMAT=ubuntu-image ;; *) IMAGEFORMAT=ext4 ;; esac ;; ubuntu-server:live|ubuntu-mini-iso:) IMAGEFORMAT=plain ;; esac fi # Configure preinstalled ubuntu-cpc images with included password # one also must request disk1-img-xz image format if [ "$IMAGEFORMAT" = "ext4" ] && [ "$PROJECT" = "ubuntu-cpc" ]; then case $ARCH:$SUBARCH in armhf:raspi2 | \ riscv64:icicle | \ riscv64:nezha | \ riscv64:licheerv | \ riscv64:unmatched | \ riscv64:visionfive | \ riscv64:visionfive2 | \ *:generic) IMAGE_HAS_HARDCODED_PASSWORD=1 if [ -z "${IMAGE_TARGETS:-}" ]; then export IMAGE_TARGETS="disk-image-non-cloud" fi ;; esac fi skip_lb_stage() { STAGE="$1" mkdir -p .build touch ".build/$STAGE" } case $IMAGEFORMAT in ext2|ext3|ext4) OPTS="${OPTS:+$OPTS }--initramfs none --chroot-filesystem $IMAGEFORMAT" PREINSTALLED=true ;; plain) case $PROJECT:${SUBPROJECT:-} in ubuntu-server:live) touch config/universe-enabled ;; ubuntu-mini-iso:) ;; *) PREINSTALLED=true ;; esac OPTS="${OPTS:+$OPTS }--initramfs none --chroot-filesystem $IMAGEFORMAT" ;; ubuntu-image) UBUNTU_IMAGE_ARGS="" case "$ARCH+${SUBARCH:-}" in amd64+intel-iot) MODEL=intel-iot ;; amd64+*) MODEL=pc-amd64 ;; arm64+snapdragon) MODEL=dragonboard ;; armhf+raspi) MODEL=pi ;; armhf+raspi2) MODEL=pi2 ;; armhf+raspi3) MODEL=pi3 ;; arm64+raspi) MODEL=pi-arm64 ;; arm64+raspi3) MODEL=pi3-arm64 ;; armhf+cm3) MODEL=cm3 ;; arm64+tegra) MODEL=tegra ;; arm64+tegra-igx) MODEL=tegra-igx ;; arm64+*) MODEL=pc-arm64 ;; *) echo "Model $ARCH+${SUBARCH:-} unknown to livecd-rootfs" >&2 exit 1 ;; esac # If we have a datestamp coming from cdimage, use that to populate # .disk/info on the target image if [ -n "$NOW" ]; then echo "$NOW" > config/disk-info UBUNTU_IMAGE_ARGS="$UBUNTU_IMAGE_ARGS --disk-info config/disk-info" fi if [ $PROJECT = "ubuntu-core" ]; then # snap-based core images CHANNEL="${CHANNEL:-edge}" case $MODEL in pc-amd64|pc-arm64) if [ -z "${SUBARCH:-}" ]; then # This is to make sure there's enough writable space UBUNTU_IMAGE_ARGS="$UBUNTU_IMAGE_ARGS --image-size 3700M" fi ;; *) ;; esac case $SUITE in xenial) # Ubuntu Core 16 UBUNTU_IMAGE_ARGS="$UBUNTU_IMAGE_ARGS -c $CHANNEL" ;; bionic) # Ubuntu Core 18 MODEL="ubuntu-core-18-${MODEL#pc-}" UBUNTU_IMAGE_ARGS="$UBUNTU_IMAGE_ARGS -c $CHANNEL" ;; *) if [ "$SUITE" = "focal" ]; then CORE_MAJOR=20 else CORE_MAJOR=22 fi if [ "${MODEL}" = "pi" ]; then MODEL=pi-armhf fi # Ubuntu Core 2x # Currently uc2x assertions do not support global # channel overrides, instead we have per-channel models case $CHANNEL in stable) MODEL="ubuntu-core-${CORE_MAJOR}-${MODEL#pc-}" ;; candidate|beta|edge|dangerous) MODEL="ubuntu-core-${CORE_MAJOR}-${MODEL#pc-}-${CHANNEL}" ;; dangerous-*) # That being said, the dangerous grade *does* # support channel overrides, so we can use the # dangerous model assertion and override the channel # freely. MODEL="ubuntu-core-${CORE_MAJOR}-${MODEL#pc-}-dangerous" CHANNEL=${CHANNEL#dangerous-} UBUNTU_IMAGE_ARGS="$UBUNTU_IMAGE_ARGS -c $CHANNEL" ;; *) echo "Unknown CHANNEL ${CHANNEL} specification for ${SUITE}" exit 1 ;; esac ;; esac case "$ARCH+${SUBARCH:-}" in amd64+kassel) EXTRA_SNAPS="$EXTRA_SNAPS core bluez alsa-utils" ;; *) ;; esac for snap in $EXTRA_SNAPS; do UBUNTU_IMAGE_ARGS="$UBUNTU_IMAGE_ARGS --extra-snaps $snap" done echo "IMAGEFORMAT=$IMAGEFORMAT" >> config/common echo "UBUNTU_IMAGE_ARGS=\"$UBUNTU_IMAGE_ARGS\"" >> config/common # Store model assertion in top dir to get it picked up later as a build artifact env SNAPPY_STORE_NO_CDN=1 snap known --remote model series=16 model="$MODEL" brand-id=canonical > "$PREFIX".model-assertion echo "Configured ubuntu-image for the following model assertion:" cat "$PREFIX".model-assertion echo "----------------------------------------------------------" else # classic images IMAGE_PROJECT=$PROJECT [ "$IMAGE_PROJECT" = "ubuntu-cpc" ] && IMAGE_PROJECT="ubuntu-server" LB_UBUNTU_IMAGES_REPO="${LB_UBUNTU_IMAGES_REPO:-git://git.launchpad.net/ubuntu-images}" LB_UBUNTU_IMAGES_BRANCH="${LB_UBUNTU_IMAGES_BRANCH:-$SUITE}" git clone "$LB_UBUNTU_IMAGES_REPO" -b "$LB_UBUNTU_IMAGES_BRANCH" image-definitions IMAGE_DEFINITION="image-definitions/$IMAGE_PROJECT-$MODEL.yaml" echo "IMAGE_DEFINITION=$IMAGE_DEFINITION" >> config/common echo "Configured ubuntu-image to use image definition file $IMAGE_DEFINITION which has the following contents:" cat "$IMAGE_DEFINITION" echo "----------------------------------------------------------" fi # Save the model name used for building, mostly for any model-specific hook execution echo "MODEL=$MODEL" >> config/common echo "IMAGEFORMAT=$IMAGEFORMAT" >> config/common # Fake finished configuration for lb build mkdir -p .build touch .build/config exit 0 ;; none) # Currently the IMAGEFORMAT none format is used only for ubuntu-image # targeted image builds which, currently, only target physical devices. OPTS="${OPTS:+$OPTS }--chroot-filesystem $IMAGEFORMAT" PREINSTALLED=true ;; *) case $PROJECT in ubuntu-server|ubuntu-wsl|ubuntu-oem) ;; ubuntu|ubuntu-budgie) if [ "$SUBPROJECT" = "legacy" ]; then add_package live casper fi ;; *) add_package live casper ;; esac ;; esac if [ "$PREINSTALLED" = "true" ]; then # Touch a random file that we can refer back to during build, # cause that's wildly hackish touch config/universe-enabled case $PROJECT in kubuntu*) add_package live oem-config-kde ubiquity-frontend-kde add_package live ubiquity-slideshow-kubuntu ;; lubuntu*) add_package live oem-config-gtk ubiquity-frontend-gtk add_package live ubiquity-slideshow-lubuntu ;; xubuntu*) add_package live oem-config-gtk ubiquity-frontend-gtk add_package live ubiquity-slideshow-xubuntu ;; ubuntu-mate) add_package live oem-config-gtk ubiquity-frontend-gtk add_package live ubiquity-slideshow-ubuntu-mate ;; ubuntu-unity) add_package live oem-config-gtk ubiquity-frontend-gtk add_package live ubiquity-slideshow-ubuntu ;; ubuntu-server) add_package live oem-config-debconf ubiquity-frontend-debconf ;; ubuntu-base|ubuntu-oci|ubuntu-cpc|ubuntu-wsl|ubuntu-mini-iso) ;; ubuntu) add_package live oem-config-gtk ubiquity-frontend-gtk add_package live ubiquity-slideshow-ubuntu if [ "$SUBPROJECT" = "desktop-preinstalled" ]; then add_package live language-pack-en-base oem-config-slideshow-ubuntu fi ;; *) add_package live oem-config-gtk ubiquity-frontend-gtk add_package live ubiquity-slideshow-ubuntu ;; esac fi case $BINARYFORMAT in iso*|usb*) BINARY_IMAGES="$BINARYFORMAT" MEMTEST=memtest86+ BOOTLOADER=syslinux OPTS="${OPTS:+$OPTS }--zsync=false" ;; esac if [ "${SUBPROJECT:-}" = minimized ]; then OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal --linux-packages=linux-image" fi mkdir -p config/germinate-output case $PROJECT in edubuntu*) FLAVOUR=edubuntu ;; kubuntu*) FLAVOUR=kubuntu ;; xubuntu*) FLAVOUR=xubuntu ;; ubuntu-mate*) FLAVOUR=ubuntu-mate ;; ubuntu-unity*) FLAVOUR=ubuntu-unity ;; lubuntu*) FLAVOUR=lubuntu ;; ubuntu-budgie*) FLAVOUR=ubuntu-budgie ;; ubuntukylin*) FLAVOUR=ubuntukylin ;; ubuntustudio*) FLAVOUR=ubuntustudio ;; ubuntucinnamon*) FLAVOUR=ubuntucinnamon ;; *) FLAVOUR=ubuntu ;; esac case $PROJECT in ubuntu-server|ubuntu-mini-iso) COMPONENTS='main' ;; edubuntu|kubuntu|ubuntu-budgie|ubuntu-gnome|ubuntucinnamon|ubuntukylin) COMPONENTS='main restricted universe' ;; lubuntu|ubuntu-mate|ubuntu-unity|ubuntustudio-dvd|xubuntu) COMPONENTS='main restricted universe multiverse' ;; esac case $SUBPROJECT in buildd) COMPONENTS='main restricted universe multiverse' ;; 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 -s $FLAVOUR.$SUITE \ $GERMINATE_ARG -a $ARCH) fi case $PROJECT in ubuntu) case ${SUBPROJECT:-} in legacy) LIVE_TASK='ubuntu-live' add_task install minimal standard ubuntu-desktop add_task live ubuntu-desktop-minimal-default-languages ubuntu-desktop-default-languages KERNEL_FLAVOURS='generic-hwe-22.04' if [ "$SUBARCH" = "intel-iot" ]; then KERNEL_FLAVOURS='intel-iotg' fi ;; desktop-preinstalled) add_task install minimal standard ubuntu-desktop case $SUBARCH in raspi) add_task install ubuntu-desktop-raspi # XXX: Are those actually needed? I see we use those for ubuntu-cpc, which is the project # for existing raspi preinstalled images # XXX: I would prefer to use --hdd-label=desktop-rootfs like 040-hyperv-desktop-images.binary OPTS="${OPTS:+$OPTS }--initramfs=none" OPTS="${OPTS:+$OPTS }--system=normal" OPTS="${OPTS:+$OPTS }--hdd-label=cloudimg-rootfs" OPTS="${OPTS:+$OPTS }--ext-resize-blocks=536870912 --ext-block-size=4096" OPTS="${OPTS:+$OPTS }--ext-fudge-factor=15" ;; intel-iot) KERNEL_FLAVOURS='intel-iotg' OPTS="${OPTS:+$OPTS }--initramfs=none" OPTS="${OPTS:+$OPTS }--system=normal" OPTS="${OPTS:+$OPTS }--hdd-label=cloudimg-rootfs" OPTS="${OPTS:+$OPTS }--ext-resize-blocks=536870912 --ext-block-size=4096" OPTS="${OPTS:+$OPTS }--ext-fudge-factor=15" ;; *) ## Otherwise HYPERV image options.... *crickets* see the hyperv hook ;; esac ;; *) touch config/universe-enabled KERNEL_FLAVOURS='generic-hwe-22.04' if [ "$SUBARCH" = "x13s" ]; then KERNEL_FLAVOURS='laptop-23.10' fi PASSES_TO_LAYERS="true" # the minimal layer, for minimal installs add_task minimal minimal standard ubuntu-desktop-minimal ubuntu-desktop-minimal-default-languages add_package minimal cloud-init # the standard layer, contains all base common packages for later layers add_task minimal.standard ubuntu-desktop ubuntu-desktop-default-languages # the live layer, contains all packages for the live session installer add_task minimal.standard.live ubuntu-live remove_package minimal.standard.live ubiquity-frontend-gtk add_snap minimal.standard.live ubuntu-desktop-installer/classic add_package minimal.standard.live linux-$KERNEL_FLAVOURS casper # language support seeded_langs="$(get_seeded_languages desktop)" echo "$seeded_langs" | tr ' ' ',' > config/seeded-languages derive_language_layers minimal desktop-minimal desktop-minimal-default-languages "$seeded_langs" derive_language_layers minimal.standard desktop desktop-default-languages "$seeded_langs" # Enchanced secureboot stuff case "$ARCH" in amd64) # the enhanced-secureboot layer, contains all packages for the enhanced secureboot install add_package minimal.enhanced-secureboot cryptsetup boot-managed-by-snapd add_package minimal.standard.enhanced-secureboot cryptsetup boot-managed-by-snapd derive_language_layers minimal.enhanced-secureboot desktop-minimal desktop-default-languages "$seeded_langs" derive_language_layers minimal.standard.enhanced-secureboot desktop desktop-default-languages "$seeded_langs" cat <<-EOF > config/minimal.enhanced-secureboot.catalog-in.yaml id: ubuntu-desktop-minimal variations: minimal-enhanced-secureboot: path: minimal.enhanced-secureboot.squashfs snapd_system_label: enhanced-secureboot-desktop EOF cat <<-EOF > config/minimal.standard.enhanced-secureboot.catalog-in.yaml id: ubuntu-desktop variations: enhanced-secureboot: path: minimal.standard.enhanced-secureboot.squashfs snapd_system_label: enhanced-secureboot-desktop EOF ;; esac # now let's create the neccessary catalog files cat <<-EOF > config/minimal.catalog-in.yaml name: "Ubuntu Desktop (minimized)" description: >- A minimal but usable Ubuntu Desktop. id: ubuntu-desktop-minimal type: fsimage-layered default: yes variant: desktop locale_support: langpack variations: minimal: path: minimal.squashfs EOF cat <<-EOF > config/minimal.standard.catalog-in.yaml name: "Ubuntu Desktop" description: >- A full featured Ubuntu Desktop. id: ubuntu-desktop type: fsimage-layered variant: desktop locale_support: langpack variations: standard: path: minimal.standard.squashfs EOF /usr/share/livecd-rootfs/checkout-translations-branch \ https://git.launchpad.net/subiquity po config/catalog-translations ;; esac ;; ubuntu-oem) touch config/universe-enabled PASSES_TO_LAYERS="true" #KERNEL_FLAVOURS='oem-22.04' KERNEL_FLAVOURS='generic-hwe-22.04' add_task minimal minimal standard ubuntu-desktop-minimal ubuntu-desktop-minimal-default-languages add_package minimal cloud-init add_task minimal.standard ubuntu-desktop ubuntu-desktop-default-languages add_task minimal.standard.live ubuntu-live remove_package minimal.standard.live ubiquity-frontend-gtk add_snap minimal.standard.live ubuntu-desktop-installer/classic add_package minimal.standard.live linux-$KERNEL_FLAVOURS casper cat <<-EOF > config/minimal.catalog-in.yaml name: "Ubuntu Desktop for OEM (minimal)" description: >- Ubuntu Desktop (minimal) for OEM preinstallation. id: ubuntu-desktop-oem-minimal type: fsimage-layered variant: desktop locale_support: none default: yes EOF cat <<-EOF > config/minimal.standard.catalog-in.yaml name: "Ubuntu Desktop for OEM" description: >- Ubuntu Desktop for OEM preinstallation. id: ubuntu-desktop-oem type: fsimage-layered variant: desktop locale_support: none EOF ;; kubuntu) add_task install minimal standard add_task install kubuntu-desktop LIVE_TASK='kubuntu-live' add_chroot_hook remove-gnome-icon-cache ;; edubuntu) add_task install minimal standard edubuntu-desktop-gnome LIVE_TASK='edubuntu-live' ;; lubuntu|ubuntu-gnome|ubuntu-unity|ubuntucinnamon|ubuntukylin) add_task install minimal standard ${PROJECT}-desktop LIVE_TASK=${PROJECT}-live ;; xubuntu) case ${SUBPROJECT:-} in minimal) add_task install minimal standard xubuntu-minimal ;; *) add_task install minimal standard xubuntu-desktop ;; esac LIVE_TASK='xubuntu-live' ;; ubuntu-budgie) case ${SUBPROJECT:-} in legacy) add_task install minimal standard ubuntu-budgie-desktop LIVE_TASK='ubuntu-budgie-live' ;; *) # By default Ubuntu Budgie now ships the new installer. touch config/universe-enabled PASSES_TO_LAYERS="true" KERNEL_FLAVOURS='generic-hwe-22.04' add_task minimal minimal standard ubuntu-budgie-desktop-minimal ubuntu-budgie-desktop-minimal-default-languages add_task minimal.standard ubuntu-budgie-desktop ubuntu-budgie-desktop-default-languages add_task minimal.standard.live ubuntu-budgie-live add_package minimal cloud-init remove_package minimal.standard.live ubiquity-frontend-gtk add_snap minimal.standard.live ubuntu-budgie-installer/classic add_package minimal.standard.live linux-$KERNEL_FLAVOURS casper seeded_langs="$(get_seeded_languages budgie-desktop-minimal budgie-desktop)" echo "$seeded_langs" | tr ' ' ',' > config/seeded-languages derive_language_layers minimal budgie-desktop-minimal budgie-desktop-minimal-default-languages "$seeded_langs" derive_language_layers minimal.standard budgie-desktop budgie-desktop-default-languages "$seeded_langs" cat <<-EOF > config/minimal.catalog-in.yaml name: "Ubuntu Budgie Desktop (minimized)" description: >- A minimal but usable Ubuntu Budgie Desktop. id: ubuntu-budgie-desktop-minimal type: fsimage-layered variant: desktop locale_support: langpack EOF cat <<-EOF > config/minimal.standard.catalog-in.yaml name: "Ubuntu Budgie Desktop" description: >- A full featured Ubuntu Budgie Desktop. id: ubuntu-budgie-desktop type: fsimage-layered variant: desktop locale_support: langpack default: yes EOF /usr/share/livecd-rootfs/checkout-translations-branch \ https://git.launchpad.net/subiquity po config/catalog-translations ;; esac ;; ubuntu-mate) add_task install minimal standard ubuntu-mate-core ubuntu-mate-desktop LIVE_TASK='ubuntu-mate-live' ;; ubuntustudio-dvd) add_task install minimal standard ubuntustudio-desktop ubuntustudio-audio ubuntustudio-graphics ubuntustudio-video ubuntustudio-photography KERNEL_FLAVOURS=lowlatency ;; ubuntu-server) case ${SUBPROJECT:-} in live) OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal" PASSES_TO_LAYERS=true add_task ubuntu-server-minimal server-minimal add_package ubuntu-server-minimal lxd-installer add_task ubuntu-server-minimal.ubuntu-server minimal standard server add_package ubuntu-server-minimal.ubuntu-server cloud-init add_task ubuntu-server-minimal.ubuntu-server.installer server-live # Live server ISOs for LTS point releases past .2 offer both # the GA and HWE kernels (in separate layers) so this code is # written generically to support both even though a lot of the # time only one kernel is offered. case ${SUBARCH:-} in intel-iot) variants='intel' ;; tegra) variants='tegra' ;; tegra-igx) variants='tegra-igx' ;; *) # variants='ga hwe' variants='ga' ;; esac for variant in $variants; do if [ "$variant" = "ga" ]; then kernel_metapkg=linux-generic flavor=generic elif [ "$variant" = "hwe" ]; then kernel_metapkg=linux-generic-hwe-$(lsb_release -sr) flavor=generic-hwe elif [ "$variant" = "intel" ]; then kernel_metapkg=linux-intel-iotg flavor=intel-iotg elif [ "$variant" = "tegra" ]; then kernel_metapkg=linux-nvidia-tegra flavor=nvidia-tegra elif [ "$variant" = "tegra-igx" ]; then kernel_metapkg=linux-nvidia-tegra-igx flavor=nvidia-tegra-igx else echo "bogus variant: $variant" exit 1 fi add_package ubuntu-server-minimal.ubuntu-server.installer.$flavor $kernel_metapkg LIVE_PASSES="${LIVE_PASSES:+$LIVE_PASSES }ubuntu-server-minimal.ubuntu-server.installer.$flavor" done case $ARCH in amd64) add_package ubuntu-server-minimal.ubuntu-server.installer.generic.netboot grub-pc shim-signed pxelinux ;; arm64) add_package ubuntu-server-minimal.ubuntu-server.installer.generic.netboot shim-signed ;; *) add_package ubuntu-server-minimal.ubuntu-server.installer.generic.netboot ;; esac NO_SQUASHFS_PASSES=ubuntu-server-minimal.ubuntu-server.installer.generic.netboot /usr/share/livecd-rootfs/checkout-translations-branch \ https://git.launchpad.net/subiquity po config/catalog-translations ;; *) echo "unrecognized subproject for server: '$SUBPROJECT'" exit 1 ;; esac PREINSTALL_POOL_SEEDS='server-ship' ;; ubuntu-mini-iso) OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal" OPTS="${OPTS:+$OPTS }--linux-packages=none --initramfs=none" KERNEL_FLAVOURS=none BINARY_REMOVE_LINUX=false add_package install mini-iso-tools openssl ca-certificates isc-dhcp-client linux-generic case $ARCH in amd64) add_package install cd-boot-images-amd64 ;; *) echo "unexpected architecture for $PROJECT: '$ARCH'" exit 1 ;; esac ;; ubuntu-base|ubuntu-oci) OPTS="${OPTS:+$OPTS }--bootstrap-flavour=minimal" ;; ubuntu-wsl) add_task install minimal ubuntu-wsl OPTS="${OPTS:+$OPTS }--linux-packages=none --initramfs=none" KERNEL_FLAVOURS=none BINARY_REMOVE_LINUX=false ;; ubuntu-cpc) KERNEL_FLAVOURS=virtual if [ "${SUBPROJECT:-}" = minimized ]; then # For minimized images we do not want to install any recommended packages. # We can do this by setting APT::Install-Recommends to false in apt config # or by passing --no-install-recommends to apt-get install. # Apt config is set using `APT_OPTIONS` variable in this script. # This fixes LP: #2031640 # # We're also installing python3-systemd for now because it's needed by # ubuntu-advantage-tools. This will eventually be dropped in the next # release of u-a-t. This is being discussed and tracked at # https://github.com/canonical/ubuntu-pro-client/issues/2692. # Once python3-systemd is dropped from u-a-t, we can remove it # from here, too. APT_OPTIONS="${APT_OPTIONS:+$APT_OPTIONS }--no-install-recommends" add_package install ubuntu-cloud-minimal python3-systemd else add_task install minimal standard cloud-image add_package install ubuntu-minimal case $ARCH in armhf|arm64|ppc64el|powerpc) add_task install server ;; esac fi BINARY_REMOVE_LINUX=false OPTS="${OPTS:+$OPTS }--initramfs=none" case "$ARCH+${SUBARCH:-}" in *+raspi) add_task install ubuntu-server-raspi ;; arm64*) if [ "${SUBARCH:-}" = "generic" ]; then KERNEL_FLAVOURS=generic fi ;; amd64*) if [ "${SUBARCH:-}" = "generic" ]; then KERNEL_FLAVOURS=generic elif [ "${SUBARCH:-}" = "intel-iot" ]; then KERNEL_FLAVOURS=intel-iotg OPTS="${OPTS:+$OPTS }--initramfs=none" fi ;; riscv64*) if [ -n "$SUBARCH" ]; then case "${SUBARCH:-}" in nezha|licheerv) KERNEL_FLAVOURS=allwinner ;; visionfive) KERNEL_FLAVOURS=starfive ;; *) KERNEL_FLAVOURS=generic ;; esac fi ;; esac OPTS="${OPTS:+$OPTS }--system=normal" OPTS="${OPTS:+$OPTS }--hdd-label=cloudimg-rootfs" OPTS="${OPTS:+$OPTS }--ext-resize-blocks=536870912 --ext-block-size=4096" OPTS="${OPTS:+$OPTS }--ext-fudge-factor=15" ;; *) echo "unknown project $PROJECT" >&2 exit 2 ;; esac case $SUBPROJECT in buildd) OPTS="${OPTS:+$OPTS }--archive-areas main" OPTS="${OPTS:+$OPTS }--apt-recommends false" OPTS="${OPTS:+$OPTS }--apt-secure false" OPTS="${OPTS:+$OPTS }--parent-mirror-binary ${MIRROR}" # XXX cjwatson 2018-04-27: We need to work out how to make # this conditional so that we can do things like building # buildd chroots with -updates. This probably involves # either extending the PROPOSED hack or fixing the strange # way that SUITE is in fact a series; in either case it's # likely to involve work both here and in launchpad-buildd. OPTS="${OPTS:+$OPTS }--security false --volatile false" add_package install adduser add_package install pkgbinarymangler add_package install ca-certificates add_package install gpg add_package install gpg-agent add_package install fakeroot add_package install build-essential # Needed for LXD-based builds. add_package install init # Not strictly build-essential, but traditionally present # 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 ;; esac # we'll expand the base seed given here according to the STRUCTURE file, and # then look in all of the seeds found to see which snaps are seeded case $PROJECT:${SUBPROJECT:-} in ubuntu-wsl:*) BASE_SEED='wsl' ;; ubuntu-cpc:*) # we don't preseed any snaps in minimized images, so no need to set # BASE_SEED in that case. if [ "${SUBPROJECT:-}" != minimized ]; then BASE_SEED='server' fi ;; ubuntu-server:live) BASE_SEED='server' ;; ubuntu-base:*|ubuntu-core:*|ubuntu-mini-iso:|ubuntu-oci:*|\ xubuntu:minimal) ;; edubuntu:*) BASE_SEED='desktop-gnome' ;; *) BASE_SEED='desktop' ;; esac if [ "$PROJECT:${SUBPROJECT:-}" = ubuntu-cpc:minimized ]; then # We install a lxc script that installs the snap when invoked and # don't want any other snaps. if [ -s config/seeded-snaps ]; then echo "Unexpected seeded snaps for ubuntu-cpc:minimized build:" cat config/seeded-snaps exit 1 fi # Create an empty file to trigger initialization of assertions. truncate --size 0 config/seeded-snaps fi # grab a list of packags to remove for a "minimal" installation from the seed # mirror for this project if [ -n "${BASE_SEED}" ]; then minimal_packages_url=${SEEDMIRROR}/${SEED}/${BASE_SEED}.minimal-remove echo -n "Checking ${minimal_packages_url} for a minimal installation list... " minimal_packages_remove=$(wget -q -O- ${minimal_packages_url} | sed -e '/\s*#.*$/d' -e '/^\s*$/d') if [ -n "${minimal_packages_remove}" ]; then echo "${minimal_packages_remove}" > config/manifest-minimal-remove echo "$(echo ${minimal_packages_remove} | tr '\n' ' ')" else echo "failed to retrieve, not including." fi fi export APT_OPTIONS if [ "$PREINSTALLED" != "true" ] && [ "$PASSES_TO_LAYERS" != "true" ] && [ "$LIVE_TASK" ]; then add_task live "$LIVE_TASK" fi case $PROJECT in *-dvd) add_task live "$PROJECT-live" ;; esac case "$ARCH${SUBARCH:++$SUBARCH}" in arm*+raspi) # Common configuration for all Raspberry Pi image variants (server, # desktop etc.) KERNEL_FLAVOURS="$SUBARCH" # Most Pi-specific package installation is handled via the seeds in the # per-project/subproject cases above add_package install linux-firmware-raspi pi-bluetooth u-boot-rpi u-boot-tools BINARY_REMOVE_LINUX=false ;; arm64+tegra|arm64+tegra-igx) # Common configuration for all NVIDIA Tegra image variants # (server, desktop etc.) KERNEL_FLAVOURS="nvidia-$SUBARCH" ;; riscv*+*) if [ "${SUBARCH:-}" = "licheerv" ]; then # The wifi driver of the licheerv is an out-of-tree driver packaged # in universe for now, so to ease its installation for those without # network, install its dependencies. add_package install dkms fi # We'll add wpasupplicant to the seeds when we work on RISC-V seeds. add_package install wpasupplicant ;; esac case $PROJECT:${SUBPROJECT:-} in ubuntu-server:*|ubuntu-base:*|ubuntu-oci:*) OPTS="${OPTS:+$OPTS }--linux-packages=none --initramfs=none" KERNEL_FLAVOURS=none BINARY_REMOVE_LINUX=false ;; esac add_chroot_hook update-apt-file-cache add_chroot_hook update-apt-xapian-index add_chroot_hook update-mlocate-database add_chroot_hook remove-dbus-machine-id add_chroot_hook remove-openssh-server-host-keys add_chroot_hook remove-udev-persistent-rules case $PROJECT in # if any flavours want to strip .pyc files from their live images, add them here _) add_chroot_hook remove-python-py ;; esac lb config noauto \ --mode ubuntu \ --distribution "$SUITE" \ --iso-preparer "livecd-rootfs" \ --bootstrap-keyring ubuntu-keyring \ --binary-images "$BINARY_IMAGES" \ --memtest "$MEMTEST" \ $SOURCE \ --build-with-chroot false \ ${MIRROR:+--parent-mirror-bootstrap $MIRROR} \ ${COMPONENTS:+--parent-archive-areas "$COMPONENTS"} \ --apt-source-archives false \ ${KERNEL_FLAVOURS:+--linux-flavours "$KERNEL_FLAVOURS"} \ --initsystem none \ --bootloader "$BOOTLOADER" \ ${INITRAMFS_COMPRESSION:+--initramfs-compression "$INITRAMFS_COMPRESSION"} \ --checksums none \ --cache false \ ${BOOTAPPEND_LIVE:+--bootappend-live "$BOOTAPPEND_LIVE"} \ $OPTS \ "$@" PASSES=$(_sanitize_passes "$PASSES") LIVE_PASSES=${LIVE_PASSES:-$(_get_live_passes "$PASSES")} if [ -n "$PASSES" ] && [ -z "$LIVE_PASSES" ]; then echo "W: Multi-layered mode is enabled, but we didn't find any live pass." \ "Either set \$LIVE_PASSES or add a pass ending with '.live'." fi echo "LB_CHROOT_HOOKS=\"$CHROOT_HOOKS\"" >> config/chroot echo "SUBPROJECT=\"${SUBPROJECT:-}\"" >> config/chroot echo "LB_DISTRIBUTION=\"$SUITE\"" >> config/chroot echo "IMAGEFORMAT=\"$IMAGEFORMAT\"" >> config/chroot if [ -n "$PASSES" ]; then echo "PASSES=\"$PASSES\"" >> config/common fi if [ -n "$NO_SQUASHFS_PASSES" ]; then echo "NO_SQUASHFS_PASSES=\"$NO_SQUASHFS_PASSES\"" >> config/common fi if [ -n "$LIVE_PASSES" ]; then echo "LIVE_PASSES=\"$LIVE_PASSES\"" >> config/common fi echo "LB_BINARY_HOOKS=\"$BINARY_HOOKS\"" >> config/binary echo "BUILDSTAMP=\"$NOW\"" >> config/binary echo "SUBPROJECT=\"${SUBPROJECT:-}\"" >> config/binary echo "LB_DISTRIBUTION=\"$SUITE\"" >> config/binary echo "CHANNEL=\"${CHANNEL:-}\"" >> config/binary if [ "${IMAGE_HAS_HARDCODED_PASSWORD:-}" = "1" ]; then echo IMAGE_HAS_HARDCODED_PASSWORD=1 >> config/binary if [ -n "${IMAGE_TARGETS:-}" ]; then echo "IMAGE_TARGETS=\"${IMAGE_TARGETS:-}\"" >> config/binary fi fi # apply this hook unconditionally to remove files from the chroot that # are supposed to be install-specific secrets and therefore must never # be shipped in any image. # this hook should be extended if we discover any more files that are # supposed to be private but aren't. cat > config/hooks/100-too-many-secrets.chroot < config/hooks/100-add-lxd-group.chroot < config/hooks/01-firmware-directory.chroot_early < config/hooks/999-raspi-fixes.chroot <> /etc/fstab << EOM LABEL=system-boot /boot/firmware vfat defaults 0 1 EOM EOF ;; *) ;; esac if [ $PROJECT != ubuntu-cpc ]; then cat > config/hooks/100-preserve-apt-prefs.chroot <<\EOF #! /bin/sh -ex # live-build "helpfully" removes /etc/apt/preferences.d/* so we put a # copy somewhere it won't touch it. if [ -n "$(ls -A /etc/apt/preferences.d)" ]; then cp -a /etc/apt/preferences.d /etc/apt/preferences.d.save fi EOF fi if [ $PROJECT = ubuntukylin ]; then cat > config/hooks/100-ubuntukylin.chroot < config/binary_rootfs/excludes << EOF boot/vmlinu?-* boot/initrd.img-* EOF fi if [ "$PROPOSED" ]; then . config/bootstrap cat > config/archives/proposed.list.chroot << EOF deb $LB_PARENT_MIRROR_BINARY_VOLATILE $SUITE-proposed $LB_PARENT_ARCHIVE_AREAS EOF cp -a config/archives/proposed.list.chroot \ config/archives/proposed.list.binary mkdir -p config/chroot_apt/ cat > config/chroot_apt/proposed.pref < config/archives/dvd.list.binary << EOF deb $LB_PARENT_MIRROR_BINARY $SUITE universe multiverse deb $LB_PARENT_MIRROR_BINARY_VOLATILE $SUITE-updates universe multiverse deb $LB_PARENT_MIRROR_BINARY_SECURITY $SUITE-security universe multiverse EOF if [ "$PROPOSED" ]; then cat >> config/archives/dvd.list.binary << EOF deb $LB_PARENT_MIRROR_BINARY_VOLATILE $SUITE-proposed universe multiverse EOF fi ;; ubuntu-cpc:*|ubuntu-server:live|ubuntu:desktop-preinstalled| \ ubuntu-wsl:*|ubuntu-mini-iso:*|ubuntu:|ubuntu-oem:*) # Ensure that most things e.g. includes.chroot are copied as is for entry in /usr/share/livecd-rootfs/live-build/${PROJECT}/*; do case $entry in *hooks*) # But hooks are shared across the projects with symlinks # dereference them cp -afL $entry config/ ;; *) # Most places want to preserve symlinks as is cp -af $entry config/ ;; esac done if [ "$PROJECT" = "ubuntu-cpc" ] || [ "$PROJECT" = "ubuntu-oem" ] ; then case ${IMAGE_TARGETS:-} in "") config/hooks.d/make-hooks --hooks-dir config/hooks all ;; *) config/hooks.d/make-hooks --hooks-dir config/hooks \ "$IMAGE_TARGETS" ;; esac fi if [ "$IMAGEFORMAT" = none ]; then rm -f config/hooks/*.binary* fi ;; esac case $SUBPROJECT in buildd) cp -af /usr/share/livecd-rootfs/live-build/buildd/* config/ ;; esac if [ "$EXTRA_PPAS" ]; then rm -f config/archives/extra-ppas.list.chroot \ config/archives/extra-ppas.pref.chroot \ config/archives/extra-ppas.key.chroot gpg_tmpdir="$(mktemp -d)" run_gpg () { gpg --no-default-keyring --no-options --homedir "$gpg_tmpdir" \ --secret-keyring "$gpg_tmpdir/secring.gpg" \ --keyserver hkp://keyserver.ubuntu.com:80/ \ "$@" } for extra_ppa in $EXTRA_PPAS; do extra_ppa_pin='' extra_ppa_origin='' case $extra_ppa in *:*) extra_ppa_pin=${extra_ppa#*:} extra_ppa=${extra_ppa%:*} ;; esac extra_ppa_fingerprint="$(/usr/share/livecd-rootfs/get-ppa-fingerprint "$extra_ppa")" cat >> config/archives/extra-ppas.list.chroot <> config/archives/extra-ppas.pref.chroot echo "Pin: release o=$extra_ppa_origin" >> config/archives/extra-ppas.pref.chroot echo "Pin-Priority: $extra_ppa_pin" >> config/archives/extra-ppas.pref.chroot echo "" >> config/archives/extra-ppas.pref.chroot fi run_gpg --keyring "$gpg_tmpdir/pubring.gpg" \ --recv "$extra_ppa_fingerprint" run_gpg --keyring "$gpg_tmpdir/pubring.gpg" \ --output "$gpg_tmpdir/export.gpg" \ --export "$extra_ppa_fingerprint" got_fingerprint="$( run_gpg --keyring "$gpg_tmpdir/export.gpg" \ --fingerprint --batch --with-colons | grep '^fpr:' | cut -d: -f10)" if [ "$got_fingerprint" != "$extra_ppa_fingerprint" ]; then echo "Fingerprints do not match. Got:" >&2 echo "$got_fingerprint" | sed 's/^/ /' >&2 echo "Expected:" >&2 echo " $extra_ppa_fingerprint" >&2 exit 1 fi cat "$gpg_tmpdir/export.gpg" >> config/archives/extra-ppas.key.chroot rm -f "$gpg_tmpdir/export.gpg" done rm -rf "$gpg_tmpdir" cp -a config/archives/extra-ppas.list.chroot \ config/archives/extra-ppas.list.binary cp -a config/archives/extra-ppas.key.chroot \ config/archives/extra-ppas.key.binary if [ -f config/archives/extra-ppas.pref.chroot ]; then cp -a config/archives/extra-ppas.pref.chroot \ config/archives/extra-ppas.pref.binary fi fi if [ "$PREINSTALLED" = "true" ]; then if [ -n "$PREINSTALL_POOL_SEEDS" ]; then UNWANTED_SEEDS="${LIVE_TASK:+$LIVE_TASK }boot installer required" for i in $UNWANTED_SEEDS; do UNWANTED_SEEDS="${UNWANTED_SEEDS:+$UNWANTED_SEEDS }$(inheritance $i)" done for i in $PREINSTALL_POOL_SEEDS; do PREINSTALL_POOL_SEEDS="${PREINSTALL_POOL_SEEDS:+$PREINSTALL_POOL_SEEDS }$(inheritance $i)" done for i in $PREINSTALL_POOL_SEEDS; do case " $UNWANTED_SEEDS " in *" $i "*) ;; *) PPS_EXP="${PPS_EXP:+$PPS_EXP }$i" ;; esac done for i in $PPS_EXP; do PREINSTALL_POOL="$PREINSTALL_POOL $(awk '{print $1}' \ config/germinate-output/$i | egrep -v '^-|^Package|^\|' | tr '\n' ' ')" done fi if [ -n "$PREINSTALL_POOL" ]; then mkdir -p config/gnupg mkdir -p config/indices for component in $COMPONENTS; do (cd config/indices && \ wget $MIRROR/indices/override.$SUITE.$component && \ wget $MIRROR/indices/override.$SUITE.extra.$component \ ) done cat > config/hooks/100-preinstall-pool.chroot <