#!/bin/bash set -e cd "$(dirname "$0")" # # This script builds the neko base image and all the applications # function log() { echo "$(date +'%Y-%m-%d %H:%M:%S') - [NEKO] - $1" > /dev/stderr } function help() { echo "Usage: $0" echo " -p, --platform : The platform (default: linux/amd64)" echo " -i, --image : The image name prefix (default: ghcr.io/m1k1o/neko)" echo " -t, --tag : The image tag (default: latest)" echo " -f, --flavor : The flavor, if not specified, builds without flavor" echo " -b, --base : The base image name (default: ghcr.io/m1k1o/neko/[-]base:)" echo " -a, --app : The app to build, if not specified, builds the base image" echo " -y, --yes : Skip confirmation prompts" echo " --no-cache : Build without docker cache" echo " --push : Push the image to the registry after building" echo " -h, --help : Show this help message" } FULL_IMAGE="" while [[ "$#" -gt 0 ]]; do case $1 in --platform|-p) PLATFORM="$2"; shift ;; --image|-i) IMAGE="$2"; shift ;; --tag|-t) # comma separated list of TAGS IFS=',' read -r -a TAGS <<< "$2" # default tag is the first one TAG="${TAGS[0]}" shift ;; --flavor|-f) FLAVOR="$2"; shift ;; --base|-b) BASE_IMAGE="$2"; shift ;; --app|-a) APPLICATION="$2"; shift ;; --yes|-y) YES=1 ;; --no-cache) NO_CACHE="--no-cache" log "Building without cache" ;; --push) PUSH=1 ;; --help|-h) help; exit 0 ;; -*) log "Unknown parameter passed: $1"; help; exit 1 ;; *) if [ -z "$FULL_IMAGE" ]; then FULL_IMAGE="$1" # extracts image, flavor, app and tag from the full image name # example: # ghcr.io/m1k1o/neko/nvidia-firefox:latest # will be split into: # IMAGE=ghcr.io/m1k1o/neko # FLAVOR=nvidia # APPLICATION=firefox # TAG=latest # remove the tag from the image name if [[ "$FULL_IMAGE" == *":"* ]]; then # removes everything before the last : TAG="${FULL_IMAGE##*:}" # will be latest # removes everything after the last : FULL_IMAGE="${FULL_IMAGE%:*}" # will be ghcr.io/m1k1o/neko/nvidia-firefox fi # extract the image name and save the rest to IMAGE if [[ "$FULL_IMAGE" == *"/"* ]]; then # removes everything after the last / IMAGE="${FULL_IMAGE%/*}" # will be ghcr.io/m1k1o/neko # removes everything before the last / FULL_IMAGE="${FULL_IMAGE##*/}" # will be nvidia-firefox fi # extract the flavor and application name if [[ "$FULL_IMAGE" == *"-"* ]]; then # removes everything after the last - FLAVOR="${FULL_IMAGE%-*}" # will be nvidia # removes everything before the last - APPLICATION="${FULL_IMAGE#*-}" # will be firefox else # no flavor specified so use the full image name as application name APPLICATION="$FULL_IMAGE" # will be firefox fi # if application name is base, set it to empty if [ "$APPLICATION" == "base" ]; then APPLICATION="" fi else log "Unknown positional argument: $1" help exit 1 fi ;; esac shift done function prompt() { if [ ! -z "$YES" ]; then return 0 fi local OK="" while [ -z "$OK" ]; do read -p "$1 (yes/no) " REPLY case "$REPLY" in yes|YES|y|Y) OK=1 ;; no|NO|n|N) log "Aborting build." exit 1 ;; *) log "Please answer 'yes' or 'no'." ;; esac done } function build_image() { docker build --platform $PLATFORM $NO_CACHE $@ } function tag_image() { local IMAGE="$1" local IMAGE_NO_TAG="${IMAGE%:*}" local IMAGE_TAG="${IMAGE##*:}" for TAG in "${TAGS[@]}"; do # skip if the tag is the same as the image tag if [ "$TAG" == "$IMAGE_TAG" ]; then continue fi log "Tagging $IMAGE with tag $TAG" docker tag $IMAGE $IMAGE_NO_TAG:$TAG done } function push_image() { if [ -z "$PUSH" ]; then return 0 fi local IMAGE="$1" local IMAGE_NO_TAG="${IMAGE%:*}" for TAG in "${TAGS[@]}"; do log "Pushing $IMAGE_NO_TAG:$TAG to registry" docker push $IMAGE_NO_TAG:$TAG done } # -------------------------------------------------------------------- if [ -z "$PLATFORM" ]; then PLATFORM="linux/amd64" fi log "Using platform: $PLATFORM" if [ -z "$IMAGE" ]; then IMAGE="ghcr.io/m1k1o/neko" fi log "Using image: $IMAGE" if [ -z "$TAG" ]; then TAG="latest" TAGS=($TAG) fi for TAG in "${TAGS[@]}"; do log "Using tag: $TAG" done if [ -z "$FLAVOR" ]; then log "No flavor specified, building without flavor" else log "Using flavor: $FLAVOR" fi if [ -z "$BASE_IMAGE" ]; then if [ -z "$FLAVOR" ]; then BASE_IMAGE="$IMAGE/base:$TAG" else BASE_IMAGE="$IMAGE/$FLAVOR-base:$TAG" fi fi # -------------------------------------------------------------------- if [ ! -z "$APPLICATION" ]; then log "Building application: $APPLICATION" log "Using base image: $BASE_IMAGE" # check if application directory exists APPLICATION_DIR="apps/$APPLICATION" if [ ! -d "$APPLICATION_DIR" ]; then log "Application directory $APPLICATION_DIR does not exist." exit 1 fi # flavor is specified, append it to the image name and Dockerfile APPLICATION_IMAGE="$IMAGE/$APPLICATION:$TAG" APPLICATION_DOCKERFILE="apps/$APPLICATION/Dockerfile" if [ ! -z "$FLAVOR" ]; then APPLICATION_IMAGE="$IMAGE/$FLAVOR-$APPLICATION" # if application flavor is specified and Dockerfile exists, use it if [ -f "$APPLICATION_DIR/Dockerfile.$FLAVOR" ]; then APPLICATION_DOCKERFILE="$APPLICATION_DIR/Dockerfile.$FLAVOR" fi fi prompt "Are you sure you want to build $APPLICATION_IMAGE from $APPLICATION_DOCKERFILE?" log "Building $APPLICATION_IMAGE image from $APPLICATION_DOCKERFILE" build_image \ --build-arg="BASE_IMAGE=$BASE_IMAGE" \ -t $APPLICATION_IMAGE \ -f $APPLICATION_DOCKERFILE \ $APPLICATION_DIR tag_image $APPLICATION_IMAGE push_image $APPLICATION_IMAGE exit 0 fi # -------------------------------------------------------------------- prompt "Are you sure you want to build $BASE_IMAGE?" log "Building base image: $BASE_IMAGE" log "[STAGE 1]: Building neko-xorg-deps image" build_image -t neko-xorg-deps runtime/xorg-deps/ log "[STAGE 2]: Building neko-server image" build_image -t neko-server server/ log "[STAGE 3]: Building neko-client image" build_image -t neko-client client/ if [ -z "$FLAVOR" ]; then RUNTIME_IMAGE="neko-runtime" log "[STAGE 4]: Building $RUNTIME_IMAGE image" build_image -t $RUNTIME_IMAGE runtime/ else RUNTIME_IMAGE="neko-$FLAVOR-runtime" log "[STAGE 4]: Building $RUNTIME_IMAGE image" build_image -t $RUNTIME_IMAGE -f runtime/Dockerfile.$FLAVOR runtime/ fi log "[STAGE 5]: Building $BASE_IMAGE image" build_image -t $BASE_IMAGE -f - . <