hassio-build/builder/builder.sh
2017-09-26 11:07:32 +02:00

367 lines
8.6 KiB
Bash
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
######################
# Hass.io Build-env
######################
set -e
#### Variable ####
DOCKER_TIMEOUT=20
DOCKER_PID=-1
DOCKER_HUB=""
DOCKER_CACHE="true"
DOCKER_LATEST="true"
DOCKER_PUSH="true"
GIT_REPOSITORY=""
GIT_BRANCH="master"
TARGET=""
BUILD_LIST=()
BUILD_TYPE="addon"
#### Misc functions ####
function print_help() {
cat << EOF
Hass.io build-env for ecosystem:
docker run --rm homeassistant/build-env:latest [options]
Options:
-h, --help
       Display this help and exit.
Repository / Data handling
-r, --repository <REPOSITORY>
       Set git repository to load data from.
-b, --branch <BRANCH>
       Set git branch for repository.
-t, --target <PATH_TO_BUILD>
Set local folder or path inside repository for build.
Architecture
--armhf
Build for arm.
--amd64
Build for intel/amd 64bit.
--aarch64
Build for arm 64bit.
--i386
Build for intel/amd 32bit.
--all
Build all architecture.
Build handling
--test
Disable push to dockerhub.
--no-latest
Do not tag images as latest.
--no-cache
Disable cache for the build (from latest).
--docker-hub <DOCKER_REPOSITORY>
Set or overwrite the docker repository.
Internals:
--addon
Default on. Run all things for a addon build.
--supervisor
Build a hassio supervisor.
--homeassistant-base
Build a Home-Assistant base image.
--homeassistant-generic
Build the generic release for a Home-Assistant.
--homeassistant
Build the machine based image for a release.
EOF
exit 1
}
#### Docker functions ####
function start_docker() {
local starttime
local endtime
echo "[INFO] Starting docker."
dockerd 2> /dev/null &
DOCKER_PID=$!
echo "[INFO] Waiting for docker to initialize..."
starttime="$(date +%s)"
endtime="$(date +%s)"
until docker info >/dev/null 2>&1; do
if [ $((endtime - starttime)) -le $DOCKER_TIMEOUT ]; then
sleep 1
endtime=$(date +%s)
else
echo "[ERROR] Timeout while waiting for docker to come up"
exit 1
fi
done
echo "[INFO] Docker was initialized"
}
function stop_docker() {
local starttime
local endtime
echo "[INFO] Stopping in container docker..."
if [ "$DOCKER_PID" -gt 0 ] && kill -0 "$DOCKER_PID" 2> /dev/null; then
starttime="$(date +%s)"
endtime="$(date +%s)"
# Now wait for it to die
kill "$DOCKER_PID"
while kill -0 "$DOCKER_PID" 2> /dev/null; do
if [ $((endtime - starttime)) -le $DOCKER_TIMEOUT ]; then
sleep 1
endtime=$(date +%s)
else
echo "[ERROR] Timeout while waiting for container docker to die"
exit 1
fi
done
else
echo "[WARN] Your host might have been left with unreleased resources"
fi
}
function run_build() {
local build_dir=$1
local repository=$2
local image=$3
local version=$4
local build_type=$5
local build_from=$6
local build_arch=$7
local docker_cli=("${!8}")
local push_images=()
echo "[INFO] Run build for $repository/$image:$version"
# Build image
docker build -t "$repository/$image:$version" \
--label "io.hass.version=$version" \
--label "io.hass.type=$build_type" \
--label "io.hass.arch=$build_arch" \
--build-arg "BUILD_FROM=$build_from" \
--build-arg "BUILD_VERSION=$version" \
--build-arg "BUILD_ARCH=$build_arch" \
"${docker_cli[@]}" \
"$build_dir"
push_images+=("$repository/$image:$version")
echo "[INFO] Finish build for $repository/$image:$version"
# Tag latest
if [ "$DOCKER_LATEST" == "true" ]; then
docker tag "$repository/$image:$version" "$repository/$image:latest"
push_images+=("$repository/$image:latest")
fi
# Push images
if [ "$DOCKER_PUSH" == "true" ]; then
for i in "${push_images[@]}"; do
echo "[INFO] Start upload $i"
if docker push "$i" > /dev/null 2>&1; then
echo "[INFO] Upload success"
else
echo "[WARN] Upload fail!"
fi
done
fi
}
#### HassIO functions ####
function build_addon() {
local build_arch=$1
local docker_cli=()
local build_from=""
local version=""
local image=""
local repository=""
local raw_image=""
# Read addon build.json
if [ -f "$TARGET/build.json" ]; then
build_from="$(jq --raw-output ".build_from.$build_arch // empty" "$TARGET/build.json")"
fi
# Set defaults build things
if [ -z "$build_from" ]; then
build_from="homeassistant/$build_arch-base:latest"
fi
# Read addon config.json
version="$(jq --raw-output '.version' "$TARGET/config.json")"
raw_image="$(jq --raw-output '.image // empty' "$TARGET/config.json" | sed -r "s/\{arch\}/$build_arch/g")"
# Image need exists
if [ -z "$raw_image" ]; then
echo "[ERROR] Can't find image data inside config.json"
exit 1
fi
repository="$(echo "$raw_image" | cut -f 1 -d '/')"
image="$(echo "$raw_image" | cut -f 2 -d '/')"
# Overwrite docker hub
if [ ! -z "$DOCKER_HUB" ]; then
repository=$DOCKER_HUB
fi
# Init Cache
if [ "$DOCKER_CACHE" == "true" ]; then
echo "[INFO] Init cache for $repository/$image:$version"
if docker pull "$repository/$image:latest" > /dev/null 2>&1; then
docker_cli+=("--cache-from" "$repository/$image:latest")
else
echo "[WARN] No cache image found. Cache is disabled for build"
fi
fi
# Start build
run_build "$TARGET" "$repository" "$image" "$version" \
"addon" "$build_from" "$build_arch" docker_cli[@]
}
#### initialized cross-build ####
function init_crosscompile() {
echo "[INFO] Setup crosscompiling feature"
mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
update-binfmts --enable qemu-arm
update-binfmts --enable qemu-aarch64
}
function clean_crosscompile() {
if [ -f /proc/sys/fs/binfmt_misc ]; then
umount /proc/sys/fs/binfmt_misc
fi
update-binfmts --disable qemu-arm
update-binfmts --disable qemu-aarch64
}
#### Error handling ####
function error_handling() {
stop_docker
clean_crosscompile
exit 1
}
trap 'error_handling' SIGINT SIGTERM
#### Parse arguments ####
while [[ $# -gt 0 ]]; do
key=$1
case $key in
-h|--help)
print_help
;;
-r|--repository)
GIT_REPOSITORY=$2
shift
;;
-b|--branch)
GIT_BRANCH=$2
shift
;;
-t|--target)
TARGET=$2
shift
;;
--no-latest)
DOCKER_LATEST="false"
;;
--test)
DOCKER_PUSH="false"
;;
--no-cache)
DOCKER_CACHE="false"
;;
--docker-hub)
DOCKER_HUB=$2
shift
;;
--armhf)
BUILD_LIST+=("armhf")
;;
--amd64)
BUILD_LIST+=("amd64")
;;
--i386)
BUILD_LIST+=("i386")
;;
--aarch64)
BUILD_LIST+=("aarch64")
;;
--all)
BUILD_LIST=("armhf" "amd64" "i386" "aarch64")
;;
--addon)
BUILD_TYPE="addon"
;;
--supervisor)
BUILD_TYPE="supervisor"
;;
--homeassistant-base)
BUILD_TYPE="homeassistant-base"
;;
--homeassistant-generic)
BUILD_TYPE="homeassistant-generic"
;;
--homeassistant)
BUILD_TYPE="homeassistant"
;;
*)
echo "[WARN] $0 : Argument '$1' unknown will be Ignoring"
;;
esac
shift
done
# Check if a architecture is available
if [ "${#BUILD_LIST[@]}" -eq 0 ]; then
echo "[ERROR] You need select a architecture for build!"
exit 1
fi
#### Main ####
mkdir -p /data
# Setup docker env
init_crosscompile
start_docker
# Load external repository
if [ ! -z "$GIT_REPOSITORY" ]; then
echo "[INFO] Checkout repository $GIT_REPOSITORY"
git clone --depth 1 --branch "$GIT_BRANCH" "$GIT_REPOSITORY" /data/git 2> /dev/null
TARGET="/data/git/$TARGET"
fi
# Select addon build
if [ "$BUILD_TYPE" == "addon" ]; then
echo "[INFO] Run addon build for: ${BUILD_LIST[*]}"
for arch in "${BUILD_LIST[@]}"; do
(build_addon "$arch") &
done
wait
fi
# Cleanup docker env
clean_crosscompile
stop_docker
exit 0