depository-deploy 1.5.6 → 1.5.15
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.
- package/install/install-unix.sh +16 -0
- package/install/install-windows.ps1 +10 -0
- package/install/templates/appsettings-api.json +3 -0
- package/install/templates/appsettings-gatherer.json +3 -0
- package/install/templates/appsettings-worker.json +3 -0
- package/install/templates/web.config +0 -3
- package/install/update-unix.sh +224 -0
- package/install/update-windows.ps1 +214 -0
- package/package.json +4 -4
- package/wizard.html +11 -2
package/install/install-unix.sh
CHANGED
|
@@ -437,6 +437,22 @@ echo "=============================================="
|
|
|
437
437
|
echo " INSTALLATION COMPLETE"
|
|
438
438
|
echo "=============================================="
|
|
439
439
|
echo ""
|
|
440
|
+
# ---- Write version file (read by API to report installed version) ----
|
|
441
|
+
PKG_VERSION=$(node -e "try{const p=require('$DEPLOY_DIR/package.json');process.stdout.write(p.version)}catch(e){}" 2>/dev/null || echo "")
|
|
442
|
+
if [ -n "$PKG_VERSION" ]; then
|
|
443
|
+
echo "$PKG_VERSION" > "$INSTALL_DIR/version.txt"
|
|
444
|
+
info "Version file written: $PKG_VERSION"
|
|
445
|
+
fi
|
|
446
|
+
|
|
447
|
+
# ---- Allow depository user to run update commands without password ----
|
|
448
|
+
SUDOERS_FILE="/etc/sudoers.d/depository-update"
|
|
449
|
+
cat > "$SUDOERS_FILE" << SUDOERS_EOF
|
|
450
|
+
# Allow depository service account to manage its own services and npm updates
|
|
451
|
+
depository ALL=(ALL) NOPASSWD: /usr/bin/npm, /usr/local/bin/npm, /bin/systemctl stop depository-*, /bin/systemctl start depository-*, /usr/bin/systemctl stop depository-*, /usr/bin/systemctl start depository-*
|
|
452
|
+
SUDOERS_EOF
|
|
453
|
+
chmod 440 "$SUDOERS_FILE"
|
|
454
|
+
info "sudo permissions configured for depository user"
|
|
455
|
+
|
|
440
456
|
sleep 2
|
|
441
457
|
ALL_OK=true
|
|
442
458
|
for svc in depository-auth depository-gatherer depository-api depository-worker depository-digestor; do
|
|
@@ -614,6 +614,16 @@ Write-Host " INSTALLATION COMPLETE" -ForegroundColor Cyan
|
|
|
614
614
|
Write-Host "==============================================" -ForegroundColor Cyan
|
|
615
615
|
Write-Host ""
|
|
616
616
|
Start-Sleep -Seconds 3
|
|
617
|
+
# ---- Write version file (read by API to report installed version) ----
|
|
618
|
+
try {
|
|
619
|
+
$pkgJson = Join-Path $DeployDir "package.json"
|
|
620
|
+
if (Test-Path $pkgJson) {
|
|
621
|
+
$installedVersion = (Get-Content $pkgJson -Raw | ConvertFrom-Json).version
|
|
622
|
+
Set-Content -Path "$INSTALL_DIR\version.txt" -Value $installedVersion -Encoding UTF8
|
|
623
|
+
Write-OK "Version file written: $installedVersion"
|
|
624
|
+
}
|
|
625
|
+
} catch { Write-Warn "Could not write version.txt: $_" }
|
|
626
|
+
|
|
617
627
|
$allOk = $true
|
|
618
628
|
foreach ($def in $svcDefs) {
|
|
619
629
|
$svc = Get-Service -Name $def.Name -ErrorAction SilentlyContinue
|
|
@@ -20,9 +20,6 @@
|
|
|
20
20
|
<!-- 1. REST API → Kestrel on {{API_PORT}} -->
|
|
21
21
|
<rule name="Depository API" stopProcessing="true">
|
|
22
22
|
<match url="^api/(.*)" />
|
|
23
|
-
<conditions logicalGrouping="MatchAll">
|
|
24
|
-
<add input="{CACHE_URL}" pattern="^(.*)$" />
|
|
25
|
-
</conditions>
|
|
26
23
|
<action type="Rewrite"
|
|
27
24
|
url="http://{{IIS_BACKEND_HOST}}:{{API_PORT}}/api/{R:1}"
|
|
28
25
|
appendQueryString="true" />
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# =============================================================
|
|
3
|
+
# DEPOSITORY - UNIX AUTO-UPDATE SCRIPT
|
|
4
|
+
# Triggered by the API when an admin approves an update.
|
|
5
|
+
# Run via nohup so it survives the API service restart.
|
|
6
|
+
#
|
|
7
|
+
# Usage (called by UpdateService.cs):
|
|
8
|
+
# bash update-unix.sh <version> <install_root> <status_file> <log_file>
|
|
9
|
+
#
|
|
10
|
+
# Arguments:
|
|
11
|
+
# $1 version npm version tag, e.g. "1.5.7" or "latest"
|
|
12
|
+
# $2 install_root INSTALL_DIR root, e.g. /opt/depository
|
|
13
|
+
# $3 status_file JSON file path for progress state
|
|
14
|
+
# $4 log_file Plain-text log file path
|
|
15
|
+
# =============================================================
|
|
16
|
+
set -euo pipefail
|
|
17
|
+
|
|
18
|
+
VERSION="${1:-latest}"
|
|
19
|
+
INSTALL_ROOT="${2:-/opt/depository}"
|
|
20
|
+
STATUS_FILE="${3:-}"
|
|
21
|
+
LOG_FILE="${4:-}"
|
|
22
|
+
|
|
23
|
+
# ── Helpers ─────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
log() {
|
|
26
|
+
local ts
|
|
27
|
+
ts=$(date '+%H:%M:%S')
|
|
28
|
+
local line="[$ts] $*"
|
|
29
|
+
if [ -n "$LOG_FILE" ]; then
|
|
30
|
+
echo "$line" >> "$LOG_FILE" 2>/dev/null || true
|
|
31
|
+
fi
|
|
32
|
+
echo "$line"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
write_status() {
|
|
36
|
+
local STATUS="$1"
|
|
37
|
+
[ -z "$STATUS_FILE" ] && return
|
|
38
|
+
# Use python3 to safely update the JSON status file
|
|
39
|
+
python3 - <<PYEOF 2>/dev/null || true
|
|
40
|
+
import json, os, sys
|
|
41
|
+
path = "$STATUS_FILE"
|
|
42
|
+
try:
|
|
43
|
+
with open(path) as f:
|
|
44
|
+
d = json.load(f)
|
|
45
|
+
except Exception:
|
|
46
|
+
d = {}
|
|
47
|
+
from datetime import datetime, timezone
|
|
48
|
+
now = datetime.now(timezone.utc).isoformat()
|
|
49
|
+
d["status"] = "$STATUS"
|
|
50
|
+
d["updatedAt"] = now
|
|
51
|
+
if "$STATUS" in ("complete", "failed"):
|
|
52
|
+
d["completedAt"] = now
|
|
53
|
+
d["success"] = "$STATUS" == "complete"
|
|
54
|
+
with open(path, "w") as f:
|
|
55
|
+
json.dump(d, f, indent=2)
|
|
56
|
+
PYEOF
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Detect OS platform
|
|
60
|
+
OS_TYPE=$(uname -s)
|
|
61
|
+
if [ "$OS_TYPE" = "Darwin" ]; then
|
|
62
|
+
PLAT="macos"
|
|
63
|
+
else
|
|
64
|
+
PLAT="linux"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# ── Main ─────────────────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
log "============================================================"
|
|
70
|
+
log " DEPOSITORY AUTO-UPDATE"
|
|
71
|
+
log " Target version : $VERSION"
|
|
72
|
+
log " Install root : $INSTALL_ROOT"
|
|
73
|
+
log " Platform : $PLAT"
|
|
74
|
+
log "============================================================"
|
|
75
|
+
|
|
76
|
+
# ── Step 1: Download new package ─────────────────────────────────────────────
|
|
77
|
+
write_status "installing_package"
|
|
78
|
+
log ""
|
|
79
|
+
log "STEP 1/4 Installing depository-deploy@$VERSION via npm..."
|
|
80
|
+
|
|
81
|
+
# Use sudo if npm is owned by root (typical global install)
|
|
82
|
+
NPM_CMD="npm"
|
|
83
|
+
if [ -f "$(which npm 2>/dev/null)" ] && [ "$(stat -c '%U' "$(which npm)" 2>/dev/null || stat -f '%Su' "$(which npm)" 2>/dev/null)" = "root" ]; then
|
|
84
|
+
NPM_CMD="sudo npm"
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
$NPM_CMD install -g "depository-deploy@$VERSION" >> "$LOG_FILE" 2>&1
|
|
88
|
+
log "Package installed."
|
|
89
|
+
|
|
90
|
+
# Locate release binaries
|
|
91
|
+
NPM_ROOT=$(npm root -g 2>/dev/null || echo "")
|
|
92
|
+
log "npm global root: $NPM_ROOT"
|
|
93
|
+
|
|
94
|
+
RELEASE_DIR=""
|
|
95
|
+
for candidate in \
|
|
96
|
+
"$NPM_ROOT/depository-deploy-$PLAT/release/$PLAT" \
|
|
97
|
+
"$NPM_ROOT/depository-deploy/release/$PLAT" \
|
|
98
|
+
"$NPM_ROOT/depository-deploy/release"
|
|
99
|
+
do
|
|
100
|
+
if [ -d "$candidate" ]; then
|
|
101
|
+
RELEASE_DIR="$candidate"
|
|
102
|
+
break
|
|
103
|
+
fi
|
|
104
|
+
done
|
|
105
|
+
|
|
106
|
+
if [ -z "$RELEASE_DIR" ]; then
|
|
107
|
+
log "ERROR: Release directory not found under npm root: $NPM_ROOT"
|
|
108
|
+
write_status "failed"
|
|
109
|
+
exit 1
|
|
110
|
+
fi
|
|
111
|
+
log "Release directory: $RELEASE_DIR"
|
|
112
|
+
|
|
113
|
+
# ── Step 2: Stop services ─────────────────────────────────────────────────────
|
|
114
|
+
write_status "stopping_services"
|
|
115
|
+
log ""
|
|
116
|
+
log "STEP 2/4 Stopping Depository services..."
|
|
117
|
+
|
|
118
|
+
for svc in depository-api depository-auth depository-worker depository-gatherer depository-digestor; do
|
|
119
|
+
if systemctl is-active --quiet "$svc" 2>/dev/null; then
|
|
120
|
+
sudo systemctl stop "$svc" 2>/dev/null || true
|
|
121
|
+
log " Stopped: $svc"
|
|
122
|
+
fi
|
|
123
|
+
done
|
|
124
|
+
|
|
125
|
+
# Kill any remaining processes
|
|
126
|
+
for proc_name in DEPOSITORY.API.REST DEPOSITORY.API.OATH DEPOSITORY.CORE.WORKER \
|
|
127
|
+
DEPOSITORY.CORE.GATHERER DEPOSITORY.CORE.DIGESTOR; do
|
|
128
|
+
pids=$(pgrep -f "$proc_name" 2>/dev/null || true)
|
|
129
|
+
if [ -n "$pids" ]; then
|
|
130
|
+
echo "$pids" | while read -r pid; do
|
|
131
|
+
kill -9 "$pid" 2>/dev/null || true
|
|
132
|
+
done
|
|
133
|
+
fi
|
|
134
|
+
done
|
|
135
|
+
sleep 6
|
|
136
|
+
|
|
137
|
+
# ── Step 3: Copy new binaries (preserve appsettings*.json) ───────────────────
|
|
138
|
+
write_status "copying_binaries"
|
|
139
|
+
log ""
|
|
140
|
+
log "STEP 3/4 Copying new binaries..."
|
|
141
|
+
|
|
142
|
+
for sub in api auth worker gatherer digestor pdfindexer setup; do
|
|
143
|
+
src="$RELEASE_DIR/$sub"
|
|
144
|
+
dst="$INSTALL_ROOT/$sub"
|
|
145
|
+
[ -d "$src" ] || continue
|
|
146
|
+
[ -d "$dst" ] || mkdir -p "$dst"
|
|
147
|
+
log " $sub ..."
|
|
148
|
+
find "$src" -type f | while IFS= read -r srcfile; do
|
|
149
|
+
rel="${srcfile#$src/}"
|
|
150
|
+
name=$(basename "$srcfile")
|
|
151
|
+
destfile="$dst/$rel"
|
|
152
|
+
destdir=$(dirname "$destfile")
|
|
153
|
+
mkdir -p "$destdir"
|
|
154
|
+
# Preserve all appsettings files — they contain production config
|
|
155
|
+
if echo "$name" | grep -q '^appsettings'; then
|
|
156
|
+
log " (preserved) $rel"
|
|
157
|
+
else
|
|
158
|
+
cp -f "$srcfile" "$destfile"
|
|
159
|
+
fi
|
|
160
|
+
done
|
|
161
|
+
done
|
|
162
|
+
|
|
163
|
+
# Update UI (static files — safe to overwrite)
|
|
164
|
+
UI_SRC="$RELEASE_DIR/ui"
|
|
165
|
+
[ -d "$UI_SRC" ] || UI_SRC="$(dirname "$RELEASE_DIR")/ui"
|
|
166
|
+
UI_DST="$INSTALL_ROOT/ui"
|
|
167
|
+
if [ -d "$UI_SRC" ] && [ -d "$UI_DST" ]; then
|
|
168
|
+
log " ui ..."
|
|
169
|
+
cp -r "$UI_SRC/"* "$UI_DST/"
|
|
170
|
+
# Preserve the API base URL injected during original installation
|
|
171
|
+
UI_INDEX="$UI_DST/index.html"
|
|
172
|
+
if [ -f "$UI_INDEX" ]; then
|
|
173
|
+
SITE_URL=$(grep -oP "window\.__API_BASE__='\\K[^']*" "$UI_INDEX" 2>/dev/null || true)
|
|
174
|
+
if [ -n "$SITE_URL" ]; then
|
|
175
|
+
# Remove old injection then re-inject
|
|
176
|
+
sed -i.bak "s|<script>window\.__API_BASE__[^<]*</script>||g" "$UI_INDEX" 2>/dev/null || true
|
|
177
|
+
sed -i.bak "s|</head>|<script>window.__API_BASE__='${SITE_URL}';window.__CORE_API_BASE__='${SITE_URL}';</script></head>|" "$UI_INDEX"
|
|
178
|
+
rm -f "${UI_INDEX}.bak"
|
|
179
|
+
fi
|
|
180
|
+
fi
|
|
181
|
+
fi
|
|
182
|
+
|
|
183
|
+
# Fix permissions
|
|
184
|
+
chown -R depository:depository "$INSTALL_ROOT" 2>/dev/null || true
|
|
185
|
+
for bin in \
|
|
186
|
+
"$INSTALL_ROOT/api/DEPOSITORY.API.REST" \
|
|
187
|
+
"$INSTALL_ROOT/auth/DEPOSITORY.API.OATH" \
|
|
188
|
+
"$INSTALL_ROOT/worker/DEPOSITORY.CORE.WORKER" \
|
|
189
|
+
"$INSTALL_ROOT/gatherer/DEPOSITORY.CORE.GATHERER" \
|
|
190
|
+
"$INSTALL_ROOT/digestor/DEPOSITORY.CORE.DIGESTOR"; do
|
|
191
|
+
[ -f "$bin" ] && chmod +x "$bin"
|
|
192
|
+
done
|
|
193
|
+
|
|
194
|
+
# Update version.txt
|
|
195
|
+
NEW_VERSION="$VERSION"
|
|
196
|
+
if [ "$NEW_VERSION" = "latest" ]; then
|
|
197
|
+
NEW_VERSION=$(npm view depository-deploy version 2>/dev/null || echo "")
|
|
198
|
+
fi
|
|
199
|
+
if [ -n "$NEW_VERSION" ] && [ "$NEW_VERSION" != "latest" ]; then
|
|
200
|
+
echo "$NEW_VERSION" > "$INSTALL_ROOT/version.txt"
|
|
201
|
+
log " version.txt → $NEW_VERSION"
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
log "Binaries copied."
|
|
205
|
+
|
|
206
|
+
# ── Step 4: Restart services ──────────────────────────────────────────────────
|
|
207
|
+
write_status "starting_services"
|
|
208
|
+
log ""
|
|
209
|
+
log "STEP 4/4 Starting services..."
|
|
210
|
+
|
|
211
|
+
# Start in dependency order
|
|
212
|
+
for svc in depository-auth depository-api depository-gatherer \
|
|
213
|
+
depository-worker depository-digestor; do
|
|
214
|
+
log " Starting $svc ..."
|
|
215
|
+
sudo systemctl start "$svc" 2>/dev/null || true
|
|
216
|
+
sleep 1
|
|
217
|
+
done
|
|
218
|
+
sleep 5
|
|
219
|
+
|
|
220
|
+
write_status "complete"
|
|
221
|
+
log ""
|
|
222
|
+
log "============================================================"
|
|
223
|
+
log " UPDATE COMPLETE — Depository is now at version $NEW_VERSION"
|
|
224
|
+
log "============================================================"
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#Requires -RunAsAdministrator
|
|
2
|
+
# =============================================================
|
|
3
|
+
# DEPOSITORY - WINDOWS AUTO-UPDATE SCRIPT
|
|
4
|
+
# Triggered by the API when an admin approves an update.
|
|
5
|
+
# Runs as a detached process and survives the API service restart.
|
|
6
|
+
#
|
|
7
|
+
# Parameters:
|
|
8
|
+
# -Version npm version tag, e.g. "1.5.7" or "latest"
|
|
9
|
+
# -InstallRoot INSTALL_DIR root, e.g. C:\Depository
|
|
10
|
+
# -StatusFile JSON file path for progress state (read by API after restart)
|
|
11
|
+
# -LogFile Plain-text log file path (tailed by SSE stream)
|
|
12
|
+
# =============================================================
|
|
13
|
+
param(
|
|
14
|
+
[string]$Version = "latest",
|
|
15
|
+
[string]$InstallRoot = "",
|
|
16
|
+
[string]$StatusFile = "",
|
|
17
|
+
[string]$LogFile = ""
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
$ErrorActionPreference = "Continue"
|
|
21
|
+
|
|
22
|
+
# ── Helpers ─────────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
function Write-Log {
|
|
25
|
+
param([string]$Msg)
|
|
26
|
+
$ts = Get-Date -Format "HH:mm:ss"
|
|
27
|
+
$line = "[$ts] $Msg"
|
|
28
|
+
if ($LogFile) {
|
|
29
|
+
Add-Content -Path $LogFile -Value $line -Encoding UTF8 -ErrorAction SilentlyContinue
|
|
30
|
+
}
|
|
31
|
+
Write-Host $line
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function Write-Status {
|
|
35
|
+
param([string]$Status)
|
|
36
|
+
if (-not $StatusFile) { return }
|
|
37
|
+
try {
|
|
38
|
+
$raw = if (Test-Path $StatusFile) { Get-Content $StatusFile -Raw -Encoding UTF8 } else { "{}" }
|
|
39
|
+
$data = $raw | ConvertFrom-Json -ErrorAction Stop
|
|
40
|
+
$data.status = $Status
|
|
41
|
+
$data.updatedAt = (Get-Date -Format "o")
|
|
42
|
+
if ($Status -in @("complete", "failed")) {
|
|
43
|
+
$data.completedAt = $data.updatedAt
|
|
44
|
+
$data.success = ($Status -eq "complete")
|
|
45
|
+
}
|
|
46
|
+
$data | ConvertTo-Json -Depth 5 | Set-Content -Path $StatusFile -Encoding UTF8
|
|
47
|
+
} catch {
|
|
48
|
+
Write-Log "WARNING: Could not update status file — $_"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function Find-Npm {
|
|
53
|
+
foreach ($candidate in @("npm.cmd", "npm")) {
|
|
54
|
+
if (Get-Command $candidate -ErrorAction SilentlyContinue) { return $candidate }
|
|
55
|
+
}
|
|
56
|
+
# Try common Node.js install paths
|
|
57
|
+
foreach ($p in @("$env:ProgramFiles\nodejs\npm.cmd",
|
|
58
|
+
"$env:LOCALAPPDATA\Programs\nodejs\npm.cmd")) {
|
|
59
|
+
if (Test-Path $p) { return $p }
|
|
60
|
+
}
|
|
61
|
+
throw "npm not found in PATH. Ensure Node.js is installed."
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# ── Main ─────────────────────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
Write-Log "============================================================"
|
|
68
|
+
Write-Log " DEPOSITORY AUTO-UPDATE"
|
|
69
|
+
Write-Log " Target version : $Version"
|
|
70
|
+
Write-Log " Install root : $InstallRoot"
|
|
71
|
+
Write-Log "============================================================"
|
|
72
|
+
|
|
73
|
+
$npm = Find-Npm
|
|
74
|
+
|
|
75
|
+
# ── Step 1: Download new package ─────────────────────────────────────────
|
|
76
|
+
Write-Status "installing_package"
|
|
77
|
+
Write-Log ""
|
|
78
|
+
Write-Log "STEP 1/4 Installing depository-deploy@$Version via npm..."
|
|
79
|
+
& $npm install -g "depository-deploy@$Version" 2>&1 | ForEach-Object {
|
|
80
|
+
if ($_ -and "$_".Trim()) { Write-Log " $_" }
|
|
81
|
+
}
|
|
82
|
+
if ($LASTEXITCODE -and $LASTEXITCODE -ne 0) {
|
|
83
|
+
throw "npm install exited with code $LASTEXITCODE"
|
|
84
|
+
}
|
|
85
|
+
Write-Log "Package installed."
|
|
86
|
+
|
|
87
|
+
# Locate release binaries (npm global layout)
|
|
88
|
+
$npmRoot = (& $npm root -g 2>$null).Trim()
|
|
89
|
+
if (-not $npmRoot) { $npmRoot = "$env:APPDATA\npm\node_modules" }
|
|
90
|
+
Write-Log "npm global root: $npmRoot"
|
|
91
|
+
|
|
92
|
+
$ReleaseDir = $null
|
|
93
|
+
foreach ($candidate in @(
|
|
94
|
+
"$npmRoot\depository-deploy-windows\release\windows",
|
|
95
|
+
"$npmRoot\depository-deploy\release\windows",
|
|
96
|
+
"$npmRoot\depository-deploy\release"
|
|
97
|
+
)) {
|
|
98
|
+
if (Test-Path $candidate) { $ReleaseDir = $candidate; break }
|
|
99
|
+
}
|
|
100
|
+
if (-not $ReleaseDir) {
|
|
101
|
+
throw "Release directory not found under npm root: $npmRoot"
|
|
102
|
+
}
|
|
103
|
+
Write-Log "Release directory: $ReleaseDir"
|
|
104
|
+
|
|
105
|
+
# ── Step 2: Stop services ─────────────────────────────────────────────────
|
|
106
|
+
Write-Status "stopping_services"
|
|
107
|
+
Write-Log ""
|
|
108
|
+
Write-Log "STEP 2/4 Stopping Depository services..."
|
|
109
|
+
$Services = @("depository-api", "depository-auth", "depository-worker",
|
|
110
|
+
"depository-gatherer", "depository-digestor")
|
|
111
|
+
foreach ($svc in $Services) {
|
|
112
|
+
$info = sc.exe query $svc 2>$null | Out-String
|
|
113
|
+
if ($info -match "RUNNING") {
|
|
114
|
+
Write-Log " Stopping $svc ..."
|
|
115
|
+
sc.exe stop $svc 2>&1 | Out-Null
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
Write-Log "Waiting for processes to exit..."
|
|
119
|
+
Start-Sleep -Seconds 8
|
|
120
|
+
|
|
121
|
+
# ── Step 3: Copy new binaries (preserve appsettings*.json) ───────────────
|
|
122
|
+
Write-Status "copying_binaries"
|
|
123
|
+
Write-Log ""
|
|
124
|
+
Write-Log "STEP 3/4 Copying new binaries..."
|
|
125
|
+
|
|
126
|
+
$SubDirs = @("api", "auth", "worker", "gatherer", "digestor", "pdfindexer", "setup")
|
|
127
|
+
foreach ($sub in $SubDirs) {
|
|
128
|
+
$src = Join-Path $ReleaseDir $sub
|
|
129
|
+
$dst = Join-Path $InstallRoot $sub
|
|
130
|
+
if (-not (Test-Path $src)) { continue }
|
|
131
|
+
if (-not (Test-Path $dst)) {
|
|
132
|
+
New-Item -ItemType Directory -Path $dst -Force | Out-Null
|
|
133
|
+
}
|
|
134
|
+
Write-Log " $sub ..."
|
|
135
|
+
Get-ChildItem $src -Recurse | ForEach-Object {
|
|
136
|
+
$rel = $_.FullName.Substring($src.Length).TrimStart('\')
|
|
137
|
+
$target = Join-Path $dst $rel
|
|
138
|
+
if ($_.PSIsContainer) {
|
|
139
|
+
if (-not (Test-Path $target)) {
|
|
140
|
+
New-Item -ItemType Directory -Path $target -Force | Out-Null
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
# Preserve all appsettings files — they contain production config
|
|
144
|
+
if ($_.Name -match '^appsettings') {
|
|
145
|
+
Write-Log " (preserved) $rel"
|
|
146
|
+
} else {
|
|
147
|
+
Copy-Item $_.FullName -Destination $target -Force
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# Update UI (static files — safe to overwrite, no secrets)
|
|
154
|
+
$uiSrc = Join-Path $ReleaseDir "ui"
|
|
155
|
+
if (-not (Test-Path $uiSrc)) {
|
|
156
|
+
$uiSrc = Join-Path (Split-Path -Parent $ReleaseDir) "ui"
|
|
157
|
+
}
|
|
158
|
+
$uiDst = Join-Path $InstallRoot "ui"
|
|
159
|
+
if ((Test-Path $uiSrc) -and (Test-Path $uiDst)) {
|
|
160
|
+
Write-Log " ui ..."
|
|
161
|
+
Copy-Item "$uiSrc\*" $uiDst -Recurse -Force
|
|
162
|
+
# Re-inject the API base URL that was set during the original installation
|
|
163
|
+
$uiIndex = Join-Path $uiDst "index.html"
|
|
164
|
+
if (Test-Path $uiIndex) {
|
|
165
|
+
$html = Get-Content $uiIndex -Raw -Encoding UTF8
|
|
166
|
+
# Find the existing __API_BASE__ injection and preserve it
|
|
167
|
+
if ($html -match "window.__API_BASE__='([^']*)'") {
|
|
168
|
+
$siteUrl = $Matches[1]
|
|
169
|
+
$inject = "<script>window.__API_BASE__='$siteUrl';window.__CORE_API_BASE__='$siteUrl';</script>"
|
|
170
|
+
$html = $html -replace '<script>window\.__API_BASE__.*?</script>', ""
|
|
171
|
+
$html = $html -replace '</head>', "$inject</head>"
|
|
172
|
+
Set-Content $uiIndex -Value $html -Encoding UTF8
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
# Update version.txt
|
|
178
|
+
$newVersion = $Version
|
|
179
|
+
if ($newVersion -eq "latest") {
|
|
180
|
+
try { $newVersion = (& $npm view "depository-deploy" version 2>$null).Trim() } catch {}
|
|
181
|
+
}
|
|
182
|
+
if ($newVersion -and $newVersion -ne "latest") {
|
|
183
|
+
Set-Content -Path (Join-Path $InstallRoot "version.txt") -Value $newVersion -Encoding UTF8
|
|
184
|
+
Write-Log " version.txt → $newVersion"
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
Write-Log "Binaries copied."
|
|
188
|
+
|
|
189
|
+
# ── Step 4: Restart services ──────────────────────────────────────────────
|
|
190
|
+
Write-Status "starting_services"
|
|
191
|
+
Write-Log ""
|
|
192
|
+
Write-Log "STEP 4/4 Starting services..."
|
|
193
|
+
# Start in dependency order: auth first, then api, then workers
|
|
194
|
+
foreach ($svc in @("depository-auth", "depository-api", "depository-gatherer",
|
|
195
|
+
"depository-worker", "depository-digestor")) {
|
|
196
|
+
Write-Log " Starting $svc ..."
|
|
197
|
+
sc.exe start $svc 2>&1 | Out-Null
|
|
198
|
+
Start-Sleep -Seconds 1
|
|
199
|
+
}
|
|
200
|
+
Start-Sleep -Seconds 5
|
|
201
|
+
|
|
202
|
+
Write-Status "complete"
|
|
203
|
+
Write-Log ""
|
|
204
|
+
Write-Log "============================================================"
|
|
205
|
+
Write-Log " UPDATE COMPLETE — Depository is now at version $newVersion"
|
|
206
|
+
Write-Log "============================================================"
|
|
207
|
+
|
|
208
|
+
} catch {
|
|
209
|
+
Write-Log ""
|
|
210
|
+
Write-Log "ERROR: $_"
|
|
211
|
+
Write-Log $_.ScriptStackTrace
|
|
212
|
+
Write-Status "failed"
|
|
213
|
+
exit 1
|
|
214
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "depository-deploy",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.15",
|
|
4
4
|
"description": "Depository document management system – deployment wizard and installers",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"publishConfig": {
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"scripts/publish.mjs"
|
|
26
26
|
],
|
|
27
27
|
"optionalDependencies": {
|
|
28
|
-
"depository-deploy-linux": "1.5.
|
|
29
|
-
"depository-deploy-macos": "1.5.
|
|
30
|
-
"depository-deploy-windows": "1.5.
|
|
28
|
+
"depository-deploy-linux": "1.5.15",
|
|
29
|
+
"depository-deploy-macos": "1.5.15",
|
|
30
|
+
"depository-deploy-windows": "1.5.15"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|
|
33
33
|
"start": "node wizard-server.mjs"
|
package/wizard.html
CHANGED
|
@@ -1155,6 +1155,7 @@ const T = {
|
|
|
1155
1155
|
admin_org_lbl:"Organization",
|
|
1156
1156
|
admin_note:"This admin account will be created automatically after installation completes.",
|
|
1157
1157
|
err_admin_email:"Admin email is required.",
|
|
1158
|
+
err_admin_email_invalid:"Please enter a valid email address.",
|
|
1158
1159
|
err_admin_pass:"Password is required.",
|
|
1159
1160
|
err_admin_pass2:"Passwords do not match.",
|
|
1160
1161
|
err_admin_name:"Full name is required.",
|
|
@@ -1276,6 +1277,7 @@ const T = {
|
|
|
1276
1277
|
admin_org_lbl:"Organizasyon",
|
|
1277
1278
|
admin_note:"Bu yönetici hesabı, kurulum tamamlandıktan sonra otomatik olarak oluşturulacaktır.",
|
|
1278
1279
|
err_admin_email:"Yönetici e-postası zorunludur.",
|
|
1280
|
+
err_admin_email_invalid:"Lütfen geçerli bir e-posta adresi girin.",
|
|
1279
1281
|
err_admin_pass:"Şifre zorunludur.",
|
|
1280
1282
|
err_admin_pass2:"Şifreler eşleşmiyor.",
|
|
1281
1283
|
err_admin_name:"Tam ad zorunludur.",
|
|
@@ -1397,6 +1399,7 @@ const T = {
|
|
|
1397
1399
|
admin_org_lbl:"Organisation",
|
|
1398
1400
|
admin_note:"Ce compte administrateur sera créé automatiquement à la fin de l'installation.",
|
|
1399
1401
|
err_admin_email:"L'e-mail administrateur est obligatoire.",
|
|
1402
|
+
err_admin_email_invalid:"Veuillez saisir une adresse e-mail valide.",
|
|
1400
1403
|
err_admin_pass:"Le mot de passe est obligatoire.",
|
|
1401
1404
|
err_admin_pass2:"Les mots de passe ne correspondent pas.",
|
|
1402
1405
|
err_admin_name:"Le nom complet est obligatoire.",
|
|
@@ -1518,6 +1521,7 @@ const T = {
|
|
|
1518
1521
|
admin_org_lbl:"Organisation",
|
|
1519
1522
|
admin_note:"Dieses Admin-Konto wird automatisch nach Abschluss der Installation erstellt.",
|
|
1520
1523
|
err_admin_email:"Admin-E-Mail ist erforderlich.",
|
|
1524
|
+
err_admin_email_invalid:"Bitte geben Sie eine gültige E-Mail-Adresse ein.",
|
|
1521
1525
|
err_admin_pass:"Passwort ist erforderlich.",
|
|
1522
1526
|
err_admin_pass2:"Passwörter stimmen nicht überein.",
|
|
1523
1527
|
err_admin_name:"Vollständiger Name ist erforderlich.",
|
|
@@ -1639,6 +1643,7 @@ const T = {
|
|
|
1639
1643
|
admin_org_lbl:"Organización",
|
|
1640
1644
|
admin_note:"Esta cuenta de administrador se creará automáticamente al finalizar la instalación.",
|
|
1641
1645
|
err_admin_email:"El correo del administrador es obligatorio.",
|
|
1646
|
+
err_admin_email_invalid:"Por favor, introduce una dirección de correo electrónico válida.",
|
|
1642
1647
|
err_admin_pass:"La contraseña es obligatoria.",
|
|
1643
1648
|
err_admin_pass2:"Las contraseñas no coinciden.",
|
|
1644
1649
|
err_admin_name:"El nombre completo es obligatorio.",
|
|
@@ -1760,6 +1765,7 @@ const T = {
|
|
|
1760
1765
|
admin_org_lbl:"المؤسسة",
|
|
1761
1766
|
admin_note:"سيتم إنشاء حساب المسؤول تلقائيًا بعد اكتمال التثبيت.",
|
|
1762
1767
|
err_admin_email:"البريد الإلكتروني للمسؤول مطلوب.",
|
|
1768
|
+
err_admin_email_invalid:"يرجى إدخال عنوان بريد إلكتروني صالح.",
|
|
1763
1769
|
err_admin_pass:"كلمة المرور مطلوبة.",
|
|
1764
1770
|
err_admin_pass2:"كلمتا المرور غير متطابقتين.",
|
|
1765
1771
|
err_admin_name:"الاسم الكامل مطلوب.",
|
|
@@ -1924,12 +1930,15 @@ function validateStep(s) {
|
|
|
1924
1930
|
return {msg:t('err_overwrite'), field:'overwriteOk'};
|
|
1925
1931
|
}
|
|
1926
1932
|
break;
|
|
1927
|
-
case 6:
|
|
1928
|
-
|
|
1933
|
+
case 6: {
|
|
1934
|
+
const emailVal = val('admin_email');
|
|
1935
|
+
if (!emailVal) return {msg:t('err_admin_email'), field:'admin_email'};
|
|
1936
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailVal)) return {msg:t('err_admin_email_invalid'), field:'admin_email'};
|
|
1929
1937
|
if (!val('admin_name')) return {msg:t('err_admin_name'), field:'admin_name'};
|
|
1930
1938
|
if (!val('admin_pass')) return {msg:t('err_admin_pass'), field:'admin_pass'};
|
|
1931
1939
|
if (val('admin_pass') !== val('admin_pass2')) return {msg:t('err_admin_pass2'), field:'admin_pass2'};
|
|
1932
1940
|
break;
|
|
1941
|
+
}
|
|
1933
1942
|
}
|
|
1934
1943
|
return null;
|
|
1935
1944
|
}
|