| #!/usr/bin/env bash |
| |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| # Files are relative to this script directory. |
| SELF="${BASH_SOURCE[0]}" |
| cd "$( dirname "${BASH_SOURCE[0]}" )" |
| COMPOSE_FILE=./infrastructure/docker/build/docker-compose.yml |
| COMPOSE_FILE_OPT=./infrastructure/docker/build/docker-compose-opt.yml |
| |
| # Check for dependencies |
| if ! which docker >/dev/null 2>&1; then |
| echo "Error: docker is required for a docker build." >&2 |
| exit 1 |
| fi |
| |
| # If the user defined COMPOSE, use that as the path for docker-compose. |
| if [ ! -z "$COMPOSE" ]; then |
| COMPOSECMD=( "$COMPOSE" ) |
| else |
| COMPOSECMD=() |
| fi |
| |
| # Check to see if docker-compose is already installed and use it directly, if possible. |
| if [ ${#COMPOSECMD[@]} -eq 0 ]; then |
| if which docker-compose >/dev/null 2>&1; then |
| COMPOSECMD=( docker-compose ) |
| fi |
| fi |
| |
| # If it's unavailable, go get the image and run docker-compose inside a container. |
| # This is considerably slower, but allows for building on hosts without docker-compose. |
| if [ ${#COMPOSECMD[@]} -eq 0 ]; then |
| # Pin the version of docker-compose. |
| IMAGE="docker/compose:1.11.2" |
| |
| # We need to either mount the docker socket or export the docker host into the container. |
| # This allows the container to manage "sibling" containers via docker. |
| if [ -z "$DOCKER_HOST" ]; then |
| DOCKER_HOST="/var/run/docker.sock" |
| fi |
| |
| if [ -S "$DOCKER_HOST" ]; then |
| DOCKER_ADDR=(-v "$DOCKER_HOST:$DOCKER_HOST" -e DOCKER_HOST) |
| else |
| DOCKER_ADDR=(-e DOCKER_HOST -e DOCKER_TLS_VERIFY -e DOCKER_CERT_PATH) |
| fi |
| |
| # We mount the current directory (the base of the repository) into the same location |
| # inside the container. There are many places for which this won't work, but "/" is |
| # a major one. |
| # |
| # You're going to want to avoid keeping your repository in a folder named "/usr/bin", |
| # "/home", "/var" or any other standard paths that will be needed by the docker container. |
| # |
| # This is very unlikely to cause trouble for anyone in practice. |
| if [ "$(pwd)" == "/" ]; then |
| echo "Error: Cannot compile directly at filesystem root." >&2 |
| exit 1 |
| fi |
| |
| # Mount the working directory, and the home directory. Mounting $HOME provides container |
| # access to config files that are kept there. |
| VOLUMES=(-v "$(pwd):$(pwd)" -v "$HOME:$HOME" -v "$HOME:/root") |
| |
| # Prepull the image, to avoid spitting out pull progress during other commands. |
| if ! docker inspect $IMAGE >/dev/null 2>&1; then |
| docker pull $IMAGE >/dev/null 2>&1 |
| fi |
| |
| # COMPOSECMD is kept as an array to significantly simplify handling paths that contain |
| # spaces and other special characters. |
| COMPOSECMD=(docker run --rm "${DOCKER_ADDR[@]}" $COMPOSE_OPTIONS "${VOLUMES[@]}" -w "$(pwd)" $IMAGE) |
| fi |
| |
| # Mark RHEL_VERSION for export, although it is not set yet |
| export RHEL_VERSION |
| RUN_OPTIONS=(-e RHEL_VERSION) |
| |
| # Parse command line arguments |
| verbose=0 |
| debug=0 |
| quiet=0 |
| all=0 |
| build_images=0 |
| while getopts :?78abdf:lopqv opt; do |
| case $opt in |
| \?) |
| PROJECTS=`$SELF -l | sed "s/^/ - /"` |
| <<-HELP_TEXT cat |
| Usage: $SELF [options] [projects] |
| -7 Build RPMs targeting CentOS 7 (default) |
| -8 Build RPMs targeting CentOS 8 |
| -a Build all projects, including optional ones. |
| -b Build builder Docker images before building projects |
| -d Disable compiler optimizations for debugging. |
| -f <file> Use <file> as the docker-compose. Default: $COMPOSE_FILE |
| -l List available projects. |
| -o Build from the optional list. Same as -f "$COMPOSE_FILE_OPT" |
| -p Pull builder Docker images, do not build them (default) |
| -q Quiet mode. Supresses output. (default) |
| -v Verbose mode. Lists all build output. |
| |
| If no projects are listed, all projects will be packaged. |
| Valid projects: |
| $PROJECTS |
| HELP_TEXT |
| exit 0 |
| ;; |
| 7) |
| RHEL_VERSION=7 |
| ;; |
| 8) |
| RHEL_VERSION=8 |
| ;; |
| a) |
| all=1 |
| ;; |
| b) |
| build_images=1 |
| ;; |
| d) |
| echo '-d is set! Disabling all compiler optimizations for debugging...'; |
| # If DEBUG_BUILD is true, then Golang binaries will remain unoptimized and |
| # RPM packaging will not strip binaries. |
| RUN_OPTIONS+=(-e 'DEBUG_BUILD=true'); |
| debug=1 |
| ;; |
| f) |
| COMPOSE_FILE="$OPTARG" |
| ;; |
| l) |
| "${COMPOSECMD[@]}" -f $COMPOSE_FILE config --services |
| exit $? |
| ;; |
| o) |
| COMPOSE_FILE="$COMPOSE_FILE_OPT" |
| ;; |
| p) |
| build_images=0 |
| ;; |
| q) |
| exec >/dev/null 2>&1 |
| quiet=1 |
| ;; |
| v) |
| verbose=1 |
| ;; |
| esac |
| done |
| |
| shift $((OPTIND-1)) |
| |
| # If no specific packages are listed, or -a is used, run them all. |
| if (( ! "$#" || "$all" == 1 )); then |
| set -- `$SELF -f "$COMPOSE_FILE" -l` |
| fi |
| |
| # Build each project in turn. |
| failure=0 |
| badproj="" |
| while (( "$#" )); do |
| echo Building $1. |
| ( |
| if (( "$verbose" == 0 )); then |
| exec >/dev/null 2>&1 |
| fi |
| |
| # Build the project |
| if [[ $build_images -eq 1 ]]; then |
| "${COMPOSECMD[@]}" -f $COMPOSE_FILE build $1 || exit 1 |
| else |
| "${COMPOSECMD[@]}" -f $COMPOSE_FILE pull $1 || exit 1 |
| fi |
| "${COMPOSECMD[@]}" -f $COMPOSE_FILE run "${RUN_OPTIONS[@]}" --rm $1 || exit 1 |
| |
| # Check for a chained compose file for this particular project. |
| # A chained compose file will be named exactly the same as main docker-compose, with .service added, |
| # where <service> is the name of the specific service to be chained. The file may be a symlink to another |
| # compose file, in which case the symlink will be followed before it is processed. |
| # A "dist" symlink will be temporarily created in that directory to facilitate the collation of artefacts. |
| if [ -e "$COMPOSE_FILE.$1" ] ; then |
| ln -sf "$(dirname -- "$(realpath -e -- "$SELF")")/dist" "$(dirname -- "$(realpath -e -- "$COMPOSE_FILE.$1")")/dist" || exit 1 |
| $SELF -f $(realpath -e "$COMPOSE_FILE.$1") $([ "$verbose" == 0 ] || echo "-v") $([ "$quiet" == 0 ] || echo "-q") $([ "$debug" == 0 ] || echo "-d") $([ "$build" == 0 ] || echo "-b") $("${COMPOSECMD[@]}" -f $(realpath -e "$COMPOSE_FILE.$1") config --services) |
| chained_exit=$? |
| rm "$(dirname -- "$(realpath -e -- "$COMPOSE_FILE.$1")")/dist" |
| [ $chained_exit == 0 ] || exit $chained_exit |
| fi |
| ) || { |
| # Don't totally bail out, but make note of the failures. |
| failure=1 |
| badproj="$badproj $1" |
| } |
| shift |
| done |
| |
| [ "$all" == 0 ] || $SELF -o $([ "$verbose" == 0 ] || echo "-v") $([ "$quiet" == 0 ] || echo "-q") $([ "$debug" == 0 ] || echo "-d") || failure=1 |
| |
| if [[ ! -z $badproj ]]; then |
| echo "Failed to build$badproj." |
| fi |
| |
| if [[ -d dist ]]; then |
| echo "Results in 'dist':" |
| ls -lt dist |
| else |
| echo "dist artifact directory not found." |
| fi |
| |
| exit $failure |