citadel/appimg-builder/stage-one.sh

239 lines
5.9 KiB
Bash
Executable File

#!/bin/bash
: ${APPIMG_BUILDER_BASE:="/usr/share/appimg-builder"}
source ${APPIMG_BUILDER_BASE}/common.inc
umount_if_tmpfs() {
if findmnt -t tmpfs -M ${1} > /dev/null; then
info "unmounting existing rootfs tmpfs"
umount ${1}
fi
}
setup_rootfs() {
umount_if_tmpfs ${ROOTFS}
if [[ -d ${ROOTFS} ]]; then
info "Removing existing rootfs at ${ROOTFS}"
rm -rf ${ROOTFS}
fi
mkdir --parents ${ROOTFS}
if [[ ${USE_TMPFS} -eq 1 ]]; then
mount -t tmpfs rootfs-tmp ${ROOTFS}
fi
chmod 0755 ${ROOTFS}
}
run_debootstrap() {
[[ -f ${CACHE_DIR}/lock ]] && rm -f ${CACHE_DIR}/lock
mkdir --parents ${CACHE_DIR} ${ROOTFS}/var/cache/apt/archives
info "Bind mounting ${CACHE_DIR} to ${ROOTFS}/var/cache/apt/archives"
mount --bind ${CACHE_DIR} ${ROOTFS}/var/cache/apt/archives
info "Launching debootstrap"
debootstrap --verbose --merged-usr --variant=minbase \
--include=systemd-sysv,locales \
${DEBIAN_RELEASE} ${ROOTFS} ${DEBIAN_MIRROR}
}
setup_chroot() {
mount chproc ${ROOTFS}/proc -t proc
mount chsys ${ROOTFS}/sys -t sysfs
mount chtmp ${ROOTFS}/tmp -t tmpfs
# Install a copy of appimg-builder inside new image
mkdir -p ${ROOTFS}/usr/share
cp -a ${APPIMG_BUILDER_BASE} ${ROOTFS}/usr/share
ln -s /usr/share/appimg-builder/stage-one.sh ${ROOTFS}/usr/bin/appimg-builder
# $BUILDFILE and any extra files go in /tmp/appimg-build of rootfs
mkdir -p ${ROOTFS}/tmp/appimg-build
cp ${BUILDFILE} ${ROOTFS}/tmp/appimg-build/build.conf
}
cleanup_chroot() {
umount ${ROOTFS}/proc
umount ${ROOTFS}/sys
umount ${ROOTFS}/tmp
umount ${ROOTFS}/var/cache/apt/archives
# Remove cache files in case we are creating a tarball for distribution
rm -f ${ROOTFS}/var/cache/apt/pkgcache.bin
rm -f ${ROOTFS}/var/cache/apt/srcpkgcache.bin
}
run_chroot_stage() {
setup_chroot
#
# Run second-stage.sh inside chroot(), pass in various environment variables
#
DEBIAN_FRONTEND=noninteractive \
DEBCONF_NONINTERACTIVE_SEEN=true \
LC_ALL=C LANGUAGE=C LANG=C \
DEBIAN_RELEASE=${DEBIAN_RELEASE} DEBIAN_MIRROR=${DEBIAN_MIRROR} \
chroot ${ROOTFS} /usr/share/appimg-builder/stage-two.sh /tmp/appimg-build/build.conf
info "chroot installation stage finished, cleaning chroot setup"
cleanup_chroot
}
generate_tarball() {
local tarball=${WORKDIR}/appimg-rootfs.tar
info "----- Generating rootfs tarball -----"
tar -C ${ROOTFS} --numeric-owner -c --xattrs --xattrs-include=* -f $tarball .
if [[ ${DO_XZ} -eq 1 ]]; then
info "Compressing $tarball"
xz --force --threads=0 $tarball
tarball=${tarball}.xz
fi
echo
ls -hl $tarball
echo
}
usage() {
cat <<-EOF
USAGE: appimg-builder [options] [config-file]
OPTIONS
--new Create a configuration file template called build.conf in the current directory
-d <directory> Choose a non-default directory for build output (currently: $(pwd)/appimg)
-t Create a tarball but don't compress it
-z Create a tarball compressed with xz
--no-tmpfs Do not use tmpfs as rootfs build directory
--no-confirm Do not ask for confirmation before beginning
For more documentation see /usr/share/appimg-builder/README
EOF
exit 0
}
ask_confirm() {
local use_tmpfs="No"
[[ ${USE_TMPFS} -eq 1 ]] && use_tmpfs="Yes"
printf "About to build application image with the following parameters:\n\n"
printf "\tBuild Configuration File : ${BUILDFILE}\n"
printf "\tOutput rootfs directory : ${ROOTFS}\n"
printf "\tBuild rootfs on tmpfs : ${use_tmpfs}\n"
[[ -e ${ROOTFS} ]] && printf "\nWarning: rootfs directory from a prior build exists and will be deleted before building new image\n\n"
read -p "Ok to proceed? (y/N): " confirm
[[ $confirm =~ ^[Yy] ]] || exit 0
}
try_config() {
local rp
rp=$(realpath ${1} 2> /dev/null) || return 1
[[ -f ${rp} ]] || return 1
printf "${rp}"
}
WORKDIR="$(pwd)/appimg"
DO_TAR=0
DO_XZ=0
USE_TMPFS=1
NO_CONFIRM=0
while [[ $# -gt 0 ]]; do
key=${1}
case $key in
-d)
mkdir -p "${2}"
WORKDIR="$(realpath ${2})"
shift
shift
;;
-t)
DO_TAR=1
shift
;;
-z)
DO_TAR=1 DO_XZ=1
shift
;;
--no-tmpfs)
USE_TMPFS=0
shift
;;
--no-confirm)
NO_CONFIRM=1
shift
;;
--new)
cp --verbose ${APPIMG_BUILDER_BASE}/build-template.conf build.conf
exit 0
;;
--help|-h|help)
usage
;;
-*)
printf "Unknown option ${key}\n"
usage
;;
*)
BUILDFILE=$(try_config ${1}) || fatal "Cannot find config file '${1}'"
shift
;;
esac
done
if [ "$EUID" -ne 0 ]; then
echo "The appimg-builder must be run with root privileges."
exit 1
fi
if [[ -z ${BUILDFILE} ]]; then
BUILDFILE=$(try_config "${PWD}/build.conf" || try_config "${APPIMG_BUILDER_BASE}/basic-image.conf") || fatal "Could not find a configuration file to use"
fi
ROOTFS=${WORKDIR}/rootfs
CACHE_DIR=${WORKDIR}/var-cache-apt-archives
[[ ${NO_CONFIRM} -ne 1 ]] && ask_confirm
# black magick from stack overflow
exec > >(tee -a $WORKDIR/appimg-build.log) 2>&1
info "Starting build of application image from configuration file ${BUILDFILE}"
source ${BUILDFILE}
setup_rootfs
run_debootstrap
run_chroot_stage
info "rootfs build is completed:"
info " $(du -sh ${ROOTFS})"
if [[ ${DO_TAR} -eq 1 ]]; then
generate_tarball
fi
if [[ ${USE_TMPFS} -eq 1 ]]; then
info "Root directory is a tmpfs. To remove mount and directory contents:"
info " sudo umount ${ROOTFS}"
fi