2018-03-07 18:52:40 -05:00
#!/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
}
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)
2018-03-15 12:15:52 -04:00
mkdir -p " ${ 2 } "
2018-03-07 18:52:40 -05:00
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