Skip to content

Instantly share code, notes, and snippets.

@jplitza
Created February 23, 2014 20:35
Show Gist options
  • Save jplitza/9176870 to your computer and use it in GitHub Desktop.
Save jplitza/9176870 to your computer and use it in GitHub Desktop.
gluon autobuild script
#!/bin/sh
set -e
# functions
usage() {
cat <<EOF
Automatically builds gluon images from the latest versions of the repositories.
Usage: SITEURL=git://url/site.git $(dirname $0)
This script uses environment variables to set various mostly optional
parameters. These include:
SITEURL The only MANDATORY variable which specifies the URL to the site
config repository.
SITEREF The git ref to use from the site repository. Defaults to
"master".
URL URL to the main gluon git repository. Defaults to the original
repository, but you may wish to use a fork or something...
REF The git ref to use from the main gluon repository. Defaults to
"master".
RUNDIR The directory where persistent state of build is kept, such as
the final images, manifests, indications which build processes
failed etc. Defaults to "."
WORKDIR The directory where the build will take place. If specified it
must already exist and have the main gluon and the site
repository checked out. These will only be updated then to save
ressources and shorten the build process, and only if there are
no uncommitted changes.
If not specified, a random directory in /tmp is created and
deleted afterwards.
RSYNC An rsync target to which the final builds will be synced if the
build was successful. If not specified, no rsync takes place.
KEYFILE The path to an ecdsa keyfile that will be used to automatically
sign the manifest. If not specified, no signing takes place.
EOF
}
fail() {
cd "$RUNDIR"
local MSG="failed: $(date "+%Y-%m-%d %H:%M:%S"): $@"
echo "$MSG"
if [ -d "$RUNDIR" ] && [ -n "$BUILDID" ]; then
echo "$MSG" >> "$RUNDIR/$BUILDID.failed"
fi
cleanup
exit 1
}
cleanup() {
# we don't want to accidentally abort in cleanup phase
set +e
trap - INT TERM EXIT PIPE
# remove WORKDIR only if it is in /tmp
[ -d "$WORKDIR" -a "${WORKDIR#/tmp/}" != "$WORKDIR" ] && rm -rf "$WORKDIR"
[ -n "$LOCKPID" ] && kill "$LOCKPID"
[ -n "$CHECKID" ] && lockfile-remove "$RUNDIR/$CHECKID"
[ -n "$BUILDID" -a "$BUILDID" != "$CHECKID" ] && lockfile-remove "$RUNDIR/$BUILDID"
}
git_is_clean() {
# The tree must be really really clean.
if ! git update-index --ignore-submodules --refresh > /dev/null; then
fail "cannot pull: you have unstaged changes\n$(git diff-files --name-status -r --ignore-submodules --)"
fi
diff=$(git diff-index --cached --name-status -r --ignore-submodules HEAD --)
case "$diff" in
?*)
fail "cannot pull: your index contains uncommitted changes\n$diff"
;;
esac
}
remote_git_id() {
git ls-remote "$1" "$2" | head -n4 | cut -f1 | head -c10
}
if [ "$1" = "-h" -o "$1" = "--help" ]; then
usage
exit 0
fi
[ -z "$URL" ] && URL="git://github.com/freifunk-gluon/gluon.git"
[ -z "$REF" ] && REF="master"
[ -z "$SITEREF" ] && SITEREF="master"
[ -z "$RUNDIR" ] && RUNDIR="$PWD"
if [ -z "$SITEURL" ]; then
echo "\$SITEURL unset!"
usage
exit 1
fi
trap fail INT TERM EXIT PIPE
[ -d "$RUNDIR" ] || mkdir -p "$RUNDIR"
cd "$RUNDIR"
# get last commit id
CHECKID="$(remote_git_id "$URL" "$REF")-$(remote_git_id "$SITEURL" "$SITEREF")"
# dont start if...
[ -z "$CHECKID" ] && fail "Couldn't determine last commit id"
[ -f "$CHECKID.success" ] && exit 0
[ -f "$CHECKID.failed" ] && fail "Another build process for this commit already failed"
lockfile-check "$CHECKID" && fail "Another build process is already running"
# try to get lock
lockfile-create "$CHECKID"
lockfile-touch "$CHECKID" &
LOCKPID="$!"
# prepare environment
[ -d "$WORKDIR" ] || WORKDIR=$(mktemp -d) || exit 1
if [ -d "$WORKDIR/.git" ]; then
# WORKDIR already is git repo, pull instead of clone
cd "$WORKDIR"
git_is_clean
git pull --quiet "$URL" "$REF" || fail "git pull"
else
# checkout requested ref
git clone --quiet --branch "$REF" "$URL" "$WORKDIR" || fail "git clone"
cd "$WORKDIR"
fi
BUILDID=$(git rev-parse HEAD | head -c10)
if [ -d "$WORKDIR/site/.git" ]; then
# site config already is a git repo, pull instead of clone
# double cd is ugly, but git pull doesn't support GIT_DIR and GIT_WORK_TREE
cd site/
git_is_clean
git pull --quiet "$SITEURL" "$SITEREF" || fail "git pull site"
cd ../
else
# get site config
git clone --quiet --branch "$SITEREF" "$SITEURL" site || fail "git clone site"
fi
BUILDID="$BUILDID-$(git --git-dir=site/.git/ rev-parse HEAD | head -c10)"
# if someone committed between check and cloning update ID and lock
if [ "$BUILDID" != "$CHECKID" ]; then
OLD_LOCKPID="$LOCKPID"
lockfile-create "$RUNDIR/$BUILDID"
lockfile-touch "$RUNDIR/$BUILDID" &
LOCKPID="$1"
kill "$OLD_LOCKPID"
lockfile-remove "$RUNDIR/$CHECKID"
fi
# build!
make update
make GLUON_BRANCH=nightly
make manifest GLUON_BRANCH=nightly
# generate manifest
cd images/sysupgrade/
mv nightly.manifest manifest
if [ -n "$KEYFILE" ]; then
SIGNATURE="$(ecdsasign manifest < "$KEYFILE")"
echo "---" >> manifest
echo "$SIGNATURE" >> manifest
else
echo "---" >> manifest
fi
# upload images and checksums
if [ -n "$RSYNC" ]; then
rsync -av --del "$WORKDIR/images/sysupgrade/" "$RSYNC" || fail "rsync"
fi
# exit cleanly, no error occured
touch "$RUNDIR/$BUILDID.success"
trap cleanup INT TERM EXIT PIPE
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment