@echo off setlocal DisableDelayedExpansion if defined DMS_GIT_AUTH_MODE goto git_auth rem Run on a Windows deployment server with Git and Docker Linux containers. rem No token, AI login, or model data is embedded in this file. if /I "%~1"=="--help" goto help set "DMS_REPOSITORY=https://gitea.hmac.kr/is-div/design-model-box-sample_2.git" set "DMS_SERVICE_URL=http://10.14.12.22/box-sample" set "DMS_HOST_PORT=5092" set "DMS_BIND_IP=0.0.0.0" set "DMS_GITEA_USERNAME=Hyein" set "DMS_GITEA_TOKEN_FILE=%~dp0gitea-token.txt" set "DMS_AI_AUTH_FILE=%~dp0codex-auth.json" set "GIT_ASKPASS=%~f0" set "GIT_TERMINAL_PROMPT=0" set "DMS_DEPLOY_SOURCE=%~dp0deploy-source" set "DMS_COMPOSE_FILE=" set "DMS_FAILED_STEP=prerequisite check" where git >nul 2>&1 if errorlevel 1 goto failed where docker >nul 2>&1 if errorlevel 1 goto failed where powershell >nul 2>&1 if errorlevel 1 goto failed docker compose version >nul 2>&1 if errorlevel 1 goto failed docker info >nul 2>&1 if errorlevel 1 goto failed echo Repository: %DMS_REPOSITORY% echo This script runs HERE, not on a remote server. echo Run this file ON deployment server 10.14.12.22, not on your personal PC. echo Intended public service: %DMS_SERVICE_URL% echo Server port: %DMS_HOST_PORT% - prefix gateway: 8080 - internal application: 8097 echo Requires approved intranet firewall and access controls. echo Seven shared saved models are installed from the repository cache bundle. echo Existing server work is preserved. AI credentials are NOT downloaded. set "DMS_FAILED_STEP=deployment server address check" powershell -NoProfile -NonInteractive -Command "if (@(Get-NetIPAddress -AddressFamily IPv4 -ErrorAction Stop).IPAddress -notcontains '10.14.12.22') {Write-Error 'Run this file on deployment server 10.14.12.22, not on your local PC.'; exit 1}" if errorlevel 1 goto failed set "DMS_FAILED_STEP=source download or update" if not exist "%DMS_GITEA_TOKEN_FILE%" ( echo Missing private gitea-token.txt beside this script. Never upload that file to Git. goto failed ) set "DMS_GIT_AUTH_MODE=1" if exist "%DMS_DEPLOY_SOURCE%" goto update git -c credential.helper= clone -- "%DMS_REPOSITORY%" "%DMS_DEPLOY_SOURCE%" if errorlevel 1 goto failed goto source_ready :update if not exist "%DMS_DEPLOY_SOURCE%\.git" ( echo Destination exists but is not the deployment clone. Nothing was overwritten. goto failed ) set "DMS_FAILED_STEP=repository origin verification" rem Capture Git output directly; do not depend on CMD pipe/findstr encoding. powershell -NoProfile -NonInteractive -Command "$ErrorActionPreference='Stop'; $lines=@(& git -C $env:DMS_DEPLOY_SOURCE remote get-url origin); if ($LASTEXITCODE -ne 0) {Write-Host 'Git could not read origin.'; exit 2}; if ($lines.Count -ne 1) {Write-Host 'Expected one origin URL.'; exit 3}; $actual=([string]$lines[0]).Trim(); $expected=$env:DMS_REPOSITORY.Trim(); if (-not [string]::Equals($actual,$expected,[StringComparison]::Ordinal)) {Write-Host 'Origin URL differs from the configured repository. No change made.'; exit 4}; Write-Host 'Repository origin verified.'" if errorlevel 1 ( echo Repository origin verification failed. Nothing was overwritten. goto failed ) set "DMS_FAILED_STEP=source download or update" git -C "%DMS_DEPLOY_SOURCE%" status --porcelain >nul if errorlevel 1 goto failed for /f "delims=" %%S in ('git -C "%DMS_DEPLOY_SOURCE%" status --porcelain') do ( echo Deployment clone has local changes. Preserve or resolve them before deploying. goto failed ) git -c credential.helper= -C "%DMS_DEPLOY_SOURCE%" pull --ff-only if errorlevel 1 goto failed :source_ready set "DMS_GIT_AUTH_MODE=" if not exist "%DMS_DEPLOY_SOURCE%\Dockerfile" goto failed if not exist "%DMS_DEPLOY_SOURCE%\compose.yaml" goto failed if not exist "%DMS_DEPLOY_SOURCE%\deployment\subpath_gateway.py" goto failed if not exist "%DMS_DEPLOY_SOURCE%\deployment\configure-caddy.ps1" goto failed set "DMS_FAILED_STEP=Caddy administration preflight" powershell -NoProfile -NonInteractive -Command "$ErrorActionPreference='Stop'; Invoke-WebRequest -UseBasicParsing -Uri 'http://localhost:2019/config/' -TimeoutSec 10 | Out-Null" if errorlevel 1 goto failed echo Deploying commit: git -C "%DMS_DEPLOY_SOURCE%" rev-parse HEAD set "DMS_FAILED_STEP=temporary Compose configuration" for /f "delims=" %%T in ('powershell -NoProfile -NonInteractive -Command "[System.IO.Path]::GetTempFileName()"') do set "DMS_COMPOSE_FILE=%%T" if not defined DMS_COMPOSE_FILE goto failed rem A separate Compose file replaces the original localhost port mapping. rem A fixed project name keeps the named data volume stable across updates. >"%DMS_COMPOSE_FILE%" ( echo services: echo studio: echo build: echo context: "${DMS_DEPLOY_CONTEXT}" echo ports: echo - "${DMS_BIND_IP}:${DMS_HOST_PORT}:8080" echo command: ["python", "deployment/subpath_gateway.py"] echo environment: echo DMS_DATA_DIR: /data echo volumes: echo - studio-data:/data echo - studio-ai-auth:/root/.codex echo restart: unless-stopped echo volumes: echo studio-data: echo studio-ai-auth: ) set "DMS_DEPLOY_CONTEXT=%DMS_DEPLOY_SOURCE:\=/%" docker compose -p drawing-model-studio --project-directory "%DMS_DEPLOY_SOURCE%" -f "%DMS_COMPOSE_FILE%" config --quiet if errorlevel 1 goto failed set "DMS_FAILED_STEP=image build" docker compose -p drawing-model-studio --project-directory "%DMS_DEPLOY_SOURCE%" -f "%DMS_COMPOSE_FILE%" build if errorlevel 1 goto failed set "DMS_FAILED_STEP=container start" docker compose -p drawing-model-studio --project-directory "%DMS_DEPLOY_SOURCE%" -f "%DMS_COMPOSE_FILE%" up -d --no-build if errorlevel 1 goto failed set "DMS_FAILED_STEP=HTTP readiness check" if not exist "%DMS_AI_AUTH_FILE%" goto ai_auth_check set "DMS_FAILED_STEP=private AI authentication import" docker compose -p drawing-model-studio --project-directory "%DMS_DEPLOY_SOURCE%" -f "%DMS_COMPOSE_FILE%" exec -T studio python deployment/install_ai_auth.py < "%DMS_AI_AUTH_FILE%" if errorlevel 1 goto failed :ai_auth_check set "DMS_FAILED_STEP=AI authentication status check" docker compose -p drawing-model-studio --project-directory "%DMS_DEPLOY_SOURCE%" -f "%DMS_COMPOSE_FILE%" exec -T studio codex login status if errorlevel 1 ( echo AI login is not ready. Place your private codex-auth.json beside this launcher and run again. goto failed ) set "DMS_FAILED_STEP=HTTP readiness check" powershell -NoProfile -NonInteractive -Command "$url='http://127.0.0.1:'+$env:DMS_HOST_PORT+'/box-sample/'; for ($i=0; $i -lt 30; $i++) {try {$r=Invoke-WebRequest -UseBasicParsing -Uri $url -TimeoutSec 5; if ($r.StatusCode -eq 200 -and $r.Headers['X-DMS-Deployment'] -eq 'box-sample') {exit 0}} catch {}; Start-Sleep -Seconds 2}; exit 1" if errorlevel 1 goto failed set "DMS_FAILED_STEP=Caddy service route and public URL verification" powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%DMS_DEPLOY_SOURCE%\deployment\configure-caddy.ps1" if errorlevel 1 goto failed docker compose -p drawing-model-studio --project-directory "%DMS_DEPLOY_SOURCE%" -f "%DMS_COMPOSE_FILE%" ps del /q "%DMS_COMPOSE_FILE%" echo HTTP page responds on server port %DMS_HOST_PORT%. echo Direct server URL: http://10.14.12.22:%DMS_HOST_PORT%/box-sample/ echo Verified public URL: %DMS_SERVICE_URL%/ echo AI login is recognized. Network access, DWG conversion and actual model generation need separate verification. echo Keep codex-auth.json and gitea-token.txt private. Never commit or publicly share them. echo This script does not configure HTTPS, firewall rules or automatic Gitea triggers. start "" "%DMS_SERVICE_URL%/" pause exit /b 0 :failed echo FAILED: %DMS_FAILED_STEP%. echo No data volume was deleted. No automatic rollback was attempted. echo If container start failed, inspect Docker status/logs before retrying. if defined DMS_COMPOSE_FILE if exist "%DMS_COMPOSE_FILE%" del /q "%DMS_COMPOSE_FILE%" pause exit /b 1 :help echo Usage: deploy-server.bat echo Run on a Windows deployment server with Git, PowerShell and Docker Compose. echo Uses Docker Linux containers and downloads the Gitea default branch. echo Target server: 10.14.12.22 - published port: 5092 - prefix gateway: 8080. echo Intended public service: http://10.14.12.22/box-sample/ echo Refuses deployment when the target IP is not assigned to this Windows host. echo Configures only the /box-sample route through the existing local Caddy admin API. echo Stops on unavailable administration or conflicting/shared authentication rules. echo Gitea login reads private gitea-token.txt beside this script. Never commit the token file. echo First AI setup imports private codex-auth.json into a persistent server-only volume. echo Updated server AI credentials are preserved on later deployments. echo Run again to fast-forward the clean deployment clone and rebuild. echo Keep this file in the same directory between deployments. echo No automatic deployment occurs when Gitea changes. exit /b 0 :git_auth set "DMS_GIT_AUTH_PROMPT=%~1" powershell -NoProfile -NonInteractive -Command "if ($env:DMS_GIT_AUTH_PROMPT -match '^Username') {[Console]::WriteLine($env:DMS_GITEA_USERNAME); exit 0}; if ($env:DMS_GIT_AUTH_PROMPT -notmatch '^Password') {exit 1}; if (-not (Test-Path -LiteralPath $env:DMS_GITEA_TOKEN_FILE -PathType Leaf)) {exit 1}; $token=[IO.File]::ReadAllText($env:DMS_GITEA_TOKEN_FILE).Trim(); if ([string]::IsNullOrWhiteSpace($token)) {exit 1}; [Console]::WriteLine($token)" exit /b %errorlevel%