Created
February 23, 2014 20:35
-
-
Save jplitza/9176870 to your computer and use it in GitHub Desktop.
gluon autobuild script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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