4a899d754f
Add in the ability to override the prefix in .buildconf files removing the requirement to set the prefix in a .buildconf to limit the number of images built. Partially Implements: blueprint refactor-base-image-layout Change-Id: I1da1559e660adc2fe9eaf5e17ce427c89645a8b7
240 lines
5.9 KiB
Bash
Executable File
240 lines
5.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Depends on bash 4 and gawk
|
|
|
|
TOPDIR=$(git rev-parse --show-toplevel)
|
|
# Work in a temp dir so that developers can continue working while a build is
|
|
# in progress
|
|
WORKDIR=$(mktemp -d /tmp/kolla-workdir.XXXXXXXXXX)
|
|
# Remove $WORKDIR otherwise $TOPDIR is copied *inside* of it
|
|
rm -rf $WORKDIR
|
|
cp -aL "$TOPDIR" $WORKDIR
|
|
DOCKERDIR="$WORKDIR/docker"
|
|
|
|
declare -A dependency
|
|
declare -A img_dirs
|
|
declare -A status
|
|
|
|
function info {
|
|
[[ -n $1 ]] && printf "%s\n" "$1"
|
|
}
|
|
|
|
function success {
|
|
[[ -n $1 ]] && printf "\033[00;32m%s\033[00m\n" "$1"
|
|
}
|
|
|
|
function warn {
|
|
[[ -n $1 ]] && printf "\033[00;31m%s\033[00m\n" "$1"
|
|
}
|
|
|
|
function set_defaults {
|
|
PREFIX=centos-rdo-
|
|
NAMESPACE=kollaglue
|
|
[ -f $WORKDIR/.buildconf ] && . $WORKDIR/.buildconf
|
|
[ -n "${FORCE_PREFIX}" ] && PREFIX="${FORCE_PREFIX}"
|
|
}
|
|
|
|
function has_changed {
|
|
local image=$1
|
|
# Rebuild everything unless given git revision
|
|
# We don't really care about the order of the $FROM and $TO parameters, all
|
|
# we need is the list of changed files between the revisions, or HEAD if
|
|
# only one of them is specified
|
|
[[ -z $FROM && -z $TO ]] || git diff --name-only $FROM $TO | grep -q "${img_dirs[$image]#$WORKDIR/}"
|
|
}
|
|
|
|
function requires_build {
|
|
local image=$1
|
|
local dep=${dependency[$image]}
|
|
# An image requires a built if it meets the following conditions:
|
|
# - it has instructions to build the image
|
|
# - it hasn't been processed yet
|
|
# - its dependency was rebuilt or its build instruction was modified
|
|
[[ ${img_dirs[$image]} && -z ${status[$image]} ]] && \
|
|
([[ ${status[$dep]} == "rebuilt" ]] || has_changed $image)
|
|
}
|
|
|
|
function build_image {
|
|
local dir=$1
|
|
printf "\n"
|
|
if [ -x "$dir/build" ]; then
|
|
info "Building image in $dir"
|
|
if $dir/build $ARGS --no-use-released-parent; then
|
|
success "Successfully built image in $dir"
|
|
status[$image]="rebuilt"
|
|
else
|
|
warn "Failed to build image in $dir"
|
|
status[$image]="fail"
|
|
fi
|
|
else
|
|
warn "Image $image does not provide build script"
|
|
status[$image]="fail"
|
|
fi
|
|
}
|
|
|
|
function init_image {
|
|
local img_dir=$1
|
|
|
|
set_defaults
|
|
[ -f $WORKDIR/.buildconf ] && . $WORKDIR/.buildconf
|
|
[ -f $img_dir/.buildconf ] && . $img_dir/.buildconf
|
|
[ -n "$FORCE_NAMESPACE" ] && NAMESPACE=$FORCE_NAMESPACE
|
|
[ -n "${REGISTRY}" ] && NAMESPACE="${REGISTRY}/${NAMESPACE}"
|
|
|
|
local image="${NAMESPACE:+${NAMESPACE}/}${PREFIX}${img_dir##*/}"
|
|
local base_image=$(cat $img_dir/Dockerfile | gawk 'match($0, /^\s*FROM\s+(\S+)/, matches) {print matches[1]}' )
|
|
base_image=${base_image//%%KOLLA_NAMESPACE%%/$NAMESPACE}
|
|
base_image=${base_image//%%KOLLA_PREFIX%%/$PREFIX}
|
|
base_image=${base_image//:%%KOLLA_TAG%%/}
|
|
|
|
img_dirs[$image]=$img_dir
|
|
dependency[$image]=$base_image
|
|
|
|
# Restore defaults to minimize risk of side effects
|
|
set_defaults
|
|
}
|
|
|
|
function process_image {
|
|
local image=$1
|
|
if [ -n "${dependency[$image]}" ]; then
|
|
process_image ${dependency[$image]}
|
|
fi
|
|
if requires_build $image; then
|
|
build_image ${img_dirs[$image]}
|
|
fi
|
|
if [ -z "${status[$image]}" ]; then
|
|
status[$image]="up-to-date"
|
|
fi
|
|
}
|
|
|
|
function print_summary {
|
|
printf "\nSummary\n=======\n"
|
|
for image in "${!status[@]}"; do
|
|
case "${status[$image]}" in
|
|
("fail") warn "Failed to process $image" ;;
|
|
("rebuilt") success "Rebuilt $image" ;;
|
|
(*) info "$image: ${status[$image]}" ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
function print_parseable_summary {
|
|
printf "{"
|
|
for image in "${!status[@]}"; do
|
|
printf "'$image':'${status[$image]}',"
|
|
done
|
|
printf "}"
|
|
}
|
|
|
|
function interrupted {
|
|
info "Interrupted..."
|
|
print_summary
|
|
rm -rf $WORKDIR
|
|
exit 1
|
|
}
|
|
|
|
function usage {
|
|
read -r -d '' HELP <<EOF
|
|
A wrapper to build-docker-image that build all images in order.
|
|
|
|
Options:
|
|
|
|
--prefix <image_prefix>
|
|
--from <git-revision>
|
|
--to <git-revision>
|
|
|
|
$($WORKDIR/tools/build-docker-image --help)
|
|
EOF
|
|
printf "%s\n" "${HELP/$WORKDIR\/tools\/build-docker-image/$0}"
|
|
}
|
|
|
|
trap 'interrupted' INT
|
|
|
|
|
|
ARGS=$@
|
|
PARSED_ARGS=$(getopt -q -o hr:n:t: -l help,prefix:,namespace:,release,tag:,private-registry:,from:,to:,testmode -- "$@")
|
|
|
|
eval set -- "$PARSED_ARGS"
|
|
|
|
while :; do
|
|
case "$1" in
|
|
|
|
(--help|-h) usage
|
|
exit 0
|
|
;;
|
|
|
|
(--prefix) shift
|
|
FORCE_PREFIX="$1"
|
|
;;
|
|
|
|
(--namespace|-n)
|
|
shift
|
|
FORCE_NAMESPACE="$1"
|
|
;;
|
|
|
|
(--release)
|
|
RELEASE_SPECIFIED=1
|
|
;;
|
|
|
|
(--tag|-t)
|
|
shift
|
|
TAG_SPECIFIED=1
|
|
;;
|
|
|
|
(--private-registry|-r)
|
|
shift
|
|
REGISTRY="$1"
|
|
;;
|
|
|
|
(--from)
|
|
shift
|
|
FROM="$1"
|
|
ARGS=${ARGS/\-\-from*$FROM/}
|
|
;;
|
|
|
|
(--to)
|
|
shift
|
|
TO="$1"
|
|
ARGS=${ARGS/\-\-to*$TO/}
|
|
;;
|
|
|
|
(--testmode)
|
|
TESTMODE=1
|
|
ARGS=${ARGS/\-\-testmode/}
|
|
;;
|
|
|
|
(--) break
|
|
;;
|
|
|
|
esac
|
|
|
|
shift
|
|
done
|
|
|
|
set_defaults
|
|
|
|
# BASE == centos, fedora, ubuntu, etc.
|
|
BASE=$(echo "${PREFIX}" | cut -d- -f1)
|
|
# TYPE == binary, source, rdo
|
|
TYPE=$(echo "${PREFIX}" | cut -d- -f2)
|
|
|
|
# Ensure a tag is specified otherwise build may fail when changing git branch
|
|
# The release tag is automatically appended when --release flag is used.
|
|
if [[ $RELEASE_SPECIFIED != 1 ]] && [[ $TAG_SPECIFIED != 1 ]]; then
|
|
TAG=$(git rev-parse --short HEAD)
|
|
ARGS+=" --tag $TAG"
|
|
fi
|
|
|
|
# Do a first pass to find images to build and their dependencies
|
|
for dockerfile in $(find "${DOCKERDIR}/${BASE}/${TYPE}" -name Dockerfile); do
|
|
init_image $(dirname $dockerfile)
|
|
done
|
|
|
|
# Process all images
|
|
for image in "${!img_dirs[@]}"; do
|
|
process_image $image
|
|
done
|
|
|
|
print_summary
|
|
[ -n "$TESTMODE" ] && print_parseable_summary
|
|
rm -rf $WORKDIR
|