new appimg builder framework
This commit is contained in:
parent
0c193ec3dd
commit
07b3eb705d
87
appimg-builder/README
Normal file
87
appimg-builder/README
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
Application Image Builder
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Application Images (or appimgs for short) are created with this builder
|
||||||
|
framework. The build is controlled by a configuration file and this
|
||||||
|
configuration file is actually a shell script that follows the conventions
|
||||||
|
described in the Configuration File section of this document.
|
||||||
|
|
||||||
|
Stage One
|
||||||
|
---------
|
||||||
|
|
||||||
|
The Stage One builder uses debootstrap to build a very minimal debian
|
||||||
|
installation. Then a chroot is set up and stage-two.sh is executed inside the
|
||||||
|
chroot to perform most of the installation.
|
||||||
|
|
||||||
|
Stage Two
|
||||||
|
---------
|
||||||
|
|
||||||
|
The stage-two.sh script mostly just orchestrates the execution of small
|
||||||
|
fragments of shell script code that are called 'modules'. The base framework
|
||||||
|
modules can be found in the directory /usr/share/appimg-builder/appimg-modules.
|
||||||
|
|
||||||
|
It imports the configuration file with the 'source' command after all the key
|
||||||
|
variables and functions have been defined. It's possible to override any of
|
||||||
|
these variables and functions simply by defining another version with the same
|
||||||
|
name in the configuration file, but you should almost never need to do this.
|
||||||
|
|
||||||
|
Configuration File
|
||||||
|
------------------
|
||||||
|
|
||||||
|
- Variables
|
||||||
|
|
||||||
|
PACKAGES can be set to a list of additional packages to add to the base set of
|
||||||
|
packages.
|
||||||
|
|
||||||
|
PACKAGES="extremetuxracer biff anarchism"
|
||||||
|
|
||||||
|
PRE_INSTALL_MODULES can be set to a list of modules to run before the main
|
||||||
|
package installation stage happens. The contents will be appended to a
|
||||||
|
pre-defined list of 'base' modules that run.
|
||||||
|
|
||||||
|
PRE_INSTALL_MODULES="my-cool-module another-module"
|
||||||
|
|
||||||
|
If complete control over the modules to run is required, you can override the
|
||||||
|
variable BASE_PRE_INSTALL_MODULES entirely rather than providing
|
||||||
|
PRE_INSTALL_MODULES. Other modules depend on 'utility-library' so it is usually
|
||||||
|
required and should be the first module listed.
|
||||||
|
|
||||||
|
BASE_PRE_INSTALL_MODULES="utility-library configure-locale custom-create-user"
|
||||||
|
|
||||||
|
POST_INSTALL_MODULES is a list of modules to execute after packages have been
|
||||||
|
installed. It works exactly the same way as PRE_INSTALL_MODULES and also has a
|
||||||
|
corresponding 'base' variable that could be overidden if necessary.
|
||||||
|
|
||||||
|
- Modules
|
||||||
|
|
||||||
|
Modules can be functions that you define or they can be loaded from files on
|
||||||
|
disk. To use files rather than functions a directory named 'appimg-modules'
|
||||||
|
must exist as a subdirectory of the directory containing the configuration file.
|
||||||
|
Any files you place in this directory will be found by name during the module
|
||||||
|
execution stages.
|
||||||
|
|
||||||
|
- Installing Files
|
||||||
|
|
||||||
|
If you would like to have external files such as configuration files copied into
|
||||||
|
the image, create 'appimg-files' as a subdirectory of the directory containing
|
||||||
|
the configuration file. You can then use the install_file command inside of a
|
||||||
|
module to copy the files from this directory. You can either store the files to
|
||||||
|
install in a flat directory or organize them into subdirectories mirroring the
|
||||||
|
location in which they will be installed. Depending on which option you use,
|
||||||
|
the install_file command how two different modes. In the examples below BASE
|
||||||
|
refers to the directory in which your configuration file is located.
|
||||||
|
|
||||||
|
(1): install_file [mode] [file] [target directory]
|
||||||
|
|
||||||
|
Example: Install BASE/appimg-files/my_config.conf
|
||||||
|
to /etc/mydaemon/my_config.conf
|
||||||
|
|
||||||
|
install_file 0644 my_config.conf /etc/mydaemon
|
||||||
|
|
||||||
|
(2): install_file [mode] [full path]
|
||||||
|
|
||||||
|
Example: Install BASE/appimg-files/etc/mydaemon/my_config.conf
|
||||||
|
to /etc/mydaemon/my_config.conf
|
||||||
|
|
||||||
|
install_file 0644 /etc/mydaemon/my_config.conf
|
||||||
|
|
11
appimg-builder/appimg-files/configure-host0.service
Normal file
11
appimg-builder/appimg-files/configure-host0.service
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Run script to configure host0 interface
|
||||||
|
Before=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
ExecStart=/usr/libexec/configure-host0.sh
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=sysinit.target
|
28
appimg-builder/appimg-files/configure-host0.sh
Normal file
28
appimg-builder/appimg-files/configure-host0.sh
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# inspired by last section of
|
||||||
|
#
|
||||||
|
# https://www.freedesktop.org/wiki/Software/systemd/ContainerInterface/
|
||||||
|
#
|
||||||
|
SYSTEMD_ENV=$(xargs -a /proc/1/environ --null echo)
|
||||||
|
|
||||||
|
process_var() {
|
||||||
|
case ${1} in
|
||||||
|
"IFCONFIG_IP")
|
||||||
|
echo "IP: ${2}"
|
||||||
|
ip addr add ${2} dev host0
|
||||||
|
ip link set host0 up
|
||||||
|
;;
|
||||||
|
"IFCONFIG_GW")
|
||||||
|
echo "GW: ${2}"
|
||||||
|
ip route add default via ${2}
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
for var in ${SYSTEMD_ENV}; do
|
||||||
|
IFS="=" read -a PAIR <<< ${var}
|
||||||
|
if [[ ${#PAIR[@]} -eq 2 ]]; then
|
||||||
|
process_var ${PAIR[0]} ${PAIR[1]}
|
||||||
|
fi
|
||||||
|
done
|
7
appimg-builder/appimg-files/launch
Normal file
7
appimg-builder/appimg-files/launch
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
export DISPLAY=:0
|
||||||
|
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
|
||||||
|
export XDG_RUNTIME_DIR=/run/user/1000
|
||||||
|
export PULSE_SERVER=unix:/run/user/host/pulse/native
|
||||||
|
export GNOME_DESKTOP_SESSION_ID=this-is-deprecated
|
||||||
|
$@
|
6
appimg-builder/appimg-modules/configure-locale
Normal file
6
appimg-builder/appimg-modules/configure-locale
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
info "Setting up locale for en_US.UTF8"
|
||||||
|
|
||||||
|
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
|
||||||
|
locale-gen
|
||||||
|
update-locale LANG=en_US.UTF-8 LC_COLLATE=C
|
||||||
|
export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 LC_CTYPE=en_US.UTF-8
|
16
appimg-builder/appimg-modules/configure-systemd
Normal file
16
appimg-builder/appimg-modules/configure-systemd
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
info "Adding configuration files to /etc/systemd"
|
||||||
|
|
||||||
|
local userconfdir=/etc/systemd/user.conf.d
|
||||||
|
local loginconfdir=/etc/systemd/logind.conf.d
|
||||||
|
|
||||||
|
mkdir -p ${userconfdir} ${loginconfdir}
|
||||||
|
|
||||||
|
cat > ${userconfdir}/50-display-env.conf << 'EOF'
|
||||||
|
[Manager]
|
||||||
|
DefaultEnvironment="DISPLAY=:0"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat > ${loginconfdir}/50-no-kill-user-processes.conf << EOF
|
||||||
|
[Login]
|
||||||
|
KillUserProcesses=no
|
||||||
|
EOF
|
6
appimg-builder/appimg-modules/create-user
Normal file
6
appimg-builder/appimg-modules/create-user
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
info "Creating user account"
|
||||||
|
|
||||||
|
useradd -s /bin/bash -m user
|
||||||
|
echo "user:user" | chpasswd
|
||||||
|
usermod -aG sudo user
|
||||||
|
echo "export DISPLAY=:0" >> /home/user/.bashrc
|
5
appimg-builder/appimg-modules/install-configure-host0
Normal file
5
appimg-builder/appimg-modules/install-configure-host0
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
info "Installing scripts to configure host0 network interface"
|
||||||
|
|
||||||
|
install_file 0755 configure-host0.sh /usr/libexec
|
||||||
|
install_file 0644 configure-host0.service /usr/lib/systemd/system
|
||||||
|
systemctl -q enable configure-host0.service
|
2
appimg-builder/appimg-modules/install-launch-script
Normal file
2
appimg-builder/appimg-modules/install-launch-script
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
info "Installing launch script to /usr/libexec/launch"
|
||||||
|
install_file 0755 launch /usr/libexec
|
9
appimg-builder/appimg-modules/install-packages
Normal file
9
appimg-builder/appimg-modules/install-packages
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
info "Beginning package installation"
|
||||||
|
|
||||||
|
apt-get update
|
||||||
|
apt-get --assume-yes upgrade
|
||||||
|
apt-get --assume-yes install ${PACKAGES}
|
||||||
|
|
||||||
|
printf "\n\nInstalled Packages\n\n"
|
||||||
|
dpkg -l
|
||||||
|
printf "\n\n"
|
6
appimg-builder/appimg-modules/loginctl-enable-linger
Normal file
6
appimg-builder/appimg-modules/loginctl-enable-linger
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
info "Setting enable-linger for user account"
|
||||||
|
# Otherwise gnome-terminal won't work if nothing else has been launched
|
||||||
|
# see 'enable-linger' in loginctl(1)
|
||||||
|
local lingerdir="/var/lib/systemd/linger"
|
||||||
|
mkdir -p ${lingerdir}
|
||||||
|
touch ${lingerdir}/user
|
4
appimg-builder/appimg-modules/no-install-recommends
Normal file
4
appimg-builder/appimg-modules/no-install-recommends
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
info "Disabling Install-Recommends in apt.conf"
|
||||||
|
|
||||||
|
echo 'APT::Install-Recommends "0";' > /etc/apt/apt.conf.d/99no-install-recommends
|
||||||
|
echo 'APT::Install-Suggests "0";' >> /etc/apt/apt.conf.d/99no-install-recommends
|
4
appimg-builder/appimg-modules/set-hostname
Normal file
4
appimg-builder/appimg-modules/set-hostname
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
local hostname=${APPIMG_HOSTNAME:-"subgraph"}
|
||||||
|
info "Setting hostname to '$hostname' in /etc/hosts and /etc/hostname"
|
||||||
|
printf "127.0.0.1\t${hostname} localhost\n" > /etc/hosts
|
||||||
|
printf "${hostname}\n" > /etc/hostname
|
67
appimg-builder/appimg-modules/utility-library
Normal file
67
appimg-builder/appimg-modules/utility-library
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
info "utility library loaded"
|
||||||
|
SEARCH_PATH="/tmp/appimg-build;${APPIMG_BUILDER_BASE}"
|
||||||
|
|
||||||
|
# Searches for modules and files in SEARCH_PATH directories
|
||||||
|
#
|
||||||
|
# search_item module <module name>
|
||||||
|
# search_item file <file name>
|
||||||
|
#
|
||||||
|
search_item() {
|
||||||
|
local IFS=";" subtype=${1} item=${2}
|
||||||
|
local subdir="appimg-${subtype}s"
|
||||||
|
|
||||||
|
for dir in ${SEARCH_PATH}; do
|
||||||
|
local fullpath=${dir}/${subdir}/${item}
|
||||||
|
if [[ -f ${fullpath} ]]; then
|
||||||
|
printf ${fullpath}
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
fatal "Could not find ${subtype} named '${item}'. Bailing.."
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Execute a module by name. If a function exists with the
|
||||||
|
# requested module name it will be executed, otherwise scripts
|
||||||
|
# with this name are searched for in SEARCH_PATH /appimg-modules
|
||||||
|
# subdirectories.
|
||||||
|
#
|
||||||
|
|
||||||
|
module() {
|
||||||
|
if [[ $(type -t ${1}) == "function" ]]; then
|
||||||
|
local fname=${1}
|
||||||
|
${fname}
|
||||||
|
else
|
||||||
|
local modpath=$(search_item module ${1})
|
||||||
|
source ${modpath}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# See README for more information about this function
|
||||||
|
#
|
||||||
|
install_file() {
|
||||||
|
|
||||||
|
local mode=${1}
|
||||||
|
|
||||||
|
if [[ $# -eq 3 ]]; then
|
||||||
|
# Type (1)
|
||||||
|
# strip trailing / from ${3} if present
|
||||||
|
local target=${3%/}/${2}
|
||||||
|
elif [[ $# -eq 2 ]]; then
|
||||||
|
# Type (2)
|
||||||
|
# accept either /usr/bin/foo or usr/bin/foo
|
||||||
|
# add leading slash if necessary to construct absolute path
|
||||||
|
local target="/${2#/}"
|
||||||
|
else
|
||||||
|
fatal "Bad number of arguments $# to install_file()"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# strip leading slash from ${2} if present
|
||||||
|
local srcpath=$(search_item file ${2#/})
|
||||||
|
local dstdir=$(dirname ${target})
|
||||||
|
/usr/bin/install -d ${dstdir}
|
||||||
|
/usr/bin/install -m ${mode} ${srcpath} ${target}
|
||||||
|
}
|
8
appimg-builder/appimg-modules/write-apt-sources
Normal file
8
appimg-builder/appimg-modules/write-apt-sources
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
info "Writing /etc/apt/sources.list"
|
||||||
|
|
||||||
|
{
|
||||||
|
echo "deb ${DEBIAN_MIRROR} ${DEBIAN_RELEASE} main contrib non-free"
|
||||||
|
echo "deb ${DEBIAN_MIRROR}-security ${DEBIAN_RELEASE}/updates main contrib non-free"
|
||||||
|
echo "deb ${DEBIAN_MIRROR} unstable main"
|
||||||
|
|
||||||
|
} > /etc/apt/sources.list
|
2
appimg-builder/basic-image.conf
Normal file
2
appimg-builder/basic-image.conf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
PACKAGES="man manpages vim-nox iputils-ping tmux vifm gnome-terminal firefox nautilus eog evince unzip x264"
|
||||||
|
|
79
appimg-builder/build-template.conf
Normal file
79
appimg-builder/build-template.conf
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#
|
||||||
|
# Application Image Builder configuration file template
|
||||||
|
#
|
||||||
|
# Synopsis:
|
||||||
|
#
|
||||||
|
# mkdir work && cd work
|
||||||
|
# appimg-builder --new
|
||||||
|
# vim build.conf
|
||||||
|
# sudo appimg-builder build.conf
|
||||||
|
#
|
||||||
|
# Full documentation in /usr/share/appimg-builder/README
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Add space separated list of extra packages to install to PACKAGES.
|
||||||
|
#
|
||||||
|
# If you need full control over the packages installed, you can set
|
||||||
|
# the variable BASE_PACKAGES and it will override the value of this
|
||||||
|
# variable in the main builder.
|
||||||
|
#
|
||||||
|
|
||||||
|
PACKAGES="man manpages vim-nox iputils-ping tmux gnome-terminal firefox nautilus evince unzip x264"
|
||||||
|
|
||||||
|
#
|
||||||
|
# These variables are set to the default values, if you don't want to change them
|
||||||
|
# they can just be deleted. Or you can keep them, the result will be the same.
|
||||||
|
#
|
||||||
|
|
||||||
|
DEBIAN_RELEASE="buster"
|
||||||
|
DEBIAN_MIRROR="https://deb.debian.org/debian"
|
||||||
|
|
||||||
|
#
|
||||||
|
# All the following is about how you can add code to run either
|
||||||
|
# before or after packages are installed.
|
||||||
|
#
|
||||||
|
# If you just want to add some extra packages to install in your image, you don't
|
||||||
|
# need any of this and it can all be deleted.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# PRE_INSTALL_MODULES run before packages are installed
|
||||||
|
#
|
||||||
|
|
||||||
|
PRE_INSTALL_MODULES=""
|
||||||
|
|
||||||
|
#
|
||||||
|
# POST_INSTALL_MODULES run after packages are installed
|
||||||
|
#
|
||||||
|
|
||||||
|
POST_INSTALL_MODULES="example-module another-module"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Writing shell code functions inside your config file is the easiest way to
|
||||||
|
# implement modules, but you can also put module code into a directory of
|
||||||
|
# external files. See README for information about how to do that.
|
||||||
|
#
|
||||||
|
|
||||||
|
example-module() {
|
||||||
|
info "Hello, this is example-module, configuring password-less sudo for user account"
|
||||||
|
# add a sudoers config line
|
||||||
|
echo "user ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/10-no-password-for-user
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# If you add a subdirectory called 'appimg-files' to the
|
||||||
|
# directory containing this build config file and then
|
||||||
|
# add a file 'example.service':
|
||||||
|
#
|
||||||
|
# THISDIR/appimg-files/example.service
|
||||||
|
#
|
||||||
|
# You can then install it by running install_file in a module
|
||||||
|
# like this:
|
||||||
|
#
|
||||||
|
|
||||||
|
another-module() {
|
||||||
|
info "This is another example module"
|
||||||
|
# install_file 0644 example.service /usr/lib/systemd/system
|
||||||
|
# systemctl enable example.service
|
||||||
|
}
|
21
appimg-builder/common.inc
Normal file
21
appimg-builder/common.inc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
: ${DEBIAN_MIRROR:="https://deb.debian.org/debian"}
|
||||||
|
: ${DEBIAN_RELEASE:="buster"}
|
||||||
|
|
||||||
|
BASE_PACKAGES="debootstrap iproute2 less xz-utils sudo dbus libpam-systemd openssh-client packagekit-gtk3-module libcanberra-gtk3-module libpulse0 fonts-roboto-hinted bash-completion"
|
||||||
|
|
||||||
|
BASE_PRE_INSTALL_MODULES="utility-library configure-locale create-user set-hostname no-install-recommends write-apt-sources"
|
||||||
|
|
||||||
|
BASE_POST_INSTALL_MODULES="loginctl-enable-linger install-configure-host0 install-launch-script"
|
||||||
|
|
||||||
|
trap "exit 1" TERM
|
||||||
|
export TOP_PID=$$
|
||||||
|
|
||||||
|
fatal() {
|
||||||
|
>&2 echo "Fatal: ${1}"
|
||||||
|
kill -s TERM $TOP_PID
|
||||||
|
}
|
||||||
|
|
||||||
|
info() {
|
||||||
|
printf "[+] ${1}\n"
|
||||||
|
}
|
237
appimg-builder/stage-one.sh
Executable file
237
appimg-builder/stage-one.sh
Executable file
@ -0,0 +1,237 @@
|
|||||||
|
#!/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 \
|
||||||
|
--exclude=sysv-rc,initscripts,startpar,lsb-base,insserv \
|
||||||
|
${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)
|
||||||
|
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
|
58
appimg-builder/stage-two.sh
Executable file
58
appimg-builder/stage-two.sh
Executable file
@ -0,0 +1,58 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
APPIMG_BUILDER_BASE="/usr/share/appimg-builder"
|
||||||
|
source ${APPIMG_BUILDER_BASE}/common.inc
|
||||||
|
|
||||||
|
if [ "$EUID" -ne 0 ]; then
|
||||||
|
fatal "The stage-two.sh script is not running as root."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
fatal "The stage-two.sh script expects a single argument (configuration file path)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f ${1} ]; then
|
||||||
|
fatal "Configuration file '${1}' does not exist."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# running module 'utility-library' replaces this function with a more powerful version
|
||||||
|
module() {
|
||||||
|
local modpath=${APPIMG_BUILDER_BASE}/appimg-modules/${1}
|
||||||
|
[[ -f ${modpath} ]] || fatal "Could not find module '${1}'"
|
||||||
|
source ${modpath}
|
||||||
|
}
|
||||||
|
|
||||||
|
pre_install_packages() {
|
||||||
|
info "Running pre package install modules"
|
||||||
|
for mod in ${PRE_INSTALL_MODULES}; do
|
||||||
|
module ${mod}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
post_install_packages() {
|
||||||
|
info "Running post package install modules"
|
||||||
|
for mod in ${POST_INSTALL_MODULES}; do
|
||||||
|
module ${mod}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
run_build() {
|
||||||
|
pre_install_packages
|
||||||
|
module install-packages
|
||||||
|
post_install_packages
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# config file imported here
|
||||||
|
source ${1}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Define any of PACKAGES, PRE_INSTALL_MODULES, POST_INSTALL_MODULES in config file
|
||||||
|
# to append to the corresponding BASE list. Also you can override the BASE lists
|
||||||
|
# entirely by setting the variable name in config file.
|
||||||
|
#
|
||||||
|
PACKAGES="${BASE_PACKAGES} ${PACKAGES:-}"
|
||||||
|
PRE_INSTALL_MODULES="${BASE_PRE_INSTALL_MODULES} ${PRE_INSTALL_MODULES:-}"
|
||||||
|
POST_INSTALL_MODULES="${BASE_POST_INSTALL_MODULES} ${POST_INSTALL_MODULES:-}"
|
||||||
|
|
||||||
|
run_build
|
Loading…
Reference in New Issue
Block a user