uci-docker-build/build

317 lines
8.5 KiB
Bash
Executable File

#!/bin/bash
docker_image_build () {
local targets=(dev arm64 amd64 deploy private multi)
local verbose; local log_dir; local no_prompt
local efile
declare OPTION; declare OPTARG; declare OPTIND
BDIR=$(dirname "$(realpath "$BASH_SOURCE")")
export BDIR
# load script library
source $BDIR/lib/load.sh
# check for subcommands first
case "$1" in
try)
shift 1
popd > /dev/null || return 2
try_container "$@"
return $?
;;
image_name)
shift 1
image_name "$@"
return $?
;;
tag)
shift 1
image_tag "$@"
return $?
;;
push)
shift 1
image_push "$@"
return $?
;;
info)
shift 1
[[ $1 == "arch" ]] && { shift 1; image_arch "$@"; return $?; }
[[ $1 == "exists" ]] && { shift 1; image_exists "$@"; return $?; }
[[ $1 == "id" ]] && { shift 1; image_id "$@"; return $?; }
image_info "$@"; return $?
;;
esac
exit_abnormal() { # Function: Exit with error.
usage
return ${1:-1}
}
[[ -z "$PS1" ]] || no_prompt=true
overwrite=true
while getopts 'g:e:b:d:t:ncr:u:plhs:w:akvoi' OPTION; do
# echo processing: option:$OPTION argument:$OPTARG index:$OPTIND remaining:${@:$OPTIND}
case "$OPTION" in
e)
if source_env_file $OPTARG; then efile=true; else return 2; fi
;;
o)
unset overwrite
;;
v)
verbose=true
;;
a)
# automated - script is to be run without prompt (non-interactive)
no_prompt=true
;;
k)
# keep the build scripts in the image, by default they are removed
KEEP=true
;;
w)
# the work directory to put the build scripts in container (default is /opt/build)
BUILD_DIR=$OPTARG
;;
b)
# CUSTOM BASE IMAGE
BASE_IMAGE=$OPTARG
;;
s)
# building source from which to bind into build, default is src/ in current directory
BUILD_SRC=$OPTARG
;;
d)
# LINUX_DISTRO=$OPTARG
LINUX_DISTRO=$OPTARG
;;
l)
# append distro name to image name
append_distro=true
;;
t)
TARGET=$OPTARG
;;
g)
TAG=$OPTARG
;;
u)
RUSER=$OPTARG
;;
c)
try=true
;;
p)
push=true
;;
n)
nocache="--no-cache"
;;
r)
REPO=$OPTARG
;;
h)
exit_abnormal 0
return 0
;;
*)
echo "unknown $0 option -$OPTARG"
exit_abnormal 1
;;
esac
done
shift $((OPTIND - 1))
[[ ! $efile ]] && source_env_file
# processing the build source directory
if [[ ! $BUILD_SRC ]]; then
echo no BUILD_SRC directory specified
echo using present directory $PWD
BUILD_SRC=$PWD
fi
if [[ ! $(isAbsPath $BUILD_SRC) ]] ; then
if [[ ${BUILD_SRC} == "_base_" ]]; then
BUILD_SRC=${BDIR}/src
else
BUILD_SRC=$(realpath ${BUILD_SRC})
fi
fi
if [[ ! ( -d $BUILD_SRC/packages && -d $BUILD_SRC/init ) ]]; then
echo -e "\e[1;31minvalid build source directory"
echo $BUILD_SRC
echo -e "it does not contain packages and init subirectories\e[1;37m"
if [[ ! $(basename $BUILD_SRC) == "src" ]]; then
echo checking in src/ subdirectory for source
if [[ ( -d $BUILD_SRC/src/packages && -d $BUILD_SRC/src/init ) ]]; then
BUILD_SRC=$BUILD_SRC/src
echo found source in src/ subdirectory changing to source directory to
echo $BUILD_SRC
else
echo -e "\e[1;31mERROR: no build source directory at $BUILD_SRC</src>"
echo -e "with init/ and packages/ subdirectores was found\e[1;37m"
if [[ $no_prompt ]] ; then
echo aborting the build...
echo -e "\e[1;31mNOTE: use '_base_' to explicitly use build source in uci-docker-build repo\e[1;37m"
return 2
else
echo "Do you want to use the uci-docker-build repo source scripts"
echo "at $BDIR/src "
read -n 1 -p "instead? [y]=>" REPLY
[[ $REPLY != "y" ]] && echo -e "\n" && return 2
BUILD_SRC=$BDIR/src
echo -e "\n\e[1;31mNOTE: use '_base_' to explicitly use build source in uci-docker-build repo\e[1;37m"
fi
fi
fi
fi
# done processing build source directory
log_dir=$PWD/logs
mkdir -p $log_dir
pushd "$BDIR" > /dev/null || return 3
[[ ! "${targets[@]}" =~ $TARGET ]] && echo $TARGET is not a valid target && echo valid targets are: ${targets[@]} && exit 4
LINUX_DISTRO=${LINUX_DISTRO:-alpine}
if [[ $BASE_IMAGE ]]; then
echo determining DISTRO of base image: $BASE_IMAGE
LINUX_DISTRO=$(docker_image_distro $BASE_IMAGE)
[[ ! $LINUX_DISTRO ]] && echo "unable to get base image OS for: $BASE_IMAGE, aborting build" && return 5
echo $BASE_IMAGE is built from distro $LINUX_DISTRO
else
BASE_IMAGE=$LINUX_DISTRO
fi
if [[ $1 ]]; then
[[ $NAME ]] && echo changing image name from $NAME to $1
NAME=$1
fi
if [[ $2 ]]; then
[[ $RUSER ]] && echo changing image username from $RUSER to $2
RUSER=$2
fi
if [[ $NAME ]]; then
[[ $append_distro ]] && NAME=$NAME-${LINUX_DISTRO}
else
echo no image name supplied using distro name $LINUX_DISTRO
NAME=${LINUX_DISTRO}
fi
IMAGE_NAME=$([[ $RUSER ]] && echo ${RUSER}/)${NAME}
# TODO writing to existing tag untags existing image so write a new tag to that image then continue
# retag existing image and remove former tag
if [[ $(image_exists $IMAGE_NAME) ]]; then
if [[ $overwrite ]]; then
image_delete $IMAGE_NAME
else
newtag=$(date +'%d%H%M%S')
echo image exists retaging $(image_name $IMAGE_NAME) with tag :$newtag
image_tag $IMAGE_NAME $IMAGE_NAME:$newtag
image_tag -r $IMAGE_NAME
fi
fi
# BASE_IMAGE=$([[ $BASE_IMAGE == *:* ]] && echo $BASE_IMAGE || echo $BASE_IMAGE:latest)
#$([[ ! $BASE_IMAGE == *:* ]] && echo :latest)
ARCH=$(get_arch)
export BASE_IMAGE
export TAG
export IMAGE_NAME
export LINUX_DISTRO
export BUILD_DIR
export KEEP
export SYSADMIN_PW
export ARCH
echo -e "\e[1;37m********************"
echo "Using scripts source directory at $BUILD_SRC"
echo "Building with base image: $BASE_IMAGE"
#todo based on target form image names
echo "Outputing to image name => $IMAGE_NAME<-arch>:${TAG:-latest}"
[[ $push || $TARGET == "private" ]] && echo "Will push image to ${REPO:-hub.docker.com}"
[[ $TARGET == "deploy" ]] && echo "Will build and push both amd64 and arm64 images to hub.docker.com"
[[ $TARGET == "dev" || ! $TARGET ]] && echo "Building image for local machine with architecture $ARCH"
echo "Linux Distro: $LINUX_DISTRO"
echo "Using build target: ${TARGET:-default}"
echo "Build Command: docker buildx --builder ${builder} bake ${nocache} ${TARGET}"
if [[ $verbose ]]; then
echo -e "\n---------------------------------"
docker buildx bake --print $TARGET
echo -e "\n---------------------------------"
echo "build scripts at $BUILD_SRC to be copied to ${BUILD_DIR:-/build} in container ***** "
ls -la $BUILD_SRC
echo -e "\n----- base init script init.sh ------"
cat $BUILD_SRC/init.sh
echo -e "\n---------------------------------"
fi
echo -e "u********************\e[0;37m"
if [[ ! $no_prompt ]]; then
read -n 1 -p "do you want to continue [y]=>" REPLY
[[ $REPLY != "y" ]] && echo -e "\n" && return 4
fi
builder=default
if [[ $TARGET == "deploy" ]]; then
builder=deploy
if ! docker buildx ls | grep -q deploy ; then
echo multiarch deploy builder does not exist, creating with docker-container driver
docker buildx create --name deploy --driver docker-container >/dev/null
docker buildx ls | grep deploy
fi
fi
[[ $TARGET == "private" && ! $REPO ]] && echo "must use '-r <private repo>' if building to private repo" && exit 3
# copy source directory to temporary .src/ subdirectory
# MUST either be readable by all or group readable by docker group
rm -rf $BDIR/.src
rsync -aAru ${BUILD_SRC:-src}/ $BDIR/.src
ls -la $BDIR/.src
echo running build command: docker buildx --builder ${builder} bake ${nocache} ${TARGET}
docker buildx --builder ${builder} bake ${nocache} ${TARGET} 2>&1 | tee "$log_dir/${IMAGE_NAME//\//-}build.log"
[[ $? == 0 ]] && echo succcess building image $IMAGE_NAME || exit_abnormal 5
rm -rf $BDIR/.src
popd > /dev/null
if [[ ($try || $TARGET == "dev") ]] && [[ ! $no_prompt ]]; then
echo trying newly built image in a container
try_container -m opt $([[ $TARGET == "deploy" ]] && echo -p) $IMAGE_NAME
fi
if [[ $TARGET == "private" ]]; then
# echo pushing arm64 image $IMAGE_NAME to ${REPO:-docker hub}
image_push -a -r $REPO $IMAGE_NAME
# echo pushing amd image $IMAGE_NAME to ${REPO:-docker hub}
image_push -r $REPO $IMAGE_NAME
else
if [[ $push && (! $TARGET == "dev") ]];then
# echo pushing $IMAGE_NAME to ${REPO:-docker hub}
image_push $([[ $TARGET == "arm" ]] && echo -a) -r $REPO $IMAGE_NAME
fi
fi
}
# if script was executed then call the function
(return 0 2>/dev/null) || docker_image_build $@