diff --git a/Makefile b/Makefile index 0ba5017..e3ce322 100644 --- a/Makefile +++ b/Makefile @@ -8,8 +8,10 @@ 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) +DEV_UID ?= $(shell id -u 2>/dev/null || echo 1000) +DEV_GID ?= $(shell id -g 2>/dev/null || echo 1000) +export DEV_UID +export DEV_GID # Default target all: build @@ -123,11 +125,11 @@ docker-down: docker-dev: @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 + 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 + docker compose -f docker-compose.dev.yml up -d --build # Stop Docker dev environment (preserves cached volumes for fast restart) docker-dev-down: diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 5187a3f..e252571 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -8,15 +8,16 @@ services: - "8052:8052" - "5173:5173" volumes: - - .:/app + - .:/app:Z - baihu-envs:/app/envs - baihu-node-modules:/app/web/node_modules - - go-mod-cache:/go/pkg/mod - - npm-cache:/root/.npm + - go-path:/go + - npm-cache:/var/cache/npm environment: - TZ=Asia/Shanghai - - DEV_UID=${UID:-1000} - - DEV_GID=${GID:-1000} + - DEV_UID=${DEV_UID:-1000} + - DEV_GID=${DEV_GID:-1000} + - MISE_YES=1 # Auto-confirm mise prompts stdin_open: true tty: true @@ -25,7 +26,7 @@ volumes: name: baihu_dev_envs baihu-node-modules: name: baihu_dev_node_modules - go-mod-cache: - name: baihu_dev_go_cache + go-path: + name: baihu_dev_go_path npm-cache: name: baihu_dev_npm_cache diff --git a/docker/Dockerfile.dev b/docker/Dockerfile.dev index 0474861..922d2cb 100644 --- a/docker/Dockerfile.dev +++ b/docker/Dockerfile.dev @@ -34,7 +34,7 @@ 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 +ENV NPM_CONFIG_CACHE=/var/cache/npm COPY docker/docker-entrypoint-dev.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker-entrypoint-dev.sh diff --git a/docker/docker-entrypoint-dev.sh b/docker/docker-entrypoint-dev.sh index 2b16bdb..063f6a4 100644 --- a/docker/docker-entrypoint-dev.sh +++ b/docker/docker-entrypoint-dev.sh @@ -10,30 +10,74 @@ log() { printf "${COLOR_PREFIX} %s\n" "$1" } +ensure_cache_ownership() { + local dir="$1" + local target_uid="$2" + local target_gid="$3" + if [ ! -d "$dir" ]; then + mkdir -p "$dir" + chown "$target_uid:$target_gid" "$dir" + return + fi + local current_uid=$(stat -c '%u' "$dir") + local dirty_file=$(find "$dir" -mindepth 1 ! -uid "$target_uid" -print -quit 2>/dev/null) + if [ "$current_uid" == "$target_uid" ] && [ -z "$dirty_file" ]; then + log "Cache hit: $dir owned by $target_uid. Reusing." + else + if [ -n "$dirty_file" ]; then + log "Dirty cache detected in $dir (Found root-owned files like $dirty_file)." + else + log "User changed ($current_uid -> $target_uid). Resetting cache in $dir..." + fi + + log "Nuking directory to ensure clean state..." + + find "$dir" -mindepth 1 -delete 2>/dev/null || rm -rf "$dir"/* + + chown "$target_uid:$target_gid" "$dir" + log "Cache reset complete. Ownership transferred to $target_uid." + fi +} + 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 +EXISTING_USER=$(getent passwd "$DEV_UID" | cut -d: -f1 | head -n 1) - echo "devuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/devuser - chmod 0440 /etc/sudoers.d/devuser +if [ -n "$EXISTING_USER" ]; then + TARGET_USER="$EXISTING_USER" + log "UID $DEV_UID already exists as user '$TARGET_USER'. Using existing user." +else + TARGET_USER="devuser" + log "Creating user '$TARGET_USER' (UID: $DEV_UID, GID: $DEV_GID)..." + groupadd -o -g "$DEV_GID" devgroup + useradd -o -u "$DEV_UID" -g "$DEV_GID" -m -s /bin/bash "$TARGET_USER" fi -chown devuser:devgroup /app/envs /app/web/node_modules /go/pkg/mod 2>/dev/null || true +if [ "$TARGET_USER" != "root" ]; then + echo "$TARGET_USER ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$TARGET_USER + chmod 0440 /etc/sudoers.d/$TARGET_USER +fi + +export npm_config_cache=/var/cache/npm +mkdir -p /var/cache/npm /app/web/node_modules +chown "$DEV_UID:$DEV_GID" /var/cache/npm /app/web/node_modules + +if [ "$DEV_UID" != "0" ]; then + ensure_cache_ownership "/app/envs" "$DEV_UID" "$DEV_GID" + ensure_cache_ownership "/app/web/node_modules" "$DEV_UID" "$DEV_GID" + ensure_cache_ownership "/var/cache/npm" "$DEV_UID" "$DEV_GID" + ensure_cache_ownership "/go" "$DEV_UID" "$DEV_GID" +fi 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 +rsync -a --chown="$DEV_UID:$DEV_GID" --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" @@ -45,5 +89,5 @@ 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 "$@" +log "Environment ready! Starting command as user '$TARGET_USER' (UID: $DEV_UID)..." +exec gosu "$DEV_UID:$DEV_GID" "$@"