diff --git a/cobuild/000-setup.sh b/cobuild/000-setup.sh new file mode 100644 index 0000000..ff79dbf --- /dev/null +++ b/cobuild/000-setup.sh @@ -0,0 +1,4 @@ +progress "Installing Hrochobot" + +cd /build/src +pip install . diff --git a/cobuild/010-service.d/hrochobot.service b/cobuild/010-service.d/hrochobot.service new file mode 100644 index 0000000..c36d2c0 --- /dev/null +++ b/cobuild/010-service.d/hrochobot.service @@ -0,0 +1,13 @@ +[Unit] +Description="Hrochobot" +After=network.target + +[Service] +Type=exec +ExecStartPre=mkdir -p /data/etc +ExecStart=/usr/local/bin/hrochobot +Environment=HROCHOBOT_DATA=/data/etc +Environment=HROCHOBOT_LOG=/data/log + +[Install] +WantedBy=multi-user.target diff --git a/cobuild/010-service.d/run.sh b/cobuild/010-service.d/run.sh new file mode 100644 index 0000000..e290eea --- /dev/null +++ b/cobuild/010-service.d/run.sh @@ -0,0 +1,4 @@ +progress "Configuring hrochobot.service" + +install-config hrochobot.service /etc/systemd/system/ +systemctl enable hrochobot diff --git a/cobuild/Dockerfile.top b/cobuild/Dockerfile.top new file mode 100644 index 0000000..6181dd4 --- /dev/null +++ b/cobuild/Dockerfile.top @@ -0,0 +1,4 @@ +FROM docker://registry.ks.matfyz.cz/gimli/base:bullseye +COPY bin /build/src/bin +COPY hrochobot /build/src/hrochobot +COPY setup.py /build/src diff --git a/cobuild/try b/cobuild/try new file mode 100755 index 0000000..2770687 --- /dev/null +++ b/cobuild/try @@ -0,0 +1,6 @@ +#!/bin/bash +set -e +common/build cobuild --tag hrochobot-test +podman rm -if hrochobot-test +podman create --name hrochobot-test --hostname hrochobot-test hrochobot-test +podman start hrochobot-test diff --git a/common/build b/common/build new file mode 100755 index 0000000..4dadae1 --- /dev/null +++ b/common/build @@ -0,0 +1,73 @@ +#!/bin/bash +set -euo pipefail + +gen-docker-file () +{ + if [ -f $src/Dockerfile.top ] ; then + cat $src/Dockerfile.top + fi + + echo "COPY common /build/common" + + for stage in $(cd $src && echo [0-9]*.[a-z]*) ; do + case $stage in + *.docker) + cat $src/$stage + ;; + *.d|*.sh) + echo "COPY $src/$stage /build/$stage" + echo "RUN /build/common/run $stage" + ;; + *) + echo >&2 "ERROR: Unrecognized build stage name $stage" + exit 1 + ;; + esac + done + + if [ -f $src/Dockerfile.bottom ] ; then + cat $src/Dockerfile.bottom + fi + + echo "RUN rm -rf /build /data" +} + +if [ $# = 0 ] ; then + echo >&2 "Usage: $0 []" + exit 1 +fi + +src=$1 +shift + +if [ ! -v http_proxy ] ; then + PROXY= + eval "$(apt-config shell PROXY Acquire::http::proxy)" + if [ -n "$PROXY" ] ; then + export http_proxy=$PROXY + fi +fi + +if [ -v http_proxy -a ! -v https_proxy ] ; then + export https_proxy=$http_proxy +fi + +CACHE_DIR=${XDG_CACHE_HOME:-$HOME/.cache}/container-build +if [ -d $CACHE_DIR ] ; then + echo "Using cache $CACHE_DIR" +else + echo "Creating cache $CACHE_DIR" + mkdir -p $CACHE_DIR +fi +mkdir -p $CACHE_DIR/download + +gen-docker-file | podman build \ + --file - \ + --layers \ + --http-proxy \ + --volume=$CACHE_DIR:/root/.cache \ + "$@" \ + . + +echo -n "Cache usage: " +du -sh $CACHE_DIR | cut -d ' ' -f1 diff --git a/common/lib.sh b/common/lib.sh new file mode 100644 index 0000000..bee120d --- /dev/null +++ b/common/lib.sh @@ -0,0 +1,152 @@ +C_RED="$(echo -e '\e[31m')" +C_GREEN="$(echo -e '\e[32m')" +C_YELLOW="$(echo -e '\e[33m')" +C_NORMAL="$(echo -e '\e[0m')" + +export DEBIAN_FRONTEND=noninteractive +B_APT_UPDATED= + +progress () +{ + echo "${C_GREEN}$1${C_NORMAL}" >&2 +} + +note () +{ + echo "${C_YELLOW}$1${C_NORMAL}" >&2 +} + +warn () +{ + echo "${C_RED}WARNING: $1${C_NORMAL}" >&2 +} + +die () +{ + echo "${C_RED}ERROR: $1${C_NORMAL}" >&2 + exit 1 +} + +update-pkgs () +{ + if [ -z "$B_APT_UPDATED" ] ; then + apt update + B_APT_UPDATED=1 + fi +} + +install-pkgs () +{ + update-pkgs + apt install -y --no-install-recommends --no-install-suggests "$@" +} + +install-config () +{ + [ $# = 2 ] || die "Usage: install-config ( | /)" + local S=$1 + local T=$2 + if [ ${T%/} != $T ] ; then + T=$T$(basename $S) + fi + local B=$BUILD_CONFIG$T + mkdir -p $(dirname $B) $(dirname $T) + if [ -f $T ] ; then + if [ ! -f $B.orig ] ; then + echo "Backing up $T to $B.orig" + cp $T $B.orig + else + echo "Backup of $T already present in $B.orig" + fi + fi + if [ -f $S ] ; then + # Just a new file: overwrite + echo "Overwriting $T" + cp $S $T + cp $S $B.new + elif [ -f $S.orig -a -f $S.new ] ; then + # Try 3-way merge + if cmp --quiet $S.new $T ; then + warn "Skipping merge of $T: changes already present" + else + echo "Merging $T" + if diff3 -m $S.new $S.orig $T >$B.new ; then + cp $B.new $T + else + die "Merge failed, please review $B.new" + fi + fi + else + die "Do not know how to install config $T" + fi +} + +sed-config () +{ + [ $# = 2 ] || die "Usage: sed-config " + local T=$1 + local SCRIPT=$2 + local B=$BUILD_CONFIG$T + mkdir -p $(dirname $B) + [ -f $T ] || die "Want to sed $T, but it is missing" + if [ ! -f $B.orig ] ; then + echo "Backing up $T to $B.orig" + cp $T $B.orig + else + echo "Backup of $T already present in $B.orig" + fi + sed -ri "$SCRIPT" $T + cp $T $B.new +} + +pipe-config () +{ + [ $# = 1 ] || die "Usage: | pipe-config " + local TMP=$(mktemp) + cat >$TMP + install-config $TMP $1 + rm $TMP +} + +rm-config () +{ + [ $# = 1 ] || die "Usage: rm-config " + local T=$1 + local B=$BUILD_CONFIG$T + if [ -f $T ] ; then + if [ ! -f $B.orig ] ; then + echo "Backing up $T to $B.orig" + cp $T $B.orig + fi + echo "Removing $T" + rm -f $T + else + echo "Wanted to remove $T, but it does not exist" + fi +} + +download () +{ + [ $# = 3 ] || die "Usage: download " + local URL=$1 + local HTYPE=$2 + local HASH=$3 + local DEST=$(basename $URL) + local CACHE=/root/.cache/download + if [ -d $CACHE ] ; then + if [ -f $CACHE/$DEST ] ; then + echo "Using cached $DEST" + else + echo "Downloading $URL with caching" + curl $URL >$CACHE/$DEST.tmp + mv $CACHE/$DEST.tmp $CACHE/$DEST + fi + ln -s $CACHE/$DEST . + else + warn "Cache $CACHE not found: downloading directly" + echo "Downloading $URL" + curl $URL >$DEST + fi + local H=$(${HTYPE}sum $DEST | cut -d' ' -f1) + [ $H == $HASH ] || die "Mismatched hash: got $H, want $HASH" +} diff --git a/common/run b/common/run new file mode 100755 index 0000000..7a9b355 --- /dev/null +++ b/common/run @@ -0,0 +1,50 @@ +#!/bin/bash +set -euo pipefail + +if [ $# != 1 ] ; then + echo >&2 "Usage: $0 " + exit 1 +fi + +STAGE=$1 + +STAGE=/build/$STAGE +BUILD_COMMON=/build/common +BUILD_CONFIG=/build/config-tmp +. $BUILD_COMMON/lib.sh + +note "Running $STAGE" + +if [ ! -v http_proxy -o ! -v https_proxy ] ; then + warn "No HTTP(S) proxy is set" +fi + +case "$STAGE" in + *.sh) + . $STAGE + exit 0 + ;; + *.d) + ;; + *) + die "Unrecognized stage name $STAGE" +esac + +cd $STAGE + +if [ -f run.sh ] ; then + . run.sh +else + for a in [0-9]* ; do + case "$a" in + *.sh) + ( . $a ) + ;; + *.d) + ( cd $a && . run.sh ) + ;; + *) + warn "Unrecognized build step file $a" + esac + done +fi