create-entity-server 0.0.9 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/bin/create.js +26 -8
  2. package/package.json +1 -1
  3. package/template/.env.example +20 -3
  4. package/template/configs/database.json +173 -10
  5. package/template/configs/jwt.json +1 -0
  6. package/template/configs/oauth.json +37 -0
  7. package/template/configs/push.json +26 -0
  8. package/template/entities/Account/account_audit.json +4 -5
  9. package/template/entities/README.md +4 -4
  10. package/template/entities/{Auth → System/Auth}/account.json +0 -14
  11. package/template/entities/System/system_audit_log.json +14 -8
  12. package/template/samples/README.md +43 -21
  13. package/template/samples/browser/entity-server-client.js +453 -0
  14. package/template/samples/browser/example.html +498 -0
  15. package/template/samples/entities/01_basic_fields.json +39 -0
  16. package/template/samples/entities/02_types_and_defaults.json +67 -0
  17. package/template/samples/entities/03_hash_and_unique.json +33 -0
  18. package/template/samples/entities/04_fk_and_composite_unique.json +29 -0
  19. package/template/samples/entities/05_cache.json +55 -0
  20. package/template/samples/entities/06_history_and_hard_delete.json +60 -0
  21. package/template/samples/entities/07_license_scope.json +52 -0
  22. package/template/samples/entities/08_hook_sql.json +52 -0
  23. package/template/samples/entities/09_hook_entity.json +65 -0
  24. package/template/samples/entities/10_hook_submit_delete.json +78 -0
  25. package/template/samples/entities/11_hook_webhook.json +84 -0
  26. package/template/samples/entities/12_hook_push.json +73 -0
  27. package/template/samples/entities/13_read_only.json +54 -0
  28. package/template/samples/entities/14_optimistic_lock.json +29 -0
  29. package/template/samples/entities/15_reset_defaults.json +94 -0
  30. package/template/samples/entities/16_isolated_license.json +62 -0
  31. package/template/samples/entities/README.md +91 -0
  32. package/template/samples/flutter/lib/entity_server_client.dart +261 -48
  33. package/template/samples/java/EntityServerClient.java +325 -61
  34. package/template/samples/java/EntityServerExample.java +4 -3
  35. package/template/samples/kotlin/EntityServerClient.kt +261 -45
  36. package/template/samples/node/src/EntityServerClient.js +348 -59
  37. package/template/samples/node/src/example.js +9 -9
  38. package/template/samples/php/ci4/Config/EntityServer.php +14 -0
  39. package/template/samples/php/ci4/Controllers/EntityController.php +202 -0
  40. package/template/samples/php/ci4/Controllers/ProductController.php +16 -76
  41. package/template/samples/php/ci4/Libraries/EntityServer.php +352 -60
  42. package/template/samples/php/laravel/Services/EntityServerService.php +245 -40
  43. package/template/samples/python/entity_server.py +287 -68
  44. package/template/samples/python/example.py +7 -6
  45. package/template/samples/react/src/example.tsx +41 -25
  46. package/template/samples/swift/EntityServerClient.swift +248 -37
  47. package/template/scripts/normalize-entities.sh +10 -10
  48. package/template/scripts/run.ps1 +12 -3
  49. package/template/scripts/run.sh +120 -37
  50. package/template/scripts/update-server.ps1 +160 -4
  51. package/template/scripts/update-server.sh +132 -4
  52. package/template/samples/react/src/api/entityServerClient.ts +0 -290
  53. package/template/samples/react/src/hooks/useEntity.ts +0 -105
  54. /package/template/entities/{Auth → System/Auth}/api_keys.json +0 -0
  55. /package/template/entities/{Auth → System/Auth}/license.json +0 -0
  56. /package/template/entities/{Auth → System/Auth}/rbac_roles.json +0 -0
@@ -11,6 +11,10 @@ DATABASE_CONFIG="$PROJECT_ROOT/configs/database.json"
11
11
  RUN_DIR="$PROJECT_ROOT/.run"
12
12
  PID_FILE="$RUN_DIR/entity-server.pid"
13
13
  STDOUT_LOG="$PROJECT_ROOT/logs/server.out.log"
14
+ SERVER_BIN="$PROJECT_ROOT/bin/entity-server"
15
+ if [ ! -f "$SERVER_BIN" ] && [ -f "$PROJECT_ROOT/entity-server" ]; then
16
+ SERVER_BIN="$PROJECT_ROOT/entity-server"
17
+ fi
14
18
 
