#!/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 # type try_container 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:avo' 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 ;; 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" 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 IMAGE_NAME=$(make_image_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 ARCH=$(get_arch) export BASE_IMAGE export TAG export IMAGE_NAME export LINUX_DISTRO export BUILD_SRC 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 ' 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 $@