diff --git a/.air.toml b/.air.toml index f726a58..967176e 100644 --- a/.air.toml +++ b/.air.toml @@ -4,7 +4,7 @@ tmp_dir = "bin" [build] args_bin = [] - bin = "./bin/baihu" + entrypoint = "./bin/baihu" cmd = ":" full_bin = "go run main.go server" delay = 1000 diff --git a/Makefile b/Makefile index c491bf0..0ba5017 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,9 @@ VERSION=$(shell git describe --tags --always --dirty 2>/dev/null || echo "dev") BUILD_TIME=$(shell date '+%Y/%m/%d %H:%M:%S') LDFLAGS=-ldflags="-s -w -X 'github.com/engigu/baihu-panel/internal/constant.Version=$(VERSION)' -X 'github.com/engigu/baihu-panel/internal/constant.BuildTime=$(BUILD_TIME)'" +HOST_UID := $(shell id -u 2>/dev/null || echo 1000) +HOST_GID := $(shell id -g 2>/dev/null || echo 1000) + # Default target all: build @@ -68,6 +71,10 @@ clean: mkdir -p web/dist touch web/dist/.gitkeep +# Clean everything: local artifacts and Docker development environment (including volumes) +clean-all: clean docker-dev-clean + @echo "All local artifacts and Docker dev caches have been completely wiped." + # Run the application run: @mkdir -p bin @@ -77,6 +84,7 @@ run: # Development run with hot reload (both frontend and backend) dev: @command -v concurrently > /dev/null 2>&1 || npm install -g concurrently + @mkdir -p envs web/node_modules concurrently --kill-others \ "go tool air" \ "cd web && npm ci && npm run dev" @@ -105,30 +113,48 @@ docker-run: # Docker compose up docker-up: - docker-compose up -d + docker compose up -d # Docker compose down docker-down: - docker-compose down + docker compose down -# Build and run in development mode (foreground with logs) +# Start isolated Docker dev environment (foreground with logs, Ctrl+C to stop) docker-dev: - docker-compose down - docker-compose build - docker-compose up + @command -v concurrently > /dev/null 2>&1 || npm install -g concurrently + @mkdir -p envs web/node_modules + UID=$(HOST_UID) GID=$(HOST_GID) docker compose -f docker-compose.dev.yml up --build + +# Start isolated Docker dev environment (background) +docker-dev-d: + UID=$(HOST_UID) GID=$(HOST_GID) docker compose -f docker-compose.dev.yml up -d --build + +# Stop Docker dev environment (preserves cached volumes for fast restart) +docker-dev-down: + docker compose -f docker-compose.dev.yml down + +# Stop and completely clean Docker dev environment (removes all cached volumes) +# Use this if your environment is broken or you want a fresh start +docker-dev-clean: + docker compose -f docker-compose.dev.yml down -v # Help help: @echo "Available targets:" - @echo " all - Build the application (default)" - @echo " build - Build the application" - @echo " build-agent - Build agent packages (tar.gz) for all platforms" - @echo " clean - Clean built files" - @echo " run - Run the application" - @echo " deps - Install dependencies" - @echo " docker-build - Build Docker image" - @echo " docker-run - Run Docker container" - @echo " docker-up - Start Docker Compose stack" - @echo " docker-down - Stop Docker Compose stack" - @echo " docker-dev - Build and run Docker Compose in foreground" - @echo " help - Show this help message" + @echo " all - Build the application (default)" + @echo " build - Build the application" + @echo " build-agent - Build agent packages (tar.gz) for all platforms" + @echo " clean - Clean built files" + @echo " clean-all - Clean local files and Docker dev environment (including volumes)" + @echo " run - Run the application locally" + @echo " dev - Run local development with hot reload" + @echo " deps - Install Go dependencies" + @echo " docker-build - Build production Docker image" + @echo " docker-run - Run production Docker container" + @echo " docker-up - Start production Docker Compose stack" + @echo " docker-down - Stop production Docker Compose stack" + @echo " docker-dev - Start isolated Docker dev environment (foreground)" + @echo " docker-dev-d - Start isolated Docker dev environment (background)" + @echo " docker-dev-down - Stop Docker dev environment (keep caches)" + @echo " docker-dev-clean - Stop and clean Docker dev environment (remove caches)" + @echo " help - Show this help message" diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..5187a3f --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,31 @@ +services: + baihu-dev: + build: + context: . + dockerfile: docker/Dockerfile.dev + container_name: baihu-dev + ports: + - "8052:8052" + - "5173:5173" + volumes: + - .:/app + - baihu-envs:/app/envs + - baihu-node-modules:/app/web/node_modules + - go-mod-cache:/go/pkg/mod + - npm-cache:/root/.npm + environment: + - TZ=Asia/Shanghai + - DEV_UID=${UID:-1000} + - DEV_GID=${GID:-1000} + stdin_open: true + tty: true + +volumes: + baihu-envs: + name: baihu_dev_envs + baihu-node-modules: + name: baihu_dev_node_modules + go-mod-cache: + name: baihu_dev_go_cache + npm-cache: + name: baihu_dev_npm_cache diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev new file mode 100644 index 0000000..0474861 --- /dev/null +++ b/docker/Dockerfile.dev @@ -0,0 +1,48 @@ +FROM golang:1.25-trixie + +ENV TZ=Asia/Shanghai +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 + +ENV NODE_VERSION=23 +ENV PYTHON_VERSION=3.13 + +RUN sed -i 's@deb.debian.org@mirrors.tuna.tsinghua.edu.cn@g' /etc/apt/sources.list.d/debian.sources \ + && sed -i 's@security.debian.org@mirrors.tuna.tsinghua.edu.cn@g' /etc/apt/sources.list.d/debian.sources \ + && echo "${TZ}" > /etc/timezone \ + && ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + sudo gosu tzdata git curl wget vim htop ca-certificates rsync \ + && BUILD_DEPS="gcc build-essential libssl-dev zlib1g-dev libbz2-dev \ + libreadline-dev libsqlite3-dev libncursesw5-dev \ + xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev" \ + && apt-get install -y --no-install-recommends $BUILD_DEPS \ + && rm -rf /var/lib/apt/lists/* + +RUN go env -w GOPROXY=https://goproxy.cn,direct + +ENV MISE_GLOBAL_DIR=/opt/mise-dev +ENV PATH="/opt/mise-dev/shims:/opt/mise-dev/bin:$PATH" +RUN curl https://mise.run | MISE_INSTALL_PATH=/usr/local/bin/mise sh \ + && MISE_DATA_DIR=/opt/mise-dev MISE_CONFIG_DIR=/opt/mise-dev MISE_HTTP_TIMEOUT=300 \ + PYTHON_BUILD_MIRROR_URL=https://pyenv.pages.dev/api/mirror/binaries \ + mise use -g node@${NODE_VERSION} python@${PYTHON_VERSION} \ + && mise prune -- -f + +ENV MISE_DATA_DIR=/app/envs/mise +ENV MISE_CONFIG_DIR=/app/envs/mise +ENV PATH="/app/envs/mise/shims:/app/envs/mise/bin:$PATH" + +RUN mkdir -p /go/pkg/mod /root/.npm /app/web/node_modules + +COPY docker/docker-entrypoint-dev.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/docker-entrypoint-dev.sh + +WORKDIR /app + +EXPOSE 8052 5173 + +ENTRYPOINT ["docker-entrypoint-dev.sh"] + +CMD ["make", "dev"] diff --git a/docker/docker-entrypoint-dev.sh b/docker/docker-entrypoint-dev.sh new file mode 100644 index 0000000..2b16bdb --- /dev/null +++ b/docker/docker-entrypoint-dev.sh @@ -0,0 +1,49 @@ +#!/bin/bash +set -e +export LANG=C.UTF-8 +export LC_ALL=C.UTF-8 + +export MISE_HIDE_UPDATE_WARNING=1 + +COLOR_PREFIX="\033[1;36m[Entrypoint]\033[0m" +log() { + printf "${COLOR_PREFIX} %s\n" "$1" +} + +log "Initializing Development Environment..." + +DEV_UID=${DEV_UID:-1000} +DEV_GID=${DEV_GID:-1000} + +if ! id -u devuser >/dev/null 2>&1; then + log "Creating user 'devuser' (UID: $DEV_UID, GID: $DEV_GID)..." + groupadd -o -g "$DEV_GID" devgroup + useradd -o -u "$DEV_UID" -g "$DEV_GID" -m -s /bin/bash devuser + + echo "devuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/devuser + chmod 0440 /etc/sudoers.d/devuser +fi + +chown devuser:devgroup /app/envs /app/web/node_modules /go/pkg/mod 2>/dev/null || true + +MISE_DIR="/app/envs/mise" +mkdir -p "$MISE_DIR" +log "Syncing mise environment from base..." +rsync -a --ignore-existing /opt/mise-dev/ "$MISE_DIR" || true +log "Mise environment synced" + +chown -R ${DEV_UID}:${DEV_GID} /opt/mise-dev /go /root/.npm /app + +export MISE_DATA_DIR="$MISE_DIR" +export MISE_CONFIG_DIR="$MISE_DIR" +export PATH="$MISE_DIR/shims:$MISE_DIR/bin:$PATH" + +export PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple + +log "mise version: $(mise --version 2>/dev/null | head -n 1)" +log "python: $(python --version 2>&1 | head -n 1) at $(which python)" +log "node: $(node --version 2>&1 | head -n 1) at $(which node)" +log "npm: $(npm --version 2>&1 | head -n 1) at $(which npm)" + +log "Environment ready! Starting make dev..." +exec gosu devuser "$@"