2023-03-27 11:07:25 -07:00
|
|
|
#!/bin/bash
|
|
|
|
|
2023-04-14 21:27:40 -07:00
|
|
|
quiet () {
|
|
|
|
if [[ $VERBOSE ]]; then $@; fi
|
|
|
|
}
|
|
|
|
|
2023-04-01 07:17:43 -07:00
|
|
|
get_arch () {
|
|
|
|
local arch="$(uname -m)"
|
|
|
|
case "$arch" in
|
|
|
|
x86_64) arch='amd64' ;;
|
|
|
|
armhf) arch='armv6' ;;
|
|
|
|
armv7) arch='armv7' ;;
|
|
|
|
aarch64) arch='arm64' ;;
|
|
|
|
ppc64el|ppc64le) arch='ppc64le' ;;
|
|
|
|
s390x) arch='s390x';;
|
|
|
|
*) return 1 ;;\
|
|
|
|
esac;
|
|
|
|
echo $arch
|
|
|
|
}
|
|
|
|
|
2023-03-27 11:07:25 -07:00
|
|
|
isAbsPath() {
|
|
|
|
if [[ "${1:0:1}" == / || "${1:0:2}" == ~[/a-z] ]]
|
|
|
|
then
|
|
|
|
echo "true"
|
|
|
|
return 0
|
|
|
|
else
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
sed_ignore_comments () {
|
|
|
|
cmd="sed -r 'h;s/[^#]*//1;x;s/#.*//;${1};G;s/(.*)\n/\1/'"
|
|
|
|
if (( $# == 2 )) ; then
|
|
|
|
eval $cmd <<< "$2"
|
|
|
|
else
|
|
|
|
eval $cmd < /dev/stdin
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
clean_env_file () {
|
2023-04-14 21:27:40 -07:00
|
|
|
local compact; local lines
|
2023-03-27 11:07:25 -07:00
|
|
|
# -c will also remove comments and all empty lines
|
|
|
|
[[ $1 == "-c" ]] && compact=true && shift 1
|
|
|
|
#
|
|
|
|
# remove trailing spaces | remove double quotes
|
|
|
|
# | remove blanks after equals and quote value | remove any spaces before afer =
|
|
|
|
# remove blank lines | remove comment lines if requested
|
2023-04-14 21:27:40 -07:00
|
|
|
[[ -f $1 ]] && lines=$(<$1) || lines="$1"
|
|
|
|
echo "$lines" | sed_ignore_comments s/\\s*$//g | sed_ignore_comments s/\"//g \
|
2023-03-27 11:07:25 -07:00
|
|
|
| sed_ignore_comments s/\(=[[:blank:]]*\)\(.*\)/\\1\"\\2\"/ \
|
|
|
|
| sed_ignore_comments s/\\s*=\\s*/=/g \
|
|
|
|
| sed -rz 's/^\n+//; s/\n+$/\n/g' | if [[ $compact ]]; then grep -v '^#' | grep -v "^$" ; else cat; fi
|
|
|
|
}
|
|
|
|
|
|
|
|
env_file () {
|
2024-01-29 15:16:15 -08:00
|
|
|
local efile
|
|
|
|
efile=$(echo -- "$@" | grep -oP -- '(?<=-e )[^ ]*')
|
|
|
|
if [[ ! $efile ]]; then
|
|
|
|
[[ ! "$1" == *-* ]] && efile=${1:-.env}
|
|
|
|
fi
|
|
|
|
[[ -f "$(realpath "${efile}.env" 2> /dev/null)" ]] && { echo "${efile}.env"; return 0; } # || echo not ${efile}.env
|
|
|
|
[[ -f "$(realpath "${efile}/.env" 2> /dev/null)" ]] && { echo "${efile}/.env"; return 0; } # || echo not ${efile}/.env
|
|
|
|
[[ "${efile##*.}" == "env" ]] && [[ -f "$(realpath "${efile}" 2> /dev/null)" ]] && { echo $efile; return 0; } # || echo not $env
|
2023-03-27 11:07:25 -07:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
read_env_file() {
|
2023-04-03 14:14:17 -07:00
|
|
|
local evar
|
2023-03-27 11:07:25 -07:00
|
|
|
while read line; do
|
|
|
|
evar=$(echo $line | cut -d '=' -f1)
|
2023-04-22 09:21:50 -07:00
|
|
|
if [[ $(echo $(c() { echo $#; }; c $line)) -gt 1 ]];then
|
|
|
|
echo the environment file: $1
|
|
|
|
echo has a format error on this line
|
|
|
|
echo "--------------"
|
|
|
|
echo $line
|
|
|
|
echo "--------------"
|
|
|
|
echo you must correct this before the build can continue
|
|
|
|
return 1
|
|
|
|
fi
|
2023-03-27 11:07:25 -07:00
|
|
|
if [[ ! ${!evar} ]]; then
|
|
|
|
# echo DECLARE $evar via $line
|
|
|
|
if declare -gx "$(echo "${line}" | sed 's/\"//g' )"; then
|
2023-04-14 21:27:40 -07:00
|
|
|
quiet echo loaded: ${evar}=${!evar}
|
2023-03-27 11:07:25 -07:00
|
|
|
else
|
2023-04-14 21:27:40 -07:00
|
|
|
quiet echo error setting $evar
|
2023-03-27 11:07:25 -07:00
|
|
|
return 1
|
|
|
|
|
|
|
|
fi
|
|
|
|
else
|
2023-04-14 21:27:40 -07:00
|
|
|
quiet echo $evar already set to ${!evar}
|
2023-03-27 11:07:25 -07:00
|
|
|
fi
|
|
|
|
done < <(clean_env_file -c $1)
|
|
|
|
}
|
|
|
|
|
|
|
|
source_env_file () {
|
2023-04-14 21:27:40 -07:00
|
|
|
local default;local efile
|
2024-01-29 15:16:15 -08:00
|
|
|
if efile=$(env_file "${@:-$BUILD_EFILE}"); then
|
2023-03-27 11:07:25 -07:00
|
|
|
[[ $efile == ".env" ]] && default=true
|
|
|
|
[[ ! $(isAbsPath $efile) ]] && efile=$(realpath $efile)
|
2023-04-14 21:27:40 -07:00
|
|
|
quiet echo -e "\e[1;37m********************\e[0;37m"
|
|
|
|
quiet echo loading build environment with environment file
|
|
|
|
quiet echo $efile
|
|
|
|
quiet echo ----------------
|
|
|
|
quiet cat $efile
|
|
|
|
quiet echo ----------------
|
2023-03-27 11:07:25 -07:00
|
|
|
if read_env_file "$efile"; then
|
2023-04-14 21:27:40 -07:00
|
|
|
[[ $default ]] && quiet echo -e "\e[1;31mNOTE: sourced default .env file in present directory\e[0;37m"
|
|
|
|
quiet echo -e "\e[1;37m********************\e[0;37m"
|
|
|
|
BUILD_EFILE=$efile
|
2023-03-27 11:07:25 -07:00
|
|
|
else
|
2023-04-14 21:27:40 -07:00
|
|
|
quiet echo error occured while loading environment file
|
|
|
|
quiet echo $efile
|
|
|
|
quiet echo exiting
|
|
|
|
quiet echo -e "\e[1;37m********************\e[0;37m"
|
2023-03-27 11:07:25 -07:00
|
|
|
return 2
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
if [[ $efile ]]; then
|
2023-04-14 21:27:40 -07:00
|
|
|
quiet echo unable to find an environment file with passed ${1}
|
2023-03-27 11:07:25 -07:00
|
|
|
else
|
2023-04-14 21:27:40 -07:00
|
|
|
quiet echo unable to find default environment file .env
|
|
|
|
quiet echo using the current environment plus default build options
|
2023-03-27 11:07:25 -07:00
|
|
|
fi
|
|
|
|
return 2
|
|
|
|
fi
|
2023-04-14 21:27:40 -07:00
|
|
|
|
2023-03-27 11:07:25 -07:00
|
|
|
}
|
|
|
|
|
2023-04-22 08:19:45 -07:00
|
|
|
load_csv () {
|
2024-09-15 18:47:22 -07:00
|
|
|
# add newline, remove comments, remove empty lines, remove leading whitepace, remove extra whitespace around ,
|
2023-04-22 08:19:45 -07:00
|
|
|
if [[ -f $1 ]]; then
|
|
|
|
sed -e '$a\' "$1" | \
|
|
|
|
sed -e '/\s*#.*$/d' | \
|
|
|
|
sed -e '/^\s*$/d' | \
|
2024-09-15 18:47:22 -07:00
|
|
|
sed 's/^\s*//g' | \
|
2023-04-22 08:19:45 -07:00
|
|
|
sed 's/\s*,\s*/,/g'
|
|
|
|
else
|
|
|
|
return 1
|
|
|
|
fi
|
2023-03-27 11:07:25 -07:00
|
|
|
}
|
|
|
|
|
2024-09-15 18:47:22 -07:00
|
|
|
get_distro_core_image_name () {
|
|
|
|
local distro; local imagename
|
|
|
|
distro=${1:-$LINUX_DISTRO}
|
|
|
|
if [[ $distro ]]; then
|
|
|
|
imagename=$(echo "$(load_csv $BDIR/distros.csv)" | grep "^${distro}," | cut -f2 -d, | sed "s/\s/|/g")
|
|
|
|
[[ $imagename ]] && echo $imagename || return 1
|
|
|
|
else
|
|
|
|
return 2
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
get_distro_from_image () {
|
|
|
|
local temp=/tmp/os-release.tmp
|
|
|
|
local distro
|
|
|
|
local keep
|
|
|
|
[[ $1 == "-k" ]] && (keep=true;shift)
|
|
|
|
[[ ! $1 ]] && return 1
|
|
|
|
if docker create --name dummy $1 > /dev/null 2>&1; then
|
|
|
|
if docker cp -L dummy:${2:-/etc/os-release} $temp > /dev/null 2>&1; then
|
|
|
|
docker rm -f dummy > /dev/null
|
|
|
|
distro=$(cat $temp | grep "ID_LIKE=" | cut -f2 -d=)
|
|
|
|
if [[ ! "$distro" ]]; then
|
|
|
|
distro=$(cat $temp | grep "^ID=" | cut -f2 -d=)
|
|
|
|
fi
|
|
|
|
[[ "$distro" ]] && echo $distro || return 2
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
[[ ! $keep ]] && docker image rm $1 > /dev/null 2>&1
|
2023-04-22 08:19:45 -07:00
|
|
|
}
|
|
|
|
|
2024-09-15 18:47:22 -07:00
|
|
|
validate_distro() {
|
|
|
|
# only valid distros are ones in distros.csv
|
|
|
|
local distro; local set_distro;
|
|
|
|
distro=${1:-$LINUX_DISTRO}
|
|
|
|
if [[ $distro ]]; then
|
|
|
|
if [[ $BASE_IMAGE ]]; then
|
|
|
|
>&2 echo "FATAL: cannot specifiy both BASE_IMAGE ($BASE_IMAGE) and a LINUX_DISTRO ($LINUX_DISTRO), aborting build"
|
|
|
|
return 2
|
2023-04-22 08:19:45 -07:00
|
|
|
fi
|
|
|
|
else
|
2024-09-15 18:47:22 -07:00
|
|
|
if [[ $BASE_IMAGE ]]; then
|
|
|
|
echo validate from base image
|
|
|
|
if ! distro=$(get_distro_from_image $BASE_IMAGE); then
|
|
|
|
>&2 echo "ERROR: unable to get distro from BASE_IMAGE $BASE_IMAGE, can't validate"
|
|
|
|
return 2
|
|
|
|
fi
|
|
|
|
set_distro=true
|
|
|
|
else
|
|
|
|
echo "WARNING: neither LINUX_DISTRO nor BASE_IMAGE image specified"
|
|
|
|
echo "Setting LINUX_DISTRO to default (alpine)"
|
|
|
|
set_distro=true
|
|
|
|
distro=alpine
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
distros=$(echo $(echo "$(load_csv $BDIR/distros.csv)" | grep -Eo "^[^,]+") | sed "s/\s/|/g" | tr '[:upper:]' '[:lower:]')
|
|
|
|
if [[ ! "$distros" == *"${distro}"* ]]; then
|
|
|
|
>&2 echo "distro $distro is not a valid uci-docker-build distro ($distros)"
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
[[ ! $BASE_NAME ]] && BASE_IMAGE=$(get_distro_core_image_name $distro)
|
|
|
|
if [[ $set_distro ]] && [[ ! "$1" ]]; then LINUX_DISTRO=$distro; fi
|
|
|
|
|
2023-04-22 08:19:45 -07:00
|
|
|
}
|
2023-04-14 21:27:40 -07:00
|
|
|
|
2024-09-15 18:47:22 -07:00
|
|
|
# delete
|
|
|
|
# get_base_image() {
|
2023-04-14 21:27:40 -07:00
|
|
|
|
2024-09-15 18:47:22 -07:00
|
|
|
# [[ ! $BASE_IMAGE ]] && BASE_IMAGE=$(get_default_distro_image)
|
|
|
|
# if [[ $BASE_IMAGE ]]; then
|
|
|
|
# quiet echo determining DISTRO of base image: $BASE_IMAGE
|
|
|
|
# if ! validate_image_distro $BASE_IMAGE; then
|
|
|
|
# echo "unable to get or use base image: $BASE_IMAGE, aborting build" && return 5
|
|
|
|
# fi
|
|
|
|
# quiet echo $BASE_IMAGE is built from distro $LINUX_DISTRO
|
|
|
|
# else
|
|
|
|
# echo unable to determine a base image, aborting build
|
|
|
|
# return 6
|
|
|
|
# fi
|
|
|
|
# }
|
2023-04-14 21:27:40 -07:00
|
|
|
|
2023-04-03 14:14:17 -07:00
|
|
|
make_image_name () {
|
|
|
|
|
2023-04-14 21:27:40 -07:00
|
|
|
local arch
|
|
|
|
|
2023-04-03 14:14:17 -07:00
|
|
|
# echo making image name $@
|
|
|
|
# echo name: $NAME
|
2023-04-14 21:27:40 -07:00
|
|
|
# echo APPEND: $APPEND_DISTRO
|
2023-04-03 14:14:17 -07:00
|
|
|
# echo user: $RUSER
|
|
|
|
# echo distro $LINUX_DISTRO
|
|
|
|
|
|
|
|
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
|
2023-04-14 21:27:40 -07:00
|
|
|
[[ $APPEND_DISTRO ]] && NAME=$NAME-${LINUX_DISTRO}
|
2023-04-03 14:14:17 -07:00
|
|
|
else
|
|
|
|
# echo no image name supplied using distro name ${LINUX_DISTRO:-alpine}
|
|
|
|
NAME=${LINUX_DISTRO:-alpine}
|
|
|
|
fi
|
|
|
|
|
2023-04-14 21:27:40 -07:00
|
|
|
[[ $TARGET == "arm64" && ! $TARGET == $(get_arch) ]] && arch=-$TARGET
|
|
|
|
[[ $TARGET == "amd64" && ! $TARGET == $(get_arch) ]] && arch=-$TARGET
|
|
|
|
|
|
|
|
echo $([[ $RUSER ]] && echo ${RUSER}/)${NAME}$arch
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
get_build_src () {
|
|
|
|
# processing the build source directory
|
|
|
|
local src; local spath; local spaths
|
2024-01-14 14:57:09 -08:00
|
|
|
|
|
|
|
# will determine if there are any minimal build source files/directories
|
2023-04-14 21:27:40 -07:00
|
|
|
check_dir () {
|
2024-01-14 14:57:09 -08:00
|
|
|
if
|
|
|
|
[ $(ls $1/packages/*system.pkgs 2> /dev/null) ] || \
|
|
|
|
[ $(ls $1/packages/system/*.pkgs 2> /dev/null) ] || \
|
|
|
|
[ -f $1/packages/repositories.sh ] || \
|
|
|
|
[ -f $1/packages/packages.sh ]
|
|
|
|
then
|
|
|
|
_packages_=true
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
[[ -f $1/init/init.sh ]] && return 0
|
|
|
|
[[ -d $1/rootfs ]] && return 0
|
|
|
|
return 1
|
2023-04-14 21:27:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
src=${1:-$BUILD_SRC}
|
2023-04-22 08:19:45 -07:00
|
|
|
[[ $src == "_core_" ]] && return 0
|
2023-04-14 21:27:40 -07:00
|
|
|
src=${src:-src}
|
|
|
|
unset BUILD_SRC
|
|
|
|
|
|
|
|
if check_dir $src; then
|
|
|
|
BUILD_SRC=$(realpath $src)
|
2024-01-29 15:16:15 -08:00
|
|
|
echo $BUILD_SRC
|
2023-04-14 21:27:40 -07:00
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
|
2024-01-29 15:16:15 -08:00
|
|
|
quiet echo build source path \'$src\' not initially found, echo looking
|
|
|
|
quiet echo in \$PWD,\$PWD/src/,../\$PWD/src for valid build source
|
|
|
|
quiet echo to avoid this search use BUILD_SRC= in an environment file
|
2023-04-22 08:19:45 -07:00
|
|
|
spaths="$PWD $PWD/src $(dirname $PWD)/$src $(dirname $PWD)"
|
2023-04-14 21:27:40 -07:00
|
|
|
for spath in $spaths; do
|
2024-01-29 15:16:15 -08:00
|
|
|
quiet echo checking for source in: $spath
|
2023-04-14 21:27:40 -07:00
|
|
|
if check_dir $spath; then
|
2024-01-29 15:16:15 -08:00
|
|
|
quiet echo found valid source directory!
|
2023-04-14 21:27:40 -07:00
|
|
|
BUILD_SRC=$spath
|
2024-01-29 15:16:15 -08:00
|
|
|
echo $BUILD_SRC
|
2023-04-14 21:27:40 -07:00
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
2024-01-29 15:16:15 -08:00
|
|
|
quiet echo -e "\e[1;31mERROR: unable to find a build source directory as $src \e[1;37m"
|
2023-04-14 21:27:40 -07:00
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
|
|
|
build_info () {
|
|
|
|
|
|
|
|
if [[ $VERBOSE ]]; then
|
|
|
|
echo -e "\n!!!!!!!!!!!!!!!!EXTRA BUILD INFO !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
|
|
|
pushd "$BDIR" > /dev/null || return 3
|
|
|
|
docker buildx bake --print $TARGET
|
|
|
|
popd > /dev/null || return 4
|
2024-09-15 18:47:22 -07:00
|
|
|
if [[ $BUILD_SRC == "_core_" ]]; then
|
|
|
|
echo building only core
|
|
|
|
cat $BDIR/core/core.sh
|
|
|
|
ls -la $BDIR/core
|
|
|
|
else
|
|
|
|
echo -e "\n---------------------------------"
|
|
|
|
echo "build source at $BUILD_SRC to be mounted to /build in container ***** "
|
|
|
|
ls -la $BUILD_SRC
|
|
|
|
echo -e "\n----- base init script init.sh ------\n"
|
|
|
|
cat $BUILD_SRC/init/init.sh
|
|
|
|
echo -e "\n----- end base init script init.sh ------"
|
|
|
|
echo -e "\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
|
|
|
fi
|
2023-04-14 21:27:40 -07:00
|
|
|
fi
|
|
|
|
|
|
|
|
echo -e "\e[1;37m**************BUILD PARAMETERS *******************************"
|
|
|
|
echo "Architecture of this machine doing the building: $ARCH"
|
2024-01-14 14:57:09 -08:00
|
|
|
if [[ "$BUILD_SRC" == "_core_" ]] ;then
|
2023-04-22 08:19:45 -07:00
|
|
|
echo Building ONLY the UCI core
|
|
|
|
else
|
|
|
|
echo "Using scripts source directory at $BUILD_SRC"
|
|
|
|
fi
|
|
|
|
echo "Building with base image: $BASE_IMAGE"$([[ "${BASE_IMAGE}" == *":"* ]] || echo :latest)
|
2023-04-14 21:27:40 -07:00
|
|
|
echo "Build logs can be found in directory $log_dir"
|
|
|
|
echo "Linux Distro of Image: $LINUX_DISTRO"
|
|
|
|
echo "Using build target: ${TARGET}"
|
2023-04-22 08:19:45 -07:00
|
|
|
if [[ -f $APPEND_BUILD_ENV ]]; then
|
|
|
|
echo "Will append contents of $APPEND_BUILD_ENV to build envionrment"
|
|
|
|
echo "-------"
|
|
|
|
cat $APPEND_BUILD_ENV
|
|
|
|
echo "-------"
|
|
|
|
fi
|
2023-04-14 21:27:40 -07:00
|
|
|
echo "----- output --------"
|
|
|
|
echo creating image
|
|
|
|
case $TARGET in
|
|
|
|
|
|
|
|
multi)
|
|
|
|
echo "names for both amd64 and arm64, image without architecture suffix is $ARCH"
|
|
|
|
echo -e "\e[1;31m$IMAGE_NAME$([[ ! $ARCH == amd64 ]] && echo -amd64):${TAG:-latest}\n$IMAGE_NAME$([[ ! $ARCH == arm64 ]] && echo -arm64):${TAG:-latest}\e[1;37m"
|
|
|
|
echo "building locally and then pushing to ${REPO:-hub.docker.com}"
|
|
|
|
if [[ ! $REPO ]]; then
|
|
|
|
echo "NOTE: use target 'publish' to build and push these both"
|
|
|
|
echo "to docker hub without architecture suffix or local copy"
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
dev)
|
|
|
|
;&
|
|
|
|
default)
|
|
|
|
echo -e "name => \e[1;31m$IMAGE_NAME:${TAG:-latest}\e[1;37m"
|
|
|
|
echo "Will build this single image on this machine with architecture $ARCH"
|
|
|
|
;;
|
|
|
|
arm64)
|
|
|
|
echo -e "name => \e[1;31m$IMAGE_NAME$([[ ! $ARCH == arm64 ]] && echo -arm64):${TAG:-latest}\e[1;37m"
|
|
|
|
echo "Will build this single arm64 image on this machine"
|
|
|
|
;;
|
|
|
|
amd64)
|
|
|
|
echo -e "name => \e[1;31m$IMAGE_NAME$([[ ! $ARCH == amd64 ]] && echo -amd64):${TAG:-latest}\e[1;37m"
|
|
|
|
echo "Will build this single amd64 image on this machine"
|
|
|
|
;;
|
|
|
|
publish)
|
|
|
|
echo -e "image name \e[1;31m$IMAGE_NAME:${TAG:-latest}\e[1;37m"
|
|
|
|
echo "Will build and push both amd64 and arm64"
|
|
|
|
echo "architecture images to hub.docker.com with this single name"
|
|
|
|
echo "and no local copy will remain"
|
|
|
|
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
echo "------------------"
|
|
|
|
echo -e "********************\e[0;37m"
|
2023-04-03 14:14:17 -07:00
|
|
|
|
|
|
|
}
|