- Code\rebar_pipeline, review_pipeline, pier-program을 정션에서 실제 폴더로 전환 - Code\rhino_mcp 및 CLAUDE_rhino배경.md 추가, .mcp.json은 PYTHONPATH로 새 위치 사용 - pier-program 내부 .git 제거(이력은 backup\pier-program_20261028.bundle에 보관) - worktree 가이드 반영(CLAUDE.local.md, HANDOFF.md) - D:\Rhino-MCP 경로 참조를 새 위치로 치환 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
175 lines
9.3 KiB
Batchfile
175 lines
9.3 KiB
Batchfile
@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%
|