#!/bin/bash udbuild () { local targets=(dev arm64 amd64 publish multi default) local log_dir; local no_prompt; local packages; local befile declare -A dimage; declare -A dinstall; declare -A dupdate declare OPTION; declare OPTARG; declare OPTIND BDIR=$(dirname "$(realpath "$BASH_SOURCE")") export BDIR # load script library source $BDIR/lib/load.sh BUILD_EFILE="" # check for subcommands first case "$1" in try) shift 1; try_container "$@"; return $? ;; env_file) shift 1 befile=$(echo -- "$@" | grep -oP -- '(?<=-e )[^ ]*') env_file ${befile:-$BUILD_EFILE} ; return $? ;; lib) shift 1 echo $BDIR/lib/build.lib return 0 ;; build_src) shift 1 befile=$(echo -- "$@" | grep -oP -- '(?<=-e )[^ ]*') befile=${befile:-$BUILD_EFILE} if befile=$(env_file $befile); then [[ $befile ]] && source_env_file $befile get_build_src return $? else return 3 fi ;; help) ;& --help) ;& -help) shift 1; usage "$@"; return $? ;; source) type udbuild; return $? ;; image) shift 1 case "$1" in name) shift 1; image_name "$@" ;; tag) shift 1; image_tag "$@" ;; push) shift 1; image_push "$@" ;; delete) shift 1; image_delete "$@" ;; exists) shift 1; image_exists "$@" ;; info) shift 1 case "$1" in arch) shift 1; image_arch "$@" ;; tags) shift 1; image_tags "$@" ;; id) shift 1; image_id "$@" ;; * ) image_info "$@" esac ;; *) echo no image subcommand $1 ;; esac return $? ;; esac [[ -z "$PS1" ]] || no_prompt=true overwrite=true while getopts 'ya:b:c:d:e:f:g:hi:lnopr:s:t:u:v:j:' OPTION; do # echo processing: option:$OPTION argument:$OPTARG index:$OPTIND remaining:${@:$OPTIND} case "$OPTION" in a) APPEND_BUILD_ENV=$OPTARG ;; b) # CUSTOM BASE IMAGE BASE_IMAGE=$OPTARG ;; y) # CUSTOM BASE IMAGE BASE_IMAGE_COPY=true ;; c) TRY_CMD=$OPTARG ;; d) # LINUX_DISTRO=$OPTARG LINUX_DISTRO=$OPTARG ;; e) BUILD_EFILE=$OPTARG if ! source_env_file $BUILD_EFILE; then return 2; fi ;; f) REBUILD=$OPTARG ;; g) TAG=$OPTARG ;; h) usage return 0 ;; i) IMAGE_INFO=$OPTARG ;; o) unset overwrite ;; v) VOLUME=$OPTARG ;; j) VERBOSE=$OPTARG ;; l) # append distro name to image name APPEND_DISTRO=true ;; n) nocache="--no-cache" ;; p) echo "build script will be run WITHOUT user prompts (i.e. non-interactive)" no_prompt=true ;; r) REPO=$OPTARG ;; s) # building source from which to bind into build, default is src/ in current directory BUILD_SRC=$OPTARG ;; t) TARGET=$OPTARG ;; u) RUSER=$OPTARG ;; *) echo "unknown $0 option -$OPTARG" usage return 1 ;; esac done shift $((OPTIND - 1)) [[ ! $BUILD_EFILE ]] && source_env_file if ! get_build_src > /dev/null ; then if [[ $no_prompt ]] ; then echo aborting the build... echo -e "\e[1;31mNOTE: use '_core_' to explicitly build with only the UCI core repo\e[1;37m" return 2 else echo "Do you want to build with only the UCI core" read -n 1 -p "instead? [y]=>" REPLY [[ $REPLY != "y" ]] && echo -e "\n" && return 2 BUILD_SRC="_core_" echo -e "\n\e[1;31mNOTE: use '_core_' to explicitly build with only the UCI core\e[1;37m" fi fi TARGET=${TARGET:-default} [[ ! "${targets[@]}" =~ $TARGET ]] && echo $TARGET is not a valid target && echo valid targets are: ${targets[@]} && exit 4 LINUX_DISTRO=${LINUX_DISTRO:-alpine} if ! get_base_image; then return $?; 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) log_dir=$PWD/logs mkdir -p $log_dir [[ $TARGET == "dev" ]] && VERBOSE=true export BASE_IMAGE export TAG export IMAGE_NAME export LINUX_DISTRO export BUILD_SRC export ARCH export VERBOSE export REBUILD build_info if [[ ! $no_prompt ]]; then read -n 1 -p "do you want to continue [y]=>" REPLY [[ $REPLY != "y" ]] && echo -e "\n" && return 4 fi # cat $BDIR/Dockerfile | grep -b5 -a5 ENTRY # return builder=default if [[ $TARGET == "publish" ]]; then builder=publish pushd "$BDIR" > /dev/null || return 3 if ! docker buildx ls | grep -q publish ; then echo publish builder does not exist, creating with docker-container driver docker buildx create --name publish --driver docker-container >/dev/null docker buildx ls | grep publish fi popd > /dev/null || return 4 fi # make a copy of build source locally in build directory if [[ ! $BUILD_SRC = "_core_" ]]; then # copy or bind build source directory to temporary .src/ subdirectory in build repo _env_dir=rootfs/opt/env [[ -d $BDIR/.src ]] && rm -rf $BDIR/.src [[ -d $BDIR/core/$_env_dir ]] && rm -rf $BDIR/core/$_env_dir if [[ $(which rsync 2> /dev/null ) ]]; then rsync -aAru ${BUILD_SRC:-src}/ $BDIR/.src rsync -aAru $BDIR/.src/$_env_dir/ $BDIR/core/$_env_dir > /dev/null 2>&1 else echo no rsync copying with cp /bin/cp -a ${BUILD_SRC:-src}/. $BDIR/.src > /dev/null 2>&1 /bin/cp -a $BDIR/.src/rootfs/opt/env/. $BDIR/core/rootfs/opt/env > /dev/null 2>&1 fi ls -la $BDIR/.src/rootfs ls -la $BDIR/.src/rootfs/root fi echo run environment directory copied to core at $BDIR/core/$_env_dir ls -la $BDIR/core/$_env_dir # create Dockerfile from template if ! source $BDIR/Dockerfile.d/create; then echo unable to create Dockerfile from template, aborting build return 3 fi if [[ -f $APPEND_BUILD_ENV ]]; then if [[ ! $BUILD_SRC = "_core_" ]]; then echo "------ Including custom build environment at $APPEND_BUILD_ENV -------" cat $APPEND_BUILD_ENV echo -e "\n--------------------" echo | tee -a "$BDIR/.src/init/build.env" > /dev/null tee -a "$BDIR/.src/init/build.env" > /dev/null < "$APPEND_BUILD_ENV" fi cat "$APPEND_BUILD_ENV" > "$BDIR/core/build.env" # run in subshell to not affect $USER /bin/bash <<"EOF" unset USER source "$BDIR/core/build.env" [[ $USER_PW ]] && USER=${USER:-sysadmin} if [[ $USER ]]; then if [[ -f $PWD/$USER-permits ]]; then echo sudo permits file: \'$USER-permits\' added to core build /bin/cp -f $PWD/$USER-permits $BDIR/core fi fi EOF fi [[ -f $BDIR/.src/custom-core.sh ]] && /bin/cp $BDIR/.src/custom-core.sh $BDIR/core/ pushd "$BDIR" > /dev/null || return 3 export BUILDING=true echo -e "\n\e[1;31m######### RUNNING THE DOCKER BUILD COMMAND ######################" echo running build command: docker buildx --builder ${builder} bake ${nocache} ${TARGET} echo -e "#################################################################\e[1;37m" 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 popd > /dev/null || return 4 # cleanup echo cleaning up.. rm -rf $BDIR/.src $BDIR/core/build.env $BDIR/core/custom-core.sh $BDIR/core/*-permits > /dev/null 2<&1 echo done cleaning # try in container if [[ ($TRY_CMD || $TARGET == "dev") ]]; then echo trying newly built image in a container echo name before try $IMAGE_NAME try_container build -m opt $([[ $TARGET == "publish" ]] && echo -p) ${TRY_CMD:-shell} 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 fi } # if script was executed then call the function (return 0 2>/dev/null) || udbuild "$@"