diff --git a/live-build/auto/build b/live-build/auto/build index 79d3d7a4..e9f20961 100755 --- a/live-build/auto/build +++ b/live-build/auto/build @@ -235,28 +235,11 @@ echo "command. You will still need to ensure the 'man-db' package is installed." EOF chmod +x chroot/usr/bin/man fi - Chroot chroot "dpkg-divert --quiet --add \ - --divert /usr/sbin/update-initramfs.REAL --rename \ - /usr/sbin/update-initramfs" - cat > chroot/usr/sbin/update-initramfs <<'EOF' -#! /bin/sh -if [ $# != 1 ] || [ "$1" != -u ]; then - exec update-initramfs.REAL "$@" -fi -echo "update-initramfs: diverted by livecd-rootfs (will be called later)" >&2 -exit 0 -EOF - chmod +x chroot/usr/sbin/update-initramfs - - cat > config/hooks/999-undivert-update-initramfs.chroot <<'EOF' -#! /bin/sh -rm -f /usr/sbin/update-initramfs -dpkg-divert --quiet --remove --rename /usr/sbin/update-initramfs -EOF if [ -n "${PASSES}" ]; then PATH="config/:$PATH" lb chroot_layered "$@" else + divert_update_initramfs lb chroot "$@" fi @@ -453,7 +436,7 @@ for OUTPUT in ext2 ext3 ext4 manifest manifest-remove size squashfs; do done # we don't need a manifest-remove for a layered-aware installer -if [ "$SUBPROJECT" = "ubiquity-ng" ]; then +if [ "$PROJECT" = "ubuntu" ] && [ "$SUBPROJECT" = "canary" ]; then rm -f livecd.${PROJECT}-manifest-remove rm -f config/manifest-minimal-remove fi diff --git a/live-build/auto/config b/live-build/auto/config index 7f63163b..21d173ac 100755 --- a/live-build/auto/config +++ b/live-build/auto/config @@ -59,6 +59,40 @@ 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_task () { local pass="$1" @@ -68,6 +102,9 @@ add_task () local snap_list_files local curseed + _check_immutable_passes_to_layers + _register_pass "$pass" + # The removal of direct task installation support from live-build # poses some problems. If the chroot has multiarch configured - for # example, if we're building for amd64 - then dumpavail will show @@ -113,40 +150,80 @@ add_task () 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 } -add_layered_pass() { - # Add a layer to an existing pass based on seeds matching a regexp +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_packages_from_seed_regexp () { + # Creates one or more passes, depending on base_pass_name, from any seeds matching seed_regexp. # $1 base pass # $2 seeds (regexp) + local pass + + _check_immutable_passes_to_layers + _check_layers_only_API "add_packages_from_seed_regexp" for seed in $(ls config/germinate-output/|grep -P "$2"); do - pass=${1}_${seed} + pass=${1}.${seed} + _register_pass "$pass" list_packages_from_seed ${seed} >> config/package-lists/livecd-rootfs.list.chroot_$pass done } -add_layered_pass_delta() { - # Add a layer to an existing pass based on delta between seeds matching a regexp and a base seed +remove_packages_from_seed_regexp() { + # Creates one or more passes, based on base_pass_name, from any seed matching seed_regexp. + # This package list is a list of packages to remove (and included in a previous dependent + # pass then), resulting from base_seed - {current_seed_match_from_regexp}. # $1 base pass # $2 base seed # $3 seeds to remove from base seed (regexp). If empty, a no- sublayer is generated. + local pass + + _check_immutable_passes_to_layers + _check_layers_only_API "remove_packages_from_seed_regexp" local seed_regexp="$3" if [ -z "${seed_regexp}" ]; then - subtract_package_lists ${2} "" >> config/package-lists/livecd-rootfs.removal-list.chroot_${1}_no-${2} + pass="${1}.no-${2}" + _register_pass "$pass" + subtract_package_lists ${2} "" >> config/package-lists/livecd-rootfs.removal-list.chroot_$pass return fi for seed in $(ls config/germinate-output/|grep -P "$seed_regexp"); do - pass=${1}_${seed} + pass="${1}.${seed}" + _register_pass "$pass" subtract_package_lists ${2} ${seed} >> config/package-lists/livecd-rootfs.removal-list.chroot_$pass done } @@ -161,6 +238,28 @@ 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" + exit 1 + fi + done + + # return the list of passes + echo $passes +} + if [ -z "${IMAGEFORMAT:-}" ]; then case $PROJECT:${SUBPROJECT:-} in ubuntu-cpc:*) @@ -289,6 +388,11 @@ case $IMAGEFORMAT in case $PROJECT in ubuntu-server|ubuntu-touch|ubuntu-touch-custom) ;; + ubuntu) + if [ $SUBPROJECT != "canary" ]; then + add_package live lupin-casper + fi + ;; *) add_package live lupin-casper ;; @@ -390,28 +494,33 @@ esac case $PROJECT in ubuntu|ubuntu-dvd) - LIVE_TASK='ubuntu-live' case ${SUBPROJECT:-} in - ubiquity-ng) - PASSES="install-minimal install live" - add_task install-minimal minimal standard ubuntu-desktop-minimal ubuntu-desktop-minimal-default-languages - add_task install ubuntu-desktop ubuntu-desktop-default-languages - - # LANG PASS for minimal and install - add_layered_pass_delta install-minimal desktop-minimal-default-languages '^desktop-minimal-(?!default-languages)[^.]+$' - add_layered_pass_delta install-minimal desktop-minimal-default-languages '' # none (if no default langpack is selected) - add_layered_pass_delta install desktop-default-languages '^desktop-(?!default-languages|minimal|common)[^.]+$' - add_layered_pass_delta install desktop-default-languages '' # none (if no default langpack is selected) + canary) + PASSES_TO_LAYERS="true" + add_task minimal minimal standard ubuntu-desktop-minimal ubuntu-desktop-minimal-default-languages + add_task minimal.standard ubuntu-desktop ubuntu-desktop-default-languages + add_task minimal.standard.live ubuntu-live + add_package minimal.standard.live lupin-casper + + case $ARCH in + amd64) add_package minimal.standard.live $SIGNED_KERNEL_PACKAGE ;; + esac + + # LANG PASS for minimal and standard + remove_packages_from_seed_regexp minimal desktop-minimal-default-languages '^desktop-minimal-(?!default-languages)[^.]+$' + remove_packages_from_seed_regexp minimal desktop-minimal-default-languages '' # none (if no default langpack is selected) + remove_packages_from_seed_regexp minimal.standard desktop-default-languages '^desktop-(?!default-languages|minimal|common)[^.]+$' + remove_packages_from_seed_regexp minimal.standard desktop-default-languages '' # none (if no default langpack is selected) ;; *) + LIVE_TASK='ubuntu-live' add_task install minimal standard ubuntu-desktop ubuntu-desktop-minimal-default-languages ubuntu-desktop-default-languages + case $ARCH in + amd64) add_package live $SIGNED_KERNEL_PACKAGE ;; + esac ;; esac - - case $ARCH in - amd64) add_package live $SIGNED_KERNEL_PACKAGE ;; - esac ;; ubuntu-desktop-next) @@ -786,7 +895,7 @@ case $PROJECT:${SUBPROJECT:-} in ;; esac -if [ -z "$PASSES" ] && [ -n "${BASE_SEED}" ]; then +if [ "$PASSES_TO_LAYERS" != "true" ] && [ -n "${BASE_SEED}" ]; then snap_from_seed "${BASE_SEED}" config/seeded-snaps fi @@ -806,7 +915,7 @@ fi export APT_OPTIONS -if [ "$PREINSTALLED" != "true" ] && [ "$LIVE_TASK" ]; then +if [ "$PREINSTALLED" != "true" ] && [ "$PASSES_TO_LAYERS" != "true" ] && [ "$LIVE_TASK" ]; then add_task live "$LIVE_TASK" fi @@ -921,6 +1030,8 @@ lb config noauto \ $OPTS \ "$@" +PASSES=$(_sanitize_passes "$PASSES") + echo "LB_CHROOT_HOOKS=\"$CHROOT_HOOKS\"" >> config/chroot echo "SUBPROJECT=\"${SUBPROJECT:-}\"" >> config/chroot echo "LB_DISTRIBUTION=\"$SUITE\"" >> config/chroot diff --git a/live-build/functions b/live-build/functions index 1127897e..64984e35 100644 --- a/live-build/functions +++ b/live-build/functions @@ -137,6 +137,22 @@ mount_overlay() { "$path" } +get_lowerdirs_for_pass () { + # Returns the name of the lowerdir from the name of a pass + # $1 Name of the pass + local curpass="$1" + local lowerlayers="" + + while :; do + curpass=$(get_parent_pass $curpass) + # We climbed up the tree to the root layer, we are done + [ -z "$curpass" ] && break + + lowerlayers="${lowerlayers}:overlay.${curpass}" + done + echo "${lowerlayers#:}" +} + mount_disk_image() { local disk_image=${1} local mountpoint=${2} @@ -680,7 +696,7 @@ configure_network_manager() { # default. Installing NM on an existing system only manages wifi and wwan via # /usr/lib/NetworkManager/conf.d/10-globally-managed-devices.conf. When setting # the global backend to NM, netplan overrides that file. - if [ -e chroot/usr/sbin/NetworkManager ]; then + if [ -e chroot/usr/sbin/NetworkManager -a ! -f chroot/etc/netplan/01-network-manager-all.yaml ]; then echo "===== Enabling all devices in NetworkManager ====" mkdir -p chroot/etc/netplan cat < chroot/etc/netplan/01-network-manager-all.yaml @@ -693,3 +709,53 @@ EOF echo "==== NetworkManager not installed ====" fi } + +get_parent_pass () { + # return parent pass + # $1 name of the pass + # return parent pass name or '' if pass is root pass. + local pass="$1" + + parent_pass=${pass%.*} + if [ "${parent_pass}" = "${pass}" ]; then + return + fi + echo ${pass%.*} +} + +setenv_file () { + # Exposes an environment variable in a chroot + # $1 Name of the variable + # $2 Value of the variable + # $3 Path to the environment file of the chroot + local var="$1" + local val="$2" + local file="$3" + + grep -v "^$var" $file || true > $file.new + echo "${var}=${val}" >> $file.new + mv $file.new $file +} + +divert_update_initramfs () { + Chroot chroot "dpkg-divert --quiet --add \ + --divert /usr/sbin/update-initramfs.REAL --rename \ + /usr/sbin/update-initramfs" + cat > chroot/usr/sbin/update-initramfs <<'EOF' +#! /bin/sh +if [ $# != 1 ] || [ "$1" != -u ]; then + exec update-initramfs.REAL "$@" +fi +echo "update-initramfs: diverted by livecd-rootfs (will be called later)" >&2 + +exit 0 +EOF + chmod +x chroot/usr/sbin/update-initramfs + + cat > config/hooks/999-undivert-update-initramfs.chroot <<'EOF' +#! /bin/sh +[ ! -f /usr/sbin/update-initramfs.REAL ] && exit 0 +rm -f /usr/sbin/update-initramfs +dpkg-divert --quiet --remove --rename /usr/sbin/update-initramfs +EOF +} diff --git a/live-build/lb_binary_layered b/live-build/lb_binary_layered index b100339a..3b3b0b7c 100755 --- a/live-build/lb_binary_layered +++ b/live-build/lb_binary_layered @@ -37,18 +37,28 @@ Setup_cleanup . config/functions -build_layered_squashfs() { - local pass=$1 # install|install_subpass|install_subpass_subsubpass|… - local prevpass=$2 # install|install_subpass|… - local prefix=$3 # 01-|02-|… - local lowerlayers=$4 - shift 4 # restore ${*} +lb_binary_includes () { + # Copying includes from pass subdirectory + local pass="$1" - # Cleanup root filesystem - lb binary_chroot ${*} + if [ ! -d config/includes.binary.${pass} ]; then + return + fi + + cd config/includes.binary.${pass} + find . | cpio -dmpu --no-preserve-owner "${OLDPWD}"/chroot + cd "${OLDPWD}" +} + +build_layered_squashfs () { + local pass=$1 + shift 1 # restore ${*} + + Echo_message "lb_binary_layered: treating pass $pass" # Building squashfs filesystem & manifest - base="${PWD}/livecd.${PROJECT}.${prefix}${pass}" + local overlay_dir="overlay.${pass}" + base="${PWD}/livecd.${PROJECT}.${pass}" squashfs_f="${base}.squashfs" # We have already treated that pass @@ -56,77 +66,67 @@ build_layered_squashfs() { return fi - if [ -n "${lowerlayers}" ]; then - mount_overlay ${lowerlayers} "overlay.${pass}/" chroot/ + rm -f .build/binary_chroot + + mkdir -p "$overlay_dir/" + lowerdirs=$(get_lowerdirs_for_pass $pass) + if [ -n "$lowerdirs" ]; then + mkdir -p chroot/ + mount_overlay "$lowerdirs" "$overlay_dir" chroot/ else - # first pass - rmdir chroot 2>/dev/null||true - ln -s "overlay.${pass}/" chroot + ln -s "$overlay_dir/" chroot fi + export PASS=${pass} + setenv_file PASS "${pass}" config/environment.chroot + + # Cleanup root filesystem + lb binary_chroot ${*} + + lb_binary_includes $pass ${*} + lb binary_hooks ${*} + # Full manifest until that PASS squashfs_f_manifest="${base}.manifest" create_manifest "chroot" "${squashfs_f_manifest}.full" # Delta manifest - diff -NU0 ${PWD}/livecd.${PROJECT}.[0-9][0-9]-${prevpass}.manifest.full ${squashfs_f_manifest}.full|grep -v ^@ > $squashfs_f_manifest + diff -NU0 ${PWD}/livecd.${PROJECT}.$(get_parent_pass $pass).manifest.full ${squashfs_f_manifest}.full|grep -v ^@ > $squashfs_f_manifest squashfs_f_size="${base}.size" du -B 1 -s "overlay.${pass}/" | cut -f1 > "${squashfs_f_size}" + # We take first live path for "global" ISO properties (used by installers and checkers): + # Prepare initrd + kernel + # Main manifest and size files + prefix="livecd.$PROJECT${SUBARCH:+-$SUBARCH}" + if echo $pass | grep -Eq '\.live*' && test ! -e "${prefix}.manifest"; then + lb binary_linux-image ${*} + cp ${squashfs_f_size} "${prefix}.size" + cp "${squashfs_f_manifest}.full" "${prefix}.manifest" + fi + (cd "overlay.${pass}/" && mksquashfs . ${squashfs_f} \ -no-progress -xattrs -comp xz ) - if [ -n "${lowerlayers}" ]; then + if [ -n "$lowerdirs" ]; then umount chroot + rmdir chroot else rm chroot - mkdir chroot/ fi - - # Handle direct sublayer of current one - # Extract the name of the pass corresponding to the sublayer - for subpass in $(ls -d overlay.${pass}_* 2>/dev/null | sed -e "s/overlay\.\(${pass}_[^_]\+\).*/\1/"); do - lowerlayers_for_subpass="overlay.${pass}:${lowerlayers}" - lowerlayers_for_subpass="${lowerlayers_for_subpass%:}" - build_layered_squashfs "${subpass}" "${pass}" "${prefix}" "${lowerlayers_for_subpass}" ${*} - done } -CURPASS=1 -PREVPASS="" -PASSPREFIX="" -LOWER_LAYERS="" for _PASS in $PASSES do - PASSPREFIX="$(printf "%02g" $CURPASS)-" - - build_layered_squashfs "${_PASS}" "${PREVPASS}" "$PASSPREFIX" "${LOWER_LAYERS}" ${*} - - LOWER_LAYERS="overlay.${_PASS}:$LOWER_LAYERS" - LOWER_LAYERS="${LOWER_LAYERS%:}" - PREVPASS=${_PASS} - CURPASS=$(( CURPASS + 1 )) + build_layered_squashfs "${_PASS}" ${*} done -# remount last "main" pass on chroot for lb binary -mount_overlay "${LOWER_LAYERS}" "overlay.${_PASS}/" chroot/ - -# Prepare initrd + kernel -lb binary_linux-image ${*} - -umount chroot/ - -# Full ISO manifest & size from last main PASS -PREFIX="livecd.$PROJECT${SUBARCH:+-$SUBARCH}" -cp "livecd.${PROJECT}.${PASSPREFIX}${_PASS}.size" "$PREFIX.size" -cp "livecd.${PROJECT}.${PASSPREFIX}${_PASS}.manifest.full" "$PREFIX.manifest" - # Ubiquity-compatible removal manifest for ISO not using a layered-aware installer -if [ -n "$(ls livecd.${PROJECT}.[0-9][0-9]-live.manifest.full 2>/dev/null)" ] && \ - [ -n "$(ls livecd.${PROJECT}.[0-9][0-9]-install.manifest.full 2>/dev/null)" ]; then - echo "$(diff livecd.${PROJECT}.[0-9][0-9]-live.manifest.full livecd.${PROJECT}.[0-9][0-9]-install.manifest.full | awk '/^< / { print $2 }')" > livecd.${PROJECT}-manifest-remove +if [ -n "$(ls livecd.${PROJECT}.*install.live.manifest.full 2>/dev/null)" ] && \ + [ -n "$(ls livecd.${PROJECT}.*install.manifest.full 2>/dev/null)" ]; then + echo "$(diff livecd.${PROJECT}.*install.live.manifest.full livecd.${PROJECT}.*install.manifest.full | awk '/^< / { print $2 }')" > livecd.${PROJECT}-manifest-remove fi chmod 644 *.squashfs *.manifest* *.size diff --git a/live-build/lb_chroot_layered b/live-build/lb_chroot_layered index 89b84724..c65a6af4 100755 --- a/live-build/lb_chroot_layered +++ b/live-build/lb_chroot_layered @@ -41,7 +41,7 @@ Setup_cleanup . config/functions -lb_chroot_remove_packages() { +lb_chroot_remove_packages () { # Remove packages from the chroot specific to this layer # # $1: Name of the pass* @@ -54,28 +54,28 @@ lb_chroot_remove_packages() { } # Create the snap list specific to this layer -lb_chroot_snap_lists() { +lb_chroot_snap_lists () { local pass=$1 - local prevpass=$2 # This assumes that the prefix is unique for a given project local snap_for_pass=$(ls config/package-lists/*.snaplist.chroot_${pass}.full 2>/dev/null || true) - local snap_for_prevpass=$(ls config/package-lists/*.snaplist.chroot_${prevpass}.full 2>/dev/null || true) + parent_pass=$(get_parent_pass $pass) + local snap_for_parent_pass=$(ls config/package-lists/*.snaplist.chroot_${parent_pass}.full 2>/dev/null || true) if [ -z "${snap_for_pass}" ]; then return fi - if [ -z "${snap_for_prevpass}" ]; then + if [ -z "${snap_for_parent_pass}" ]; then cp ${snap_for_pass} ${snap_for_pass%.full} return fi # Generate a list of snaps added to a layer. - diff -NU0 ${snap_for_prevpass} ${snap_for_pass}|grep -Ev '^(---|\+\+\+|@@)'|cut -c2- > ${snap_for_pass%.full} + diff -NU0 ${snap_for_parent_pass} ${snap_for_pass}|grep -Ev '^(---|\+\+\+|@@)'|cut -c2- > ${snap_for_pass%.full} } -lb_chroot_install_snaps() { +lb_chroot_install_snaps () { # Prepare the snap environment and install snaps into a chroot # # $1: Name of the pass @@ -93,7 +93,7 @@ lb_chroot_install_snaps() { done < $snaplist_file } -lb_chroot_includes() { +lb_chroot_includes () { # Copying includes from pass subdirectory local pass="$1" @@ -106,30 +106,47 @@ lb_chroot_includes() { cd "${OLDPWD}" } -create_chroot_pass() { +create_chroot_pass () { local pass=$1 - local prevpass=$2 - local lowerlayers=$3 - local passtype=$4 # "first"|"last"|"" empty string - shift 4 # restore ${*} + shift 1 # restore ${*} - # We have already treated that pass - if [ -d "overlay.${pass}/" ]; then + Echo_message "lb_chroot_layered: treating pass $pass" + + # We have already treated that pass just return. + local overlay_dir="overlay.${pass}" + if [ -d "$overlay_dir/" ]; then return fi - export PASS=${pass} - - if [ "${passtype}" != "first" ]; then - mkdir overlay.${pass} - mount_overlay ${lowerlayers} "overlay.${pass}/" chroot/ + # Only get some function executed on root passes + # Copy bootstrap on root layers + if [ -z "$(get_parent_pass $pass)" ]; then + rm -f .build/chroot_linux-image .build/chroot_preseed .build/chroot_hacks + cp -a chroot.bootstrap/ "$overlay_dir/" + fi + # Others have to be executed on every pass + rm -f .build/chroot_early_hooks .build/chroot_hooks .build/chroot_interactive + + mkdir -p "$overlay_dir/" + lowerdirs=$(get_lowerdirs_for_pass $pass) + if [ -n "$lowerdirs" ]; then + mkdir -p chroot/ + mount_overlay "$lowerdirs" "$overlay_dir" chroot/ + else + ln -s "$overlay_dir/" chroot fi + export PASS=${pass} + setenv_file PASS "${pass}" config/environment.chroot + # Configuring chroot - lb chroot_cache restore ${*} lb chroot_devpts install ${*} lb chroot_proc install ${*} lb chroot_sysfs install ${*} + # We run chroot_hacks only on root layers (update-initramfs diverted) + if [ -z "$(get_parent_pass $pass)" ]; then + divert_update_initramfs + fi lb chroot_debianchroot install ${*} lb chroot_dpkg install ${*} lb chroot_tmpfs install ${*} @@ -140,10 +157,11 @@ create_chroot_pass() { # Note: this triggers an upgrade + dist-ugprade; which may impact sublayers with more # diff content than desired. However, we still need to setup the archive and teardown # for each layer. - # We could modify livebuild if necessary to have conditional upgrade (first pass only). + # We could modify livebuild if necessary to have conditional upgrade (root pass only). lb chroot_archives chroot install ${*} - if [ "${passtype}" = "first" ]; then + # Only configure universe on root passes + if [ -z "$(get_parent_pass $pass)" ]; then configure_universe fi @@ -157,23 +175,22 @@ create_chroot_pass() { lb_chroot_remove_packages ${pass} ${*} # Snap management - lb_chroot_snap_lists ${pass} ${prevpass} + lb_chroot_snap_lists ${pass} ${*} lb_chroot_install_snaps ${pass} ${*} - # Kernel should be in first layer - if [ "${passtype}" = "first" ]; then - configure_network_manager - Chroot chroot "dpkg -l linux-headers-3* linux-headers-4*" 2>/dev/null \ + configure_network_manager + + # Mark kernel headers as autoremovable + Chroot chroot "dpkg -l linux-headers-3* linux-headers-4*" 2>/dev/null \ | awk '/^i/ {print $2}' > chroot.headers - for i in $(cat chroot.headers); do - Chroot chroot "apt-mark auto $i" - done - fi + for i in $(cat chroot.headers); do + Chroot chroot "apt-mark auto $i" + done Chroot chroot "apt-get --purge -y autoremove" - # Add live packages to top layer - if [ "${passtype}" = "last" ]; then + # Add live packages to live layers + if echo $pass | grep -Eq '\.live*'; then lb chroot_live-packages ${*} fi @@ -181,7 +198,14 @@ create_chroot_pass() { lb_chroot_includes ${pass} ${*} lb chroot_hooks ${*} + + # Run chroot_hacks only on root layers. + # chroot_hacks changes the mode of boot/initrd*. The side effect in + # layered mode is to create an initrd on each layer with a significant + # impact on image size (+30MB per layer). This is an issue even with + # update-initramfs disabled. lb chroot_hacks ${*} + lb chroot_interactive ${*} # Misc ubuntu cleanup and post-layer configuration @@ -202,45 +226,19 @@ create_chroot_pass() { lb chroot_sysfs remove ${*} lb chroot_proc remove ${*} lb chroot_devpts remove ${*} - lb chroot_cache save ${*} - if [ "${passtype}" = "first" ]; then - mv chroot overlay.${pass} - mkdir chroot - else + if [ -n "$lowerdirs" ]; then umount chroot + rmdir chroot + else + rm chroot fi - - # Handle direct sublayer of current one - # Extract the name of the pass corresponding to the sublayer - for subpass in $(ls config/package-lists/*list.chroot_${pass}_* 2>/dev/null | sed -e "s/.*list\.chroot_\(${pass}_[^_]\+\).*/\1/"); do - lowerlayers_for_subpass="overlay.${pass}:${lowerlayers}" - lowerlayers_for_subpass="${lowerlayers_for_subpass%:}" - create_chroot_pass "${subpass}" "${pass}" "${lowerlayers_for_subpass}" "" ${*} - done } -PASSES="${PASSES:-install live}" -CURPASS=1 -PREVPASS="" -LASTPASS=$(echo $PASSES|wc -w) -LOWER_LAYERS="" +if [ ! -d chroot.bootstrap/ ]; then + mv chroot/ chroot.bootstrap/ +fi for _PASS in $PASSES do - PASSTYPE="" - if [ $CURPASS -eq 1 ]; then - PASSTYPE="first" - elif [ $CURPASS -eq $LASTPASS ]; then - PASSTYPE="last" - fi - - create_chroot_pass "$_PASS" "$PREVPASS" "$LOWER_LAYERS" "$PASSTYPE" ${*} - - LOWER_LAYERS="overlay.${_PASS}:$LOWER_LAYERS" - LOWER_LAYERS="${LOWER_LAYERS%:}" - PREVPASS=${_PASS} - - CURPASS=$(( CURPASS + 1 )) + create_chroot_pass "$_PASS" ${*} done - -rmdir chroot