#!/bin/sh # apk add \ # abuild apk-tools alpine-conf busybox fakeroot syslinux xorriso cmd:mksquashfs # (for efi:) mtools grub-efi # FIXME: clean workdir out of unneeded sections # FIXME: --release: cp/mv images to REPODIR/$ARCH/releases/ # FIXME: --update-latest: rewrite latest-releases.yaml with this build set -e # get abuild configurables [ -e /usr/share/abuild/functions.sh ] || (echo "abuild not found" ; exit 1) . /usr/share/abuild/functions.sh scriptdir="$(dirname "$0")" git=$(command -v git) || git=true # deduce aports directory [ -n "$APORTS" ] || APORTS=$(realpath "$scriptdir/../") [ -e "$APORTS/main/build-base" ] || die "Unable to deduce aports base checkout" # echo '-dirty' if git is not clean git_dirty() { [ $($git status -s -- "$scriptdir" | wc -l) -ne 0 ] && echo "-dirty" } # echo last commit hash id git_last_commit() { $git log --format=oneline -n 1 -- "$scriptdir" | awk '{print $1}' } # date of last commit git_last_commit_epoch() { $git log -1 --format=%cd --date=unix "$1" -- "$scriptdir" } set_source_date() { # dont error out if we're not in git if ! $git rev-parse --show-toplevel >/dev/null 2>&1; then git=true fi # set time stamp for reproducible builds if [ -z "$ABUILD_LAST_COMMIT" ]; then export ABUILD_LAST_COMMIT="$(git_last_commit)$(git_dirty)" fi if [ -z "$SOURCE_DATE_EPOCH" ] && [ "${ABUILD_LAST_COMMIT%-dirty}" = "$ABUILD_LAST_COMMIT" ]; then SOURCE_DATE_EPOCH=$(git_last_commit_epoch "$ABUILD_LAST_COMMIT") fi if [ -z "$SOURCE_DATE_EPOCH" ]; then SOURCE_DATE_EPOCH=$(date -u "+%s") fi export SOURCE_DATE_EPOCH } set_source_date # all_sections="" all_profiles="" all_checksums="sha256 sha512" all_arches="aarch64 armhf armv7 riscv64 x86 x86_64" all_dirs="" build_date="$(date -u +%y%m%d -d "@$SOURCE_DATE_EPOCH")" default_arch="$(apk --print-arch)" _hostkeys="" _simulate="" _checksum="" OUTDIR="$PWD" RELEASE="${build_date}" msg() { if [ -n "$quiet" ]; then return 0; fi local prompt="$GREEN>>>${NORMAL}" local name="${BLUE}mkimage${ARCH+-$ARCH}${NORMAL}" printf "${prompt} ${name}: %s\n" "$1" >&2 } list_has() { local needle="$1" local i shift for i in $@; do [ "$needle" != "$i" ] || return 0 done return 1 } usage() { cat < $section $args" if [ -z "$_simulate" ]; then rm -rf "$DESTDIR" mkdir -p "$DESTDIR" if build_${section} "$@"; then mv "$DESTDIR" "$WORKDIR/${_dir}" _dirty="yes" else rm -rf "$DESTDIR" _fail="yes" return 1 fi fi fi unset DESTDIR all_dirs="$all_dirs $_dir" _my_sections="$_my_sections $_dir" } build_profile() { local _id _dir _spec _my_sections="" _dirty="no" _fail="no" profile_$PROFILE list_has $ARCH $arch || return 0 msg "Building $PROFILE" # Collect list of needed sections, and make sure they are built for SECTION in $all_sections; do section_$SECTION || return 1 done [ "$_fail" = "no" ] || return 1 # Defaults [ -n "$image_name" ] || image_name="alpine-${PROFILE}" [ -n "$output_filename" ] || output_filename="${image_name}-${RELEASE}-${ARCH}.${image_ext}" local output_file="${OUTDIR:-.}/$output_filename" # Construct final image local _imgid=$(echo -n $_my_sections | sort | checksum) DESTDIR=$WORKDIR/image-$_imgid-$ARCH-$PROFILE if [ "$_dirty" = "yes" -o ! -e "$DESTDIR" ]; then msg "Creating $output_filename" if [ -z "$_simulate" ]; then # Merge sections rm -rf "$DESTDIR" mkdir -p "$DESTDIR" for _dir in $_my_sections; do for _fn in $WORKDIR/$_dir/*; do [ ! -e "$_fn" ] || cp -Lrs $_fn $DESTDIR/ done done echo "${image_name}-${RELEASE} ${build_date}" > "$DESTDIR"/.alpine-release fi fi if [ "$_dirty" = "yes" -o ! -e "$output_file" ]; then # Create image [ -n "$output_format" ] || output_format="${image_ext//[:\.]/}" create_image_${output_format} || { _fail="yes"; false; } if [ "$_checksum" = "yes" ]; then for _c in $all_checksums; do echo "$(${_c}sum "$output_file" | cut -d' ' -f1) ${output_filename}" > "${output_file}.${_c}" done fi fi if [ -n "$_yaml_out" ]; then $mkimage_yaml --release $RELEASE \ --title "$title" \ --desc "$desc" \ "$output_file" >> "$_yaml_out" fi } # load plugins load_plugins "$scriptdir" [ -z "$HOME" ] || load_plugins "$HOME/.mkimage" mkimage_yaml="$(dirname $0)"/mkimage-yaml.sh # parse parameters while [ $# -gt 0 ]; do opt="$1" shift case "$opt" in --repository) if [ -z "$REPOS" ]; then REPOS="$1" else REPOS=$(printf '%s\n%s' "$REPOS" "$1"); fi shift ;; --extra-repository) EXTRAREPOS="$EXTRAREPOS $1"; shift ;; --workdir) WORKDIR="$1"; shift ;; --outdir) OUTDIR="$1"; shift ;; --tag) RELEASE="$1"; shift ;; --arch) req_arch="$1"; shift ;; --profile) req_profiles="$1"; shift ;; --hostkeys) _hostkeys="--hostkeys";; --simulate) _simulate="yes";; --checksum) _checksum="yes";; --yaml) _yaml="yes";; --help) usage; exit 0;; --) break ;; -*) usage; exit 1;; esac done if [ -z "$RELEASE" ]; then if git describe --exact-match >/dev/null 2>&1; then RELEASE=$(git describe --always) RELEASE=${RELEASE#v} else RELEASE="${build_date}" fi fi if [ -z "$REPOS" ]; then echo "Must provide --repository" exit 2 fi # setup defaults if [ -z "$WORKDIR" ]; then WORKDIR="$(mktemp -d -t mkimage.XXXXXX)" trap 'rm -rf $WORKDIR' INT EXIT fi req_profiles=${req_profiles:-${all_profiles}} req_arch=${req_arch:-${default_arch}} [ "$req_arch" != "all" ] || req_arch="${all_arch}" [ "$req_profiles" != "all" ] || req_profiles="${all_profiles}" mkdir -p "$OUTDIR" # get abuild pubkey used to sign the apkindex # we need inject this to the initramfs or we will not be able to use the # boot repository if [ -z "$_hostkeys" ]; then _pub=${PACKAGER_PRIVKEY:+${PACKAGER_PRIVKEY}.pub} _abuild_pubkey="${PACKAGER_PUBKEY:-$_pub}" fi # create images for ARCH in $req_arch; do APKROOT="$WORKDIR/apkroot-$ARCH" if [ ! -e "$APKROOT" ]; then # create root for caching packages mkdir -p "$APKROOT/etc/apk/cache" cp -Pr /etc/apk/keys "$APKROOT/etc/apk/" apk --arch "$ARCH" --root "$APKROOT" add --initdb echo "$REPOS" > "$APKROOT/etc/apk/repositories" for repo in $EXTRAREPOS; do echo "$repo" >> "$APKROOT/etc/apk/repositories" done fi apk update --root "$APKROOT" if [ "$_yaml" = "yes" ]; then _yaml_out=${OUTDIR:-.}/latest-releases.yaml echo "---" > "$_yaml_out" fi for PROFILE in $req_profiles; do (build_profile) || exit 1 done done echo "Images generated in $OUTDIR"