15
19
  mkdir -p "$RUN_DIR" "$PROJECT_ROOT/logs"
16
20
 
@@ -25,6 +29,22 @@ get_server_value() {
25
29
  local fallback="$2"
26
30
  local value
27
31
 
32
+ if [ "$key" = "port" ]; then
33
+ local env_port
34
+ env_port="${SERVER_PORT:-${PORT:-}}"
35
+ if [ -z "$env_port" ] && [ -f .env ]; then
36
+ env_port=$(grep '^SERVER_PORT=' .env | tail -n 1 | cut -d '=' -f2-)
37
+ if [ -z "$env_port" ]; then
38
+ env_port=$(grep '^PORT=' .env | tail -n 1 | cut -d '=' -f2-)
39
+ fi
40
+ fi
41
+ env_port=$(echo "$env_port" | tr -d '[:space:]')
42
+ if [[ "$env_port" =~ ^[0-9]+$ ]] && [ "$env_port" -gt 0 ]; then
43
+ echo "$env_port"
44
+ return
45
+ fi
46
+ fi
47
+
28
48
  value=$(grep -E "\"$key\"[[:space:]]*:" "$SERVER_CONFIG" | head -n 1 | sed -E 's/.*:[[:space:]]*"?([^",}]+)"?.*/\1/')
29
49
  value=$(echo "$value" | tr -d '[:space:]')
30
50
  if [ -z "$value" ]; then
@@ -35,60 +55,61 @@ get_server_value() {
35
55
  }
36
56
 
37
57
  is_running() {
58
+ local port_pid
59
+ port_pid=$(find_pid_by_port)
60
+
38
61
  if [ ! -f "$PID_FILE" ]; then
62
+ if [ -n "$port_pid" ] && kill -0 "$port_pid" 2>/dev/null; then
63
+ return 0
64
+ fi
39
65
  return 1
40
66
  fi
41
67
  local pid
42
68
  pid=$(cat "$PID_FILE" 2>/dev/null)
43
69
  if [ -z "$pid" ]; then
70
+ if [ -n "$port_pid" ] && kill -0 "$port_pid" 2>/dev/null; then
71
+ return 0
72
+ fi
44
73
  return 1
45
74
  fi
46
- kill -0 "$pid" 2>/dev/null
47
- }
48
-
49
- stop_server() {
50
- if [ ! -f "$PID_FILE" ]; then
51
- if [ "$LANGUAGE" = "en" ]; then
52
- echo "ℹ️ Server is not running (pid file not found)."
53
- else
54
- echo "ℹ️ 서버가 실행 중이 아닙니다 (pid 파일 없음)."
55
- fi
75
+ if kill -0 "$pid" 2>/dev/null; then
56
76
  return 0
57
77
  fi
58
78
 
59
- local pid
60
- pid=$(cat "$PID_FILE" 2>/dev/null)
61
- if [ -z "$pid" ]; then
62
- rm -f "$PID_FILE"
63
- if [ "$LANGUAGE" = "en" ]; then
64
- echo "ℹ️ Empty pid file removed."
65
- else
66
- echo "ℹ️ 비어있는 pid 파일을 정리했습니다."
67
- fi
79
+ if [ -n "$port_pid" ] && kill -0 "$port_pid" 2>/dev/null; then
68
80
  return 0
69
81
  fi
70
82
 
83
+ return 1
84
+ }
85
+
86
+ find_pid_by_port() {
87
+ local port
88
+ port=$(get_server_value "port" "3400")
89
+ ss -ltnp 2>/dev/null | grep ":$port " | sed -n 's/.*pid=\([0-9]\+\).*/\1/p' | head -n 1
90
+ }
91
+
92
+ stop_pid_with_confirm() {
93
+ local pid="$1"
94
+ local reason="$2"
95
+
96
+ if [ -z "$pid" ]; then
97
+ return 1
98
+ fi
71
99
  if ! kill -0 "$pid" 2>/dev/null; then
72
- rm -f "$PID_FILE"
73
- if [ "$LANGUAGE" = "en" ]; then
74
- echo "ℹ️ Stale pid file removed (process not found)."
75
- else
76
- echo "ℹ️ 실행 중인 프로세스가 없어 stale pid 파일을 정리했습니다."
77
- fi
78
- return 0
100
+ return 1
79
101
  fi
80
102
 
81
- # 실행 중인 프로세스 정보 표시 후 확인
82
103
  local proc_info
83
104
  proc_info=$(ps -p "$pid" -o pid,user,etime,args --no-headers 2>/dev/null | head -1)
84
105
  if [ "$LANGUAGE" = "en" ]; then
85
- echo "Running process:"
106
+ echo "Running process ($reason):"
86
107
  echo " PID USER ELAPSED COMMAND"
87
108
  echo " $proc_info"
88
109
  echo ""
89
110
  read -r -p "Stop this process? [y/N]: " input
90
111
  else
91
- echo "실행 중인 프로세스:"
112
+ echo "실행 중인 프로세스($reason):"
92
113
  echo " PID USER 실행시간 COMMAND"
93
114
  echo " $proc_info"
94
115
  echo ""
@@ -128,16 +149,78 @@ stop_server() {
128
149
  return 0
129
150
  }
130
151
 
152
+ stop_server() {
153
+ if [ ! -f "$PID_FILE" ]; then
154
+ local port_pid
155
+ port_pid=$(find_pid_by_port)
156
+ if [ -n "$port_pid" ]; then
157
+ stop_pid_with_confirm "$port_pid" "port fallback"
158
+ return $?
159
+ fi
160
+ if [ "$LANGUAGE" = "en" ]; then
161
+ echo "ℹ️ Server is not running (pid file not found)."
162
+ else
163
+ echo "ℹ️ 서버가 실행 중이 아닙니다 (pid 파일 없음)."
164
+ fi
165
+ return 0
166
+ fi
167
+
168
+ local pid
169
+ pid=$(cat "$PID_FILE" 2>/dev/null)
170
+ if [ -z "$pid" ]; then
171
+ rm -f "$PID_FILE"
172
+ local port_pid
173
+ port_pid=$(find_pid_by_port)
174
+ if [ -n "$port_pid" ]; then
175
+ stop_pid_with_confirm "$port_pid" "port fallback"
176
+ return $?
177
+ fi
178
+ if [ "$LANGUAGE" = "en" ]; then
179
+ echo "ℹ️ Empty pid file removed."
180
+ else
181
+ echo "ℹ️ 비어있는 pid 파일을 정리했습니다."
182
+ fi
183
+ return 0
184
+ fi
185
+
186
+ if ! kill -0 "$pid" 2>/dev/null; then
187
+ rm -f "$PID_FILE"
188
+ local port_pid
189
+ port_pid=$(find_pid_by_port)
190
+ if [ -n "$port_pid" ]; then
191
+ stop_pid_with_confirm "$port_pid" "port fallback"
192
+ return $?
193
+ fi
194
+ if [ "$LANGUAGE" = "en" ]; then
195
+ echo "ℹ️ Stale pid file removed (process not found)."
196
+ else
197
+ echo "ℹ️ 실행 중인 프로세스가 없어 stale pid 파일을 정리했습니다."
198
+ fi
199
+ return 0
200
+ fi
201
+
202
+ stop_pid_with_confirm "$pid" "pid file"
203
+ return $?
204
+ }
205
+
131
206
  show_status() {
132
207
  if is_running; then
133
- ./bin/entity-server banner-status RUNNING
208
+ local status_pid
209
+ status_pid=$(find_pid_by_port)
210
+ "$SERVER_BIN" banner-status RUNNING
134
211
  if [ "$LANGUAGE" = "en" ]; then
212
+ if [ -n "$status_pid" ]; then
213
+ echo "PID: $status_pid (detected by port)"
214
+ fi
135
215
  echo "Stop: ./run.sh stop"
136
216
  else
217
+ if [ -n "$status_pid" ]; then
218
+ echo "PID: $status_pid (포트 기준 감지)"
219
+ fi
137
220
  echo "중지: ./run.sh stop"
138
221
  fi
139
222
  else
140
- ./bin/entity-server banner-status STOPPED
223
+ "$SERVER_BIN" banner-status STOPPED
141
224
  if [ "$LANGUAGE" = "en" ]; then
142
225
  echo "Start: ./run.sh start"
143
226
  else
@@ -210,11 +293,11 @@ if [ ! -f "$DATABASE_CONFIG" ]; then
210
293
  exit 1
211
294
  fi
212
295
 
213
- if [ ! -f bin/entity-server ]; then
296
+ if [ ! -f "$SERVER_BIN" ]; then
214
297
  if [ "$LANGUAGE" = "en" ]; then
215
- echo "❌ bin/entity-server not found"
298
+ echo "❌ entity-server binary not found (bin/entity-server or ./entity-server)"
216
299
  else
217
- echo "❌ bin/entity-server 파일이 없습니다"
300
+ echo "❌ entity-server 바이너리 파일이 없습니다 (bin/entity-server 또는 ./entity-server)"
218
301
  fi
219
302
  exit 1
220
303
  fi
@@ -241,7 +324,7 @@ case "$MODE" in
241
324
 
242
325
  sed -E -i 's/("environment"[[:space:]]*:[[:space:]]*")[^"]+(")/\1development\2/' "$SERVER_CONFIG"
243
326
  sed -E -i 's/("default"[[:space:]]*:[[:space:]]*")[^"]+(")/\1development\2/' "$DATABASE_CONFIG"
244
- ./bin/entity-server
327
+ "$SERVER_BIN"
245
328
  ;;
246
329
 
247
330
  start)
@@ -266,8 +349,8 @@ case "$MODE" in
266
349
  sed -E -i 's/("environment"[[:space:]]*:[[:space:]]*")[^"]+(")/\1production\2/' "$SERVER_CONFIG"
267
350
  sed -E -i 's/("default"[[:space:]]*:[[:space:]]*")[^"]+(")/\1production\2/' "$DATABASE_CONFIG"
268
351
 
269
- ./bin/entity-server banner
270
- nohup ./bin/entity-server >> "$STDOUT_LOG" 2>&1 &
352
+ "$SERVER_BIN" banner
353
+ nohup "$SERVER_BIN" >> "$STDOUT_LOG" 2>&1 &
271
354
  SERVER_PID=$!
272
355
  echo "$SERVER_PID" > "$PID_FILE"
273
356
 
@@ -1,10 +1,14 @@
1
- # update-server.ps1 — entity-server / entity-cli 바이너리 업데이트
1
+ # update-server.ps1 — entity-server / entity-cli 바이너리 및 파일 업데이트
2
2
  #
3
3
  # 사용법:
4
4
  # .\scripts\update-server.ps1 # 도움말
5
5
  # .\scripts\update-server.ps1 version # 현재 버전 + 최신 버전 확인
6
6
  # .\scripts\update-server.ps1 latest # 최신 버전으로 업데이트
7
7
  # .\scripts\update-server.ps1 1.5.0 # 특정 버전으로 업데이트
8
+ #
9
+ # 업데이트 대상:
10
+ # - 바이너리: entity-server, entity-cli
11
+ # - 파일: scripts/ samples/ (configs/ entities/ docs/ 제외)
8
12
 
9
13
  param([string]$Action = "")
10
14
 
@@ -12,14 +16,75 @@ $ErrorActionPreference = "Stop"
12
16
 
13
17
  $REPO = "ehfuse/entity-server"
14
18
  $BINARIES = @("entity-server", "entity-cli")
19
+ $DIST_DIRS = @("scripts", "samples")
15
20
  $PLATFORM = "windows"
16
21
  $ARCH_TAG = "x64"
17
22
  $ProjectRoot = Split-Path -Parent $PSScriptRoot
18
23
 
24
+ function Get-RunningServerPid {
25
+ $PidFile = Join-Path $ProjectRoot ".run\entity-server.pid"
26
+ if (Test-Path $PidFile) {
27
+ $pidValue = (Get-Content $PidFile -ErrorAction SilentlyContinue | Select-Object -First 1).Trim()
28
+ if ($pidValue -match '^\d+$') {
29
+ try {
30
+ $p = Get-Process -Id ([int]$pidValue) -ErrorAction Stop
31
+ if ($p) { return [int]$pidValue }
32
+ } catch {}
33
+ }
34
+ }
35
+
36
+ $proc = Get-Process -Name "entity-server" -ErrorAction SilentlyContinue | Select-Object -First 1
37
+ if ($proc) { return [int]$proc.Id }
38
+ return $null
39
+ }
40
+
41
+ function Ensure-ServerStopped {
42
+ $pidValue = Get-RunningServerPid
43
+ if (-not $pidValue) { return }
44
+
45
+ Write-Host ""
46
+ Write-Host "⚠️ 현재 Entity Server가 실행 중입니다."
47
+ try {
48
+ $p = Get-Process -Id $pidValue -ErrorAction Stop
49
+ Write-Host ("PID: {0} Name: {1} Start: {2}" -f $p.Id, $p.ProcessName, $p.StartTime)
50
+ } catch {}
51
+ Write-Host ""
52
+
53
+ $answer = Read-Host "업데이트를 위해 서버를 중지할까요? [y/N]"
54
+ if ($answer -notmatch '^[Yy](es)?$') {
55
+ Write-Host "❌ 업데이트를 취소했습니다."
56
+ exit 1
57
+ }
58
+
59
+ $RunScript = Join-Path $ProjectRoot "scripts\run.ps1"
60
+ if (Test-Path $RunScript) {
61
+ try {
62
+ & $RunScript stop
63
+ } catch {}
64
+ } else {
65
+ try {
66
+ Stop-Process -Id $pidValue -Force -ErrorAction Stop
67
+ } catch {}
68
+ }
69
+
70
+ Start-Sleep -Milliseconds 200
71
+ $still = Get-RunningServerPid
72
+ if ($still) {
73
+ Write-Host "❌ 서버 중지에 실패했습니다. 업데이트를 중단합니다."
74
+ exit 1
75
+ }
76
+
77
+ Write-Host "✅ 서버 중지 완료"
78
+ }
79
+
19
80
  # ── 현재 버전 확인 ────────────────────────────────────────────────────────────
20
81
 
21
82
  function Get-CurrentVer {
22
- $BinPath = Join-Path $ProjectRoot "entity-server.exe"
83
+ $BinPath = Join-Path $ProjectRoot "bin\entity-server.exe"
84
+ if (-not (Test-Path $BinPath)) {
85
+ $LegacyBin = Join-Path $ProjectRoot "entity-server.exe"
86
+ if (Test-Path $LegacyBin) { $BinPath = $LegacyBin }
87
+ }
23
88
  if (Test-Path $BinPath) {
24
89
  try {
25
90
  $out = & $BinPath --version 2>$null
@@ -47,6 +112,8 @@ function Install-Version([string]$TargetVer) {
47
112
  $TargetVer = $TargetVer -replace '^v', ''
48
113
  $CurrentVer = Get-CurrentVer
49
114
 
115
+ Ensure-ServerStopped
116
+
50
117
  Write-Host ""
51
118
  Write-Host "📦 entity-server v$TargetVer 다운로드 중... ($PLATFORM-$ARCH_TAG)"
52
119
  Write-Host ""
@@ -54,7 +121,11 @@ function Install-Version([string]$TargetVer) {
54
121
  foreach ($Bin in $BINARIES) {
55
122
  $FileName = "$Bin-$PLATFORM-$ARCH_TAG.exe"
56
123
  $Url = "https://github.com/$REPO/releases/download/v$TargetVer/$FileName"
57
- $Dest = Join-Path $ProjectRoot "$Bin.exe"
124
+ $BinDir = Join-Path $ProjectRoot "bin"
125
+ if (-not (Test-Path $BinDir)) {
126
+ New-Item -ItemType Directory -Path $BinDir | Out-Null
127
+ }
128
+ $Dest = Join-Path $BinDir "$Bin.exe"
58
129
  $Tmp = "$Dest.tmp"
59
130
 
60
131
  Write-Host (" ↓ {0,-35}" -f $FileName) -NoNewline
@@ -71,22 +142,107 @@ function Install-Version([string]$TargetVer) {
71
142
  }
72
143
  }
73
144
 
145
+ Install-Dist $TargetVer
146
+
74
147
  Write-Host ""
75
148
  Write-Host "✅ 업데이트 완료: v$CurrentVer → v$TargetVer"
76
149
  Write-Host " 서버를 재시작하면 새 버전이 적용됩니다."
77
150
  }
78
151
 
152
+ # ── dist 파일 업데이트 (scripts / samples) ──────────────────────────────────
153
+
154
+ function Install-Dist([string]$TargetVer) {
155
+ $TargetVer = $TargetVer -replace '^v', ''
156
+ $FileName = "dist.tar.gz"
157
+ $Url = "https://github.com/$REPO/releases/download/v$TargetVer/$FileName"
158
+ $TmpTar = Join-Path $env:TEMP ("entity-server-dist-$TargetVer.tar.gz")
159
+ $TmpDir = Join-Path $env:TEMP ("entity-server-dist-$TargetVer")
160
+
161
+ Write-Host (" ↓ {0,-35}" -f $FileName) -NoNewline
162
+ try {
163
+ Invoke-WebRequest -Uri $Url -OutFile $TmpTar -UseBasicParsing
164
+ Write-Host "✓"
165
+ } catch {
166
+ Write-Host "✗ 실패 (업데이트 스킵)"
167
+ Write-Host " URL: $Url"
168
+ Write-Host " ⚠️ dist.tar.gz 가 릴리스에 없습니다. 바이너리만 업데이트됩니다."
169
+ return
170
+ }
171
+
172
+ if (Test-Path $TmpDir) {
173
+ Remove-Item -Recurse -Force $TmpDir
174
+ }
175
+ New-Item -ItemType Directory -Path $TmpDir | Out-Null
176
+
177
+ # tar.exe 사용 (Windows 10+/PowerShell 5+ 기본 포함 환경 가정)
178
+ $TarCmd = Get-Command tar -ErrorAction SilentlyContinue
179
+ if (-not $TarCmd) {
180
+ Write-Host " ⚠️ tar 명령을 찾지 못해 dist 동기화를 건너뜁니다."
181
+ if (Test-Path $TmpTar) { Remove-Item -Force $TmpTar }
182
+ return
183
+ }
184
+
185
+ try {
186
+ & tar -xzf $TmpTar -C $TmpDir
187
+ } catch {
188
+ Write-Host " ⚠️ dist 압축 해제 실패: $_"
189
+ if (Test-Path $TmpTar) { Remove-Item -Force $TmpTar }
190
+ if (Test-Path $TmpDir) { Remove-Item -Recurse -Force $TmpDir }
191
+ return
192
+ }
193
+
194
+ $SrcRoot = $TmpDir
195
+ $HasTopLevel = $false
196
+ foreach ($Dir in $DIST_DIRS) {
197
+ if (Test-Path (Join-Path $TmpDir $Dir)) {
198
+ $HasTopLevel = $true
199
+ break
200
+ }
201
+ }
202
+
203
+ if (-not $HasTopLevel) {
204
+ $FirstSubdir = Get-ChildItem -Path $TmpDir -Directory | Select-Object -First 1
205
+ if ($FirstSubdir) {
206
+ $SrcRoot = $FirstSubdir.FullName
207
+ }
208
+ }
209
+
210
+ Write-Host ""
211
+ Write-Host " 파일 동기화 (configs/ entities/ docs/ 제외):"
212
+ foreach ($Dir in $DIST_DIRS) {
213
+ $Src = Join-Path $SrcRoot $Dir
214
+ $Dest = Join-Path $ProjectRoot $Dir
215
+ if (Test-Path $Src) {
216
+ if (Test-Path $Dest) {
217
+ Remove-Item -Recurse -Force $Dest
218
+ }
219
+ Copy-Item -Recurse -Force $Src $Dest
220
+ Write-Host (" ✔ {0,-20}" -f ("$Dir/"))
221
+ } else {
222
+ Write-Host (" – {0,-20} (릴리스에 없음, 스킵)" -f ("$Dir/"))
223
+ }
224
+ }
225
+
226
+ if (Test-Path $TmpTar) { Remove-Item -Force $TmpTar }
227
+ if (Test-Path $TmpDir) { Remove-Item -Recurse -Force $TmpDir }
228
+ }
229
+
79
230
  # ── 서브커맨드 분기 ───────────────────────────────────────────────────────────
80
231
 
81
232
  switch ($Action) {
82
233
  "" {
83
- Write-Host "update-server.ps1 — entity-server / entity-cli 바이너리 업데이트"
234
+ Write-Host "update-server.ps1 — entity-server / entity-cli 바이너리 및 파일 업데이트"
84
235
  Write-Host ""
85
236
  Write-Host "사용법:"
86
237
  Write-Host " .\scripts\update-server.ps1 version 현재 버전 + 최신 버전 확인"
87
238
  Write-Host " .\scripts\update-server.ps1 latest 최신 버전으로 업데이트"
88
239
  Write-Host " .\scripts\update-server.ps1 <버전> 특정 버전으로 업데이트"
89
240
  Write-Host ""
241
+ Write-Host "업데이트 대상:"
242
+ Write-Host " 바이너리 entity-server entity-cli"
243
+ Write-Host " 파일 scripts/ samples/"
244
+ Write-Host " 제외 configs/ entities/ docs/ (local 설정 보존)"
245
+ Write-Host ""
90
246
  Write-Host "예시:"
91
247
  Write-Host " .\scripts\update-server.ps1 version"
92
248
  Write-Host " .\scripts\update-server.ps1 latest"
@@ -1,11 +1,15 @@
1
1
  #!/bin/bash
2
- # update-server.sh — entity-server / entity-cli 바이너리 업데이트
2
+ # update-server.sh — entity-server / entity-cli 바이너리 및 파일 업데이트
3
3
  #
4
4
  # 사용법:
5
5
  # ./scripts/update-server.sh # 도움말
6
6
  # ./scripts/update-server.sh version # 현재 버전 + 최신 버전 확인
7
7
  # ./scripts/update-server.sh latest # 최신 버전으로 업데이트
8
8
  # ./scripts/update-server.sh 1.5.0 # 특정 버전으로 업데이트
9
+ #
10
+ # 업데이트 대상:
11
+ # - 바이너리: entity-server, entity-cli
12
+ # - 파일: scripts/ samples/ (configs/ entities/ docs/ 제외)
9
13
 
10
14
  set -e
11
15
 
@@ -13,6 +17,57 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13
17
  PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
14
18
  REPO="ehfuse/entity-server"
15
19
  BINARIES=("entity-server" "entity-cli")
20
+ DIST_DIRS=("scripts" "samples")
21
+
22
+ _find_running_pid() {
23
+ local pid_file="$PROJECT_ROOT/.run/entity-server.pid"
24
+ if [ -f "$pid_file" ]; then
25
+ local pid
26
+ pid=$(cat "$pid_file" 2>/dev/null)
27
+ if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
28
+ echo "$pid"
29
+ return 0
30
+ fi
31
+ fi
32
+
33
+ pgrep -f "${PROJECT_ROOT}/(bin/)?entity-server( |$)" | head -n 1
34
+ }
35
+
36
+ _ensure_server_stopped() {
37
+ local pid
38
+ pid="$(_find_running_pid)"
39
+
40
+ if [ -z "$pid" ]; then
41
+ return 0
42
+ fi
43
+
44
+ echo ""
45
+ echo "⚠️ 현재 Entity Server가 실행 중입니다."
46
+ ps -p "$pid" -o pid,etime,cmd --no-headers 2>/dev/null || true
47
+ echo ""
48
+ read -r -p "업데이트를 위해 서버를 중지할까요? [y/N]: " input
49
+ input=$(echo "$input" | tr '[:upper:]' '[:lower:]')
50
+
51
+ if [ "$input" != "y" ] && [ "$input" != "yes" ]; then
52
+ echo "❌ 업데이트를 취소했습니다."
53
+ exit 1
54
+ fi
55
+
56
+ if [ -x "$PROJECT_ROOT/scripts/run.sh" ]; then
57
+ "$PROJECT_ROOT/scripts/run.sh" stop || true
58
+ else
59
+ kill "$pid" 2>/dev/null || true
60
+ fi
61
+
62
+ sleep 0.2
63
+ pid="$(_find_running_pid)"
64
+ if [ -n "$pid" ]; then
65
+ echo "❌ 서버 중지에 실패했습니다. 업데이트를 중단합니다."
66
+ exit 1
67
+ fi
68
+
69
+ echo "✅ 서버 중지 완료"
70
+ }
16
71
 
17
72
  # ── 플랫폼 감지 ───────────────────────────────────────────────────────────────
18
73
 
@@ -41,7 +96,10 @@ esac
41
96
  # ── 현재 버전 확인 ────────────────────────────────────────────────────────────
42
97
 
43
98
  _current_ver() {
44
- local bin="$PROJECT_ROOT/entity-server"
99
+ local bin="$PROJECT_ROOT/bin/entity-server"
100
+ if [ ! -x "$bin" ] && [ -x "$PROJECT_ROOT/entity-server" ]; then
101
+ bin="$PROJECT_ROOT/entity-server"
102
+ fi
45
103
  if [ -x "$bin" ]; then
46
104
  "$bin" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || echo "(알 수 없음)"
47
105
  else
@@ -95,14 +153,19 @@ _install() {
95
153
  local current_ver
96
154
  current_ver="$(_current_ver)"
97
155
 
156
+ _ensure_server_stopped
157
+
98
158
  echo ""
99
159
  echo "📦 entity-server v${target_ver} 다운로드 중... (${PLATFORM}-${ARCH_TAG})"
100
160
  echo ""
101
161
 
162
+ # 바이너리 다운로드
163
+ mkdir -p "$PROJECT_ROOT/bin"
164
+
102
165
  for BIN in "${BINARIES[@]}"; do
103
166
  local file="${BIN}-${PLATFORM}-${ARCH_TAG}"
104
167
  local url="https://github.com/${REPO}/releases/download/v${target_ver}/${file}"
105
- local dest="$PROJECT_ROOT/$BIN"
168
+ local dest="$PROJECT_ROOT/bin/$BIN"
106
169
 
107
170
  printf " ↓ %-32s" "$file"
108
171
  if _download "$url" "$dest" 2>/dev/null; then
@@ -114,24 +177,89 @@ _install() {
114
177
  fi
115
178
  done
116
179
 
180
+ # scripts / samples 업데이트
181
+ _install_dist "$target_ver"
182
+
117
183
  echo ""
118
184
  echo "✅ 업데이트 완료: v${current_ver} → v${target_ver}"
119
185
  echo " 서버를 재시작하면 새 버전이 적용됩니다."
120
186
  }
121
187
 
188
+ # ── dist 파일 업데이트 (scripts / samples) ──────────────────────────────────────
189
+
190
+ _install_dist() {
191
+ local target_ver="$1"
192
+ local file="dist.tar.gz"
193
+ local url="https://github.com/${REPO}/releases/download/v${target_ver}/${file}"
194
+ local tmp_tar="/tmp/entity-server-dist-${target_ver}.tar.gz"
195
+ local tmp_dir="/tmp/entity-server-dist-${target_ver}"
196
+
197
+ printf " ↓ %-32s" "$file"
198
+ if ! _download "$url" "$tmp_tar" 2>/dev/null; then
199
+ echo "✗ 실패 (업데이트 스킵)"
200
+ echo " URL: $url"
201
+ echo " ⚠️ dist.tar.gz 가 릴리스에 없익니다. 바이너리만 업데이트됨."
202
+ return 0
203
+ fi
204
+ echo "✓"
205
+
206
+ rm -rf "$tmp_dir"
207
+ mkdir -p "$tmp_dir"
208
+ tar -xzf "$tmp_tar" -C "$tmp_dir" 2>/dev/null
209
+
210
+ # 아카이브 내부 디렉토리 구조 자동 탐지 (top-level 또는 서브디렉토리)
211
+ local src_root="$tmp_dir"
212
+ local found_dir="false"
213
+ for dir in "${DIST_DIRS[@]}"; do
214
+ if [ -d "${tmp_dir}/${dir}" ]; then
215
+ found_dir="true"
216
+ break
217
+ fi
218
+ done
219
+ if [ "$found_dir" = "false" ]; then
220
+ # tar가 서브디렉토리 하나로 풌주는 경우 (예: entity-server-1.5.0/)
221
+ local subdir
222
+ subdir="$(ls -1 "$tmp_dir" | head -1)"
223
+ if [ -n "$subdir" ] && [ -d "${tmp_dir}/${subdir}" ]; then
224
+ src_root="${tmp_dir}/${subdir}"
225
+ fi
226
+ fi
227
+
228
+ echo ""
229
+ echo " 파일 동기화 (configs/ entities/ 제외):"
230
+ for DIR in "${DIST_DIRS[@]}"; do
231
+ local src="${src_root}/${DIR}"
232
+ local dest="${PROJECT_ROOT}/${DIR}"
233
+ if [ -d "$src" ]; then
234
+ rm -rf "$dest"
235
+ cp -r "$src" "$dest"
236
+ printf " ✔ %-20s\n" "${DIR}/"
237
+ else
238
+ printf " – %-20s (릴리스에 없음, 스킵)\n" "${DIR}/"
239
+ fi
240
+ done
241
+
242
+ rm -rf "$tmp_dir" "$tmp_tar"
243
+ }
244
+
122
245
  # ── 서브커맨드 분기 ───────────────────────────────────────────────────────────
123
246
 
124
247
  ARG="${1:-}"
125
248
 
126
249
  case "$ARG" in
127
250
  "")
128
- echo "update-server.sh — entity-server / entity-cli 바이너리 업데이트"
251
+ echo "update-server.sh — entity-server / entity-cli 바이너리 및 파일 업데이트"
129
252
  echo ""
130
253
  echo "사용법:"
131
254
  echo " ./scripts/update-server.sh version 현재 버전 + 최신 버전 확인"
132
255
  echo " ./scripts/update-server.sh latest 최신 버전으로 업데이트"
133
256
  echo " ./scripts/update-server.sh <버전> 특정 버전으로 업데이트"
134
257
  echo ""
258
+ echo "업데이트 대상:"
259
+ echo " 바이너리 entity-server entity-cli"
260
+ echo " 파일 scripts/ samples/"
261
+ echo " 제외 configs/ entities/ docs/ (local 설정 보존)"
262
+ echo ""
135
263
  echo "예시:"
136
264
  echo " ./scripts/update-server.sh version"
137
265
  echo " ./scripts/update-server.sh latest"