1#!/bin/bash -r 2 3function container_exists() { 4 [[ $(docker ps -a --filter "name=^/$1$" --format '{{.Names}}') == $1 ]] && echo $1; 5} 6 7declare -A map_uname_to_docker_builder_arch=( [aarch64]=linux/arm64 [x86_64]=linux/amd64 ) 8 9# inputs 10# $1 = image name 11# $2 = container name 12# $3 = architecture (x86_64 or aarch64) 13# $4 = user name 14# $5 = user ID 15# $6 = persistent? 16# $7 = path to sources dir 17# $8 = path to working dir 18# $9 = path to output dir 19# $10 = reuse image/container? (0: no reuse; 1: reuse image; 2: reuse container) 20# $11 = build image (when reuse = 0) 21# $12 = path to Dockerfile 22# $13 = path to docker context dir 23# $14 = docker_flags_len 24# $15 = (docker_flags) 25# $16 = _prepare_source_len 26# $17 = (_prepare_source) 27function build_with_docker() { 28 set -o errexit 29 set -x 30 31 local -a _docker_target=( ${1} ) 32 local _container_name=${2} 33 local _arch=${3} 34 local _docker_image=${1}_${_arch} 35 local _user=${4} 36 local _uid=${5} 37 local _persistent=${6} 38 39 if [[ ${_persistent} -eq 1 ]]; then 40 _docker_image=${1}_${_arch}_persistent 41 fi 42 local _docker_source= 43 if [ "${7}" != 'x' ]; then 44 _docker_source="-v ${7#x}:/source:rw" 45 fi 46 local _docker_working= 47 if [ "${8}" != 'x' ]; then 48 _docker_working="-v ${8#x}:/working:rw" 49 fi 50 local _docker_output= 51 if [ "${9}" != 'x' ]; then 52 _docker_output="-v ${9#x}:/output:rw" 53 fi 54 local _reuse=${10} 55 local _build_image=${11} 56 local _dockerfile=${12} 57 local _docker_context=${13} 58 shift 13 59 local -a _args=("$@") 60 local -i _docker_flags_len=${_args[0]} 61 local -a _docker_flags=("${_args[@]:1:$_docker_flags_len}") 62 local -i _prepare_source_len=${_args[(_docker_flags_len+1)]} 63 local -a _prepare_source=("${_args[@]:(_docker_flags_len+2):_prepare_source_len}") 64 65 local _build_or_retry=${_arch}_retry 66 67 if [[ ${_reuse} -ne 1 ]]; then 68 _build_or_retry=${_arch}_build 69 if [[ ${_persistent} -eq 1 ]]; then 70 _docker_target+=("${_docker_target[0]}_persistent") 71 fi 72 if [[ ${_build_image} -eq 1 ]]; then 73 if [[ ${_arch} != $(uname -m) ]]; then 74 export DOCKER_CLI_EXPERIMENTAL=enabled 75 # from 76 # https://community.arm.com/developer/tools-software/tools/b/tools-software-ides-blog/posts/getting-started-with-docker-for-arm-on-linux 77 docker run --rm --privileged docker/binfmt:820fdd95a9972a5308930a2bdfb8573dd4447ad3 78 docker buildx create \ 79 --name docker_vmm_${_arch}_builder \ 80 --platform ${map_uname_to_docker_builder_arch[${_arch}]} \ 81 --use 82 docker buildx inspect --bootstrap 83 for _target in ${_docker_target[@]}; do 84 docker buildx build \ 85 --progress plain \ 86 --platform ${map_uname_to_docker_builder_arch[${_arch}]} \ 87 --target ${_target} \ 88 -f ${_dockerfile} \ 89 -t ${_docker_image}:latest \ 90 ${_docker_context} \ 91 --build-arg USER=${_user} \ 92 --build-arg UID=${_uid} --load 93 done 94 docker buildx rm docker_vmm_${_arch}_builder 95 unset DOCKER_CLI_EXPERIMENTAL 96 else 97 for _target in ${_docker_target[@]}; do 98 docker build \ 99 -f ${_dockerfile} \ 100 --target ${_target} \ 101 -t ${_docker_image}:latest \ 102 ${_docker_context} \ 103 --build-arg USER=${_user} \ 104 --build-arg UID=${_uid} 105 done 106 fi 107 fi 108 if [[ ${_persistent} -eq 1 ]]; then 109 if [[ -n "$(container_exists ${_container_name})" ]]; then 110 docker rm -f ${_container_name} 111 fi 112 docker run \ 113 -d \ 114 --platform ${map_uname_to_docker_builder_arch[${_arch}]} \ 115 --name ${_container_name} \ 116 -h ${_container_name} \ 117 ${_docker_source} \ 118 ${_docker_working} \ 119 ${_docker_output} \ 120 ${_docker_image}:latest 121 fi 122# else 123# # If we are reusing the docker image, then we cannot change the target 124# # architecture (though we can change the persistence) of the container. 125# echo TODO 126 fi 127 128 if [[ ${_persistent} -eq 1 ]]; then 129 if [[ "$(docker inspect --format='{{.State.Status}}' ${_container_name})" == "paused" ]]; then 130 docker unpause ${_container_name} 131 fi 132 docker exec -it \ 133 --user ${_user} \ 134 ${_docker_flags[@]} \ 135 ${_container_name} \ 136 /static/rebuild-internal.sh ${_prepare_source[@]} ${_build_or_retry} 137 docker pause ${_container_name} 138 else 139 $docker_run -it --rm \ 140 --user ${_user} \ 141 ${_docker_flags[@]} \ 142 ${_docker_source} \ 143 ${_docker_working} \ 144 ${_docker_output} \ 145 ${_docker_image}:latest \ 146 /static/rebuild-internal.sh ${_prepare_source[@]} ${_build_or_retry} 147 fi 148} 149 150build_with_docker $@ 151