set -euo pipefail
source ../scripts/build-template
function property {
if [[ ! -f "${PROPERTIES}" ]]; then
echo "Error: Properties file ${PROPERTIES} not found" >&2
exit 1
fi
grep "^${1}" "${PROPERTIES}" | cut -d'=' -f2
}
readonly BUILD_DIR=build
readonly PROPERTIES="${SCRIPT_DIR}/../src/main/resources/com/keenwrite/messages.properties"
readonly CONTAINER_EXE=podman
readonly CONTAINER_SHORTNAME=$(property Wizard.typesetter.container.image.name)
readonly CONTAINER_VERSION=$(property Wizard.typesetter.container.image.version)
readonly CONTAINER_NETWORK=host
readonly CONTAINER_IMAGE_FILE="${CONTAINER_SHORTNAME}-${CONTAINER_VERSION}"
readonly CONTAINER_IMAGE_PATH="${BUILD_DIR}/${CONTAINER_IMAGE_FILE}"
readonly CONTAINER_ARCHIVE_FILE="${CONTAINER_IMAGE_FILE}.tar"
readonly CONTAINER_ARCHIVE_PATH="${BUILD_DIR}/${CONTAINER_ARCHIVE_FILE}"
readonly CONTAINER_COMPRESSED_FILE="${CONTAINER_ARCHIVE_FILE}.gz"
readonly CONTAINER_COMPRESSED_PATH="${BUILD_DIR}/${CONTAINER_COMPRESSED_FILE}"
readonly CONTAINER_DIR_SOURCE="/root/source"
readonly CONTAINER_DIR_TARGET="/root/target"
readonly CONTAINER_DIR_IMAGES="/root/images"
readonly CONTAINER_DIR_FONTS="/root/fonts"
ARG_CONTAINER_NAME="${CONTAINER_SHORTNAME}:${CONTAINER_VERSION}"
ARG_CONTAINER_COMMAND="context --version"
ARG_MOUNTPOINT_SOURCE=""
ARG_MOUNTPOINT_TARGET="."
ARG_MOUNTPOINT_IMAGES=""
ARG_MOUNTPOINT_FONTS="${HOME}/.fonts"
DEPENDENCIES=(
"podman,https://podman.io"
"tar,https://www.gnu.org/software/tar"
"bzip2,https://gitlab.com/bzip2/bzip2"
)
ARGUMENTS+=(
"b,build,Build container"
"c,connect,Connect to container"
"d,delete,Remove all containers"
"s,source,Set mount point for input document (before typesetting)"
"t,target,Set mount point for output file (after typesetting)"
"i,images,Set mount point for image files (to typeset)"
"f,fonts,Set mount point for font files (during typesetting)"
"l,load,Load container (${CONTAINER_COMPRESSED_PATH})"
"p,publish,Publish the container"
"r,run,Run a command in the container (\"${ARG_CONTAINER_COMMAND}\")"
"x,export,Save container (${CONTAINER_COMPRESSED_PATH})"
)
execute() {
${do_delete}
${do_build}
${do_export}
${do_publish}
${do_load}
${do_execute}
${do_connect}
return 1
}
utile_delete() {
[[ -f ${CONTAINER_IMAGE_PATH} ]] && \
$log "Deleting ${CONTAINER_IMAGE_PATH}"; \
rm -f "${CONTAINER_IMAGE_PATH}"
$log "Deleting all containers"
${CONTAINER_EXE} rmi --all --force > /dev/null || true
$log "Containers deleted"
}
utile_build() {
$log "Building container version ${CONTAINER_VERSION}"
mkdir -p "${ARG_MOUNTPOINT_FONTS}"
${CONTAINER_EXE} build \
--network="${CONTAINER_NETWORK}" \
--squash \
-t "${ARG_CONTAINER_NAME}" . | \
grep ^STEP || true
}
utile_publish() {
local -r HOST_PATH="host-path.txt"
if [[ -f "${HOST_PATH}" ]]; then
local -r repository=$(cat "${HOST_PATH}")
local -r remote_file="${CONTAINER_SHORTNAME}:${CONTAINER_VERSION}"
local -r remote_path="${repository}/${remote_file}"
$log "Publishing ${CONTAINER_IMAGE_PATH} to ${remote_path}"
scp -q "${CONTAINER_IMAGE_PATH}" "${remote_path}"
else
error "Create ${HOST_PATH} with path on remote host"
fi
}
get_mountpoint() {
local result=""
local binding="ro"
if [[ -n "${3:-}" ]]; then
binding="Z"
fi
if [[ -n "${1:-}" ]]; then
result="-v ${1}:${2}:${binding}"
fi
echo "${result}"
}
get_mountpoint_source() {
echo "$(get_mountpoint "${ARG_MOUNTPOINT_SOURCE}" "${CONTAINER_DIR_SOURCE}")"
}
get_mountpoint_target() {
echo "$(get_mountpoint "${ARG_MOUNTPOINT_TARGET}" "${CONTAINER_DIR_TARGET}" 1)"
}
get_mountpoint_images() {
echo "$(get_mountpoint "${ARG_MOUNTPOINT_IMAGES}" "${CONTAINER_DIR_IMAGES}")"
}
get_mountpoint_fonts() {
echo "$(get_mountpoint "${ARG_MOUNTPOINT_FONTS}" "${CONTAINER_DIR_FONTS}")"
}
utile_connect() {
$log "Connecting to container"
local mount_source
local mount_target
local mount_images
local mount_fonts
mount_source=$(get_mountpoint_source)
mount_target=$(get_mountpoint_target)
mount_images=$(get_mountpoint_images)
mount_fonts=$(get_mountpoint_fonts)
$log "mount_source = '${mount_source}'"
$log "mount_target = '${mount_target}'"
$log "mount_images = '${mount_images}'"
$log "mount_fonts = '${mount_fonts}'"
local mount_args=()
[[ -n "${mount_source}" ]] && \
read -ra source_parts <<< "${mount_source}" && \
mount_args+=("${source_parts[@]}")
[[ -n "${mount_target}" ]] && \
read -ra target_parts <<< "${mount_target}" && \
mount_args+=("${target_parts[@]}")
[[ -n "${mount_images}" ]] && \
read -ra images_parts <<< "${mount_images}" && \
mount_args+=("${images_parts[@]}")
[[ -n "${mount_fonts}" ]] && \
read -ra fonts_parts <<< "${mount_fonts}" && \
mount_args+=("${fonts_parts[@]}")
[[ -n "${ARG_MOUNTPOINT_SOURCE}" && ! -d "${ARG_MOUNTPOINT_SOURCE}" ]] && \
mkdir -p "${ARG_MOUNTPOINT_SOURCE}"
[[ -n "${ARG_MOUNTPOINT_TARGET}" && ! -d "${ARG_MOUNTPOINT_TARGET}" ]] && \
mkdir -p "${ARG_MOUNTPOINT_TARGET}"
[[ -n "${ARG_MOUNTPOINT_IMAGES}" && ! -d "${ARG_MOUNTPOINT_IMAGES}" ]] && \
mkdir -p "${ARG_MOUNTPOINT_IMAGES}"
[[ -n "${ARG_MOUNTPOINT_FONTS}" && ! -d "${ARG_MOUNTPOINT_FONTS}" ]] && \
mkdir -p "${ARG_MOUNTPOINT_FONTS}"
${CONTAINER_EXE} run \
--network="${CONTAINER_NETWORK}" \
--rm \
-it \
"${mount_args[@]}" \
"${ARG_CONTAINER_NAME}"
}
utile_execute() {
$log "Running \"${ARG_CONTAINER_COMMAND}\":"
${CONTAINER_EXE} run \
--network="${CONTAINER_NETWORK}" \
--rm \
-it \
"${ARG_CONTAINER_NAME}" \
/bin/sh --login -c "${ARG_CONTAINER_COMMAND}"
}
utile_export() {
if [[ -f "${CONTAINER_COMPRESSED_PATH}" ]]; then
warning "${CONTAINER_COMPRESSED_PATH} exists, delete before saving."
else
$log "Saving ${CONTAINER_SHORTNAME} image"
mkdir -p "${BUILD_DIR}"
${CONTAINER_EXE} save \
--quiet \
-o "${CONTAINER_ARCHIVE_PATH}" \
"${ARG_CONTAINER_NAME}"
$log "Compressing to ${CONTAINER_COMPRESSED_PATH}"
gzip "${CONTAINER_ARCHIVE_PATH}"
$log "Renaming to ${CONTAINER_IMAGE_PATH}"
mv "${CONTAINER_COMPRESSED_PATH}" "${CONTAINER_IMAGE_PATH}"
$log "Saved ${CONTAINER_IMAGE_PATH} image"
fi
}
utile_load() {
if [[ -f "${CONTAINER_COMPRESSED_PATH}" ]]; then
$log "Loading ${CONTAINER_SHORTNAME} from ${CONTAINER_COMPRESSED_PATH}"
${CONTAINER_EXE} load \
--quiet \
-i "${CONTAINER_COMPRESSED_PATH}"
$log "Loaded ${CONTAINER_SHORTNAME} image"
else
warning "Missing ${CONTAINER_COMPRESSED_PATH}; use build followed by save"
fi
}
argument() {
local consume=1
case "$1" in
-b|--build)
do_build=utile_build
;;
-c|--connect)
do_connect=utile_connect
;;
-z|--delete)
do_delete=utile_delete
;;
-l|--load)
do_load=utile_load
;;
-i|--images)
if [[ -n "${2:-}" ]]; then
ARG_MOUNTPOINT_IMAGES="$2"
consume=2
fi
;;
-t|--target)
if [[ -n "${2:-}" ]]; then
ARG_MOUNTPOINT_TARGET="$2"
consume=2
fi
;;
-p|--publish)
do_publish=utile_publish
;;
-r|--run)
do_execute=utile_execute
if [[ -n "${2:-}" ]]; then
ARG_CONTAINER_COMMAND="$2"
consume=2
fi
;;
-s|--source)
if [[ -n "${2:-}" ]]; then
ARG_MOUNTPOINT_SOURCE="$2"
consume=2
fi
;;
-x|--export)
do_export=utile_export
;;
esac
return ${consume}
}
do_build=:
do_connect=:
do_delete=:
do_execute=:
do_load=:
do_publish=:
do_export=:
main "$@"