115 lines
3.2 KiB
Bash
Executable File
115 lines
3.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Build HTKnow on a server without installing Node.js or Rust on the host.
|
|
#
|
|
# Examples:
|
|
# ./build-docker.sh
|
|
# ./build-docker.sh --tag gwknow:v0.0.2
|
|
# ./build-docker.sh --skip-frontend --tag gwknow:v0.0.3
|
|
# IMAGE_TAG=v0.0.3 ./build-docker.sh
|
|
|
|
set -Eeuo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$ROOT_DIR"
|
|
|
|
NODE_IMAGE="${NODE_IMAGE:-docker.1ms.run/node:22}"
|
|
RUST_BUILDER_IMAGE="${RUST_BUILDER_IMAGE:-htknow-rust-builder:bookworm}"
|
|
SKIP_FRONTEND=false
|
|
REBUILD_BUILDER=false
|
|
IMAGE_TAG="${IMAGE_TAG:-}"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: ./build-docker.sh [options]
|
|
|
|
Options:
|
|
--tag IMAGE Target image tag, for example gwknow:v0.0.2.
|
|
--skip-frontend Do not rebuild frontend/dist (safe for Rust-only changes).
|
|
--rebuild-builder Rebuild the cached Rust + protoc builder image.
|
|
-h, --help Show this help.
|
|
|
|
Environment overrides:
|
|
IMAGE_TAG, NODE_IMAGE, RUST_BUILDER_IMAGE
|
|
|
|
If --tag and IMAGE_TAG are omitted, a new gwknow:YYYYmmdd-HHMMSS tag is used.
|
|
EOF
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--tag)
|
|
[[ $# -ge 2 ]] || { echo "--tag requires an image tag" >&2; exit 2; }
|
|
IMAGE_TAG="$2"
|
|
shift 2
|
|
;;
|
|
--skip-frontend|--backend-only)
|
|
SKIP_FRONTEND=true
|
|
shift
|
|
;;
|
|
--rebuild-builder)
|
|
REBUILD_BUILDER=true
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1" >&2
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
command -v docker >/dev/null || { echo "docker is not installed or is not in PATH" >&2; exit 1; }
|
|
docker info >/dev/null 2>&1 || { echo "Docker daemon is unavailable" >&2; exit 1; }
|
|
|
|
if [[ -z "$IMAGE_TAG" ]]; then
|
|
IMAGE_TAG="gwknow:$(date +%Y%m%d-%H%M%S)"
|
|
elif [[ "$IMAGE_TAG" != *:* ]]; then
|
|
IMAGE_TAG="gwknow:${IMAGE_TAG}"
|
|
fi
|
|
|
|
HOST_UID="$(id -u)"
|
|
HOST_GID="$(id -g)"
|
|
mkdir -p .cargo-cache .npm-cache
|
|
|
|
if [[ "$REBUILD_BUILDER" == true ]] || ! docker image inspect "$RUST_BUILDER_IMAGE" >/dev/null 2>&1; then
|
|
echo "==> Building Rust builder image: $RUST_BUILDER_IMAGE"
|
|
docker build -t "$RUST_BUILDER_IMAGE" -f Dockerfile.rust-builder .
|
|
fi
|
|
|
|
if [[ "$SKIP_FRONTEND" == false ]]; then
|
|
echo "==> Building frontend with $NODE_IMAGE"
|
|
docker run --rm \
|
|
--user "${HOST_UID}:${HOST_GID}" \
|
|
-e HOME=/tmp \
|
|
-e npm_config_cache=/npm-cache \
|
|
-v "$ROOT_DIR":/app \
|
|
-v "$ROOT_DIR/.npm-cache":/npm-cache \
|
|
-w /app/frontend \
|
|
"$NODE_IMAGE" \
|
|
sh -c 'npm ci && npm run build'
|
|
else
|
|
echo "==> Skipping frontend build (--skip-frontend)"
|
|
fi
|
|
|
|
echo "==> Building Rust release binary with $RUST_BUILDER_IMAGE"
|
|
docker run --rm \
|
|
--user "${HOST_UID}:${HOST_GID}" \
|
|
-e HOME=/tmp \
|
|
-e CARGO_HOME=/cargo-cache \
|
|
-v "$ROOT_DIR":/app \
|
|
-v "$ROOT_DIR/.cargo-cache":/cargo-cache \
|
|
-w /app \
|
|
"$RUST_BUILDER_IMAGE" \
|
|
bash -c 'cargo build --locked --release'
|
|
|
|
echo "==> Building runtime image: $IMAGE_TAG"
|
|
docker build -f Dockerfile -t "$IMAGE_TAG" .
|
|
|
|
echo
|
|
echo "Build complete: $IMAGE_TAG"
|
|
echo "To deploy, update the compose image tag and recreate only the intended service."
|