553 lines
21 KiB
PowerShell
553 lines
21 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Установка зависимостей, генерация тестовых данных и запуск mock-сервера.
|
|
|
|
.DESCRIPTION
|
|
Скрипт выполняет:
|
|
1. Проверяет/устанавливает Python 3.12+
|
|
2. Устанавливает Flask (pip install flask)
|
|
3. Находит config.ini и БД
|
|
4. Проверяет наличие БД и активных данных (devices, bank_profiles, materials)
|
|
5. Генерирует default_profile.json и scenarios из БД
|
|
6. Переключает config.ini на mock (apiBase=http://127.0.0.1:PORT)
|
|
7. Показывает сводку по данным из БД
|
|
8. Запускает mock-сервер и открывает отчёт в браузере
|
|
|
|
.PARAMETER Port
|
|
Порт mock-сервера (default: 8888)
|
|
|
|
.PARAMETER FtPerMaterial
|
|
Сколько FETCH_TRANSACTIONS на материал при бутстрапе (default: 3)
|
|
|
|
.PARAMETER SkipInstall
|
|
Пропустить установку Python/Flask (если уже установлены)
|
|
|
|
.PARAMETER GenerateOnly
|
|
Только сгенерировать данные, не запускать сервер
|
|
|
|
.EXAMPLE
|
|
.\setup.ps1
|
|
.\setup.ps1 -Port 9999 -FtPerMaterial 5
|
|
.\setup.ps1 -SkipInstall
|
|
.\setup.ps1 -GenerateOnly
|
|
#>
|
|
|
|
param(
|
|
[int]$Port = 8888,
|
|
[int]$FtPerMaterial = 3,
|
|
[switch]$SkipInstall,
|
|
[switch]$GenerateOnly,
|
|
[switch]$Clean
|
|
)
|
|
|
|
$ErrorActionPreference = "Continue"
|
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
$Host.UI.RawUI.WindowTitle = "ARC Mock Server Setup"
|
|
|
|
# ─── Helpers ───────────────────────────────────────────────────────────────
|
|
|
|
function Write-Step([string]$n, [string]$msg) {
|
|
Write-Host "`n=== [$n] $msg ===" -ForegroundColor Cyan
|
|
}
|
|
|
|
function Write-Ok([string]$msg) {
|
|
Write-Host " OK: $msg" -ForegroundColor Green
|
|
}
|
|
|
|
function Write-Warn([string]$msg) {
|
|
Write-Host " WARN: $msg" -ForegroundColor Yellow
|
|
}
|
|
|
|
function Write-Err([string]$msg) {
|
|
Write-Host " ERROR: $msg" -ForegroundColor Red
|
|
}
|
|
|
|
function Exit-WithError([string]$msg) {
|
|
Write-Err $msg
|
|
Write-Host "`nPress any key to exit..." -ForegroundColor Gray
|
|
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
|
|
exit 1
|
|
}
|
|
|
|
# ─── 1. Find script and project directories ───────────────────────────────
|
|
|
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
|
|
|
$configPath = $null
|
|
$configCandidates = @(
|
|
(Join-Path $scriptDir "..\..\cmake-build-debug\config.ini"),
|
|
(Join-Path $scriptDir "..\..\config.ini"),
|
|
(Join-Path $scriptDir "..\config.ini"),
|
|
(Join-Path $scriptDir "config.ini")
|
|
)
|
|
foreach ($c in $configCandidates) {
|
|
$resolved = [System.IO.Path]::GetFullPath($c)
|
|
if (Test-Path $resolved) {
|
|
$configPath = $resolved
|
|
$projectRoot = Split-Path -Parent $resolved
|
|
break
|
|
}
|
|
}
|
|
|
|
if (-not $configPath) {
|
|
Exit-WithError "config.ini not found. Run from project root or Release/tests/mock_server/"
|
|
}
|
|
|
|
Write-Host "Project root : $projectRoot" -ForegroundColor Gray
|
|
Write-Host "Config : $configPath" -ForegroundColor Gray
|
|
Write-Host "Script dir : $scriptDir" -ForegroundColor Gray
|
|
|
|
# ─── 2. Python ─────────────────────────────────────────────────────────────
|
|
|
|
Write-Step "1/6" "Python"
|
|
|
|
$pythonExe = $null
|
|
|
|
function Find-Python {
|
|
foreach ($cmd in @("python", "python3", "py")) {
|
|
try {
|
|
$ver = & $cmd --version 2>&1
|
|
if ($ver -match "Python\s+3\.(\d+)") {
|
|
if ([int]$Matches[1] -ge 9) {
|
|
return (Get-Command $cmd).Source
|
|
}
|
|
}
|
|
} catch {}
|
|
}
|
|
$paths = @(
|
|
"$env:LOCALAPPDATA\Programs\Python\Python3*\python.exe",
|
|
"$env:LOCALAPPDATA\Programs\Python\Python31*\python.exe",
|
|
"C:\Python3*\python.exe"
|
|
)
|
|
foreach ($pattern in $paths) {
|
|
$found = Get-ChildItem -Path $pattern -ErrorAction SilentlyContinue |
|
|
Sort-Object Name -Descending | Select-Object -First 1
|
|
if ($found) {
|
|
$ver = & $found.FullName --version 2>&1
|
|
if ($ver -match "Python\s+3\.(\d+)" -and [int]$Matches[1] -ge 9) {
|
|
return $found.FullName
|
|
}
|
|
}
|
|
}
|
|
return $null
|
|
}
|
|
|
|
if (-not $SkipInstall) {
|
|
$pythonExe = Find-Python
|
|
if ($pythonExe) {
|
|
$ver = & $pythonExe --version 2>&1
|
|
Write-Ok "Found: $ver ($pythonExe)"
|
|
} else {
|
|
Write-Warn "Python not found - installing via winget..."
|
|
try {
|
|
winget install Python.Python.3.12 --accept-source-agreements --accept-package-agreements --silent 2>&1 | Out-Null
|
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" +
|
|
[System.Environment]::GetEnvironmentVariable("Path", "User")
|
|
$pythonExe = Find-Python
|
|
if ($pythonExe) {
|
|
$ver = & $pythonExe --version 2>&1
|
|
Write-Ok "Installed: $ver"
|
|
} else {
|
|
Exit-WithError "Python installed but not in PATH. Restart terminal and try again."
|
|
}
|
|
} catch {
|
|
Exit-WithError "Failed to install Python. Install manually: https://python.org"
|
|
}
|
|
}
|
|
} else {
|
|
$pythonExe = Find-Python
|
|
if (-not $pythonExe) {
|
|
Exit-WithError "Python not found. Remove -SkipInstall or install manually."
|
|
}
|
|
Write-Ok "Python: $pythonExe"
|
|
}
|
|
|
|
# ─── Generate helper scripts ──────────────────────────────────────────────
|
|
|
|
$genFtPs1 = Join-Path $scriptDir "gen_transactions.ps1"
|
|
$runServerPs1 = Join-Path $scriptDir "run_server.ps1"
|
|
|
|
# Shared config-finder block for helper scripts
|
|
$configFinderBlock = @'
|
|
$_configCandidates = @(
|
|
(Join-Path $PSScriptRoot "..\..\cmake-build-debug\config.ini"),
|
|
(Join-Path $PSScriptRoot "..\..\config.ini"),
|
|
(Join-Path $PSScriptRoot "..\config.ini"),
|
|
(Join-Path $PSScriptRoot "config.ini")
|
|
)
|
|
$_configPath = $null
|
|
foreach ($_c in $_configCandidates) {
|
|
$_resolved = [System.IO.Path]::GetFullPath($_c)
|
|
if (Test-Path $_resolved) { $_configPath = $_resolved; break }
|
|
}
|
|
if (-not $_configPath) { Write-Host "ERROR: config.ini not found" -ForegroundColor Red; exit 1 }
|
|
$_configArg = @("--config", $_configPath)
|
|
'@
|
|
|
|
# gen_transactions.ps1
|
|
$genFtContent = @"
|
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
$configFinderBlock
|
|
Write-Host "Config: `$_configPath" -ForegroundColor Gray
|
|
& "$pythonExe" "`$PSScriptRoot\gen_fetch_transactions.py" @_configArg @args
|
|
"@
|
|
[System.IO.File]::WriteAllText($genFtPs1, $genFtContent, [System.Text.UTF8Encoding]::new($false))
|
|
|
|
# run_server.ps1
|
|
$runServerContent = @"
|
|
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
|
|
& "$pythonExe" "`$PSScriptRoot\mock_server.py" --port 8888 @args
|
|
"@
|
|
[System.IO.File]::WriteAllText($runServerPs1, $runServerContent, [System.Text.UTF8Encoding]::new($false))
|
|
|
|
Write-Ok "Created gen_transactions.ps1, run_server.ps1"
|
|
|
|
# ─── 3. Flask ──────────────────────────────────────────────────────────────
|
|
|
|
Write-Step "2/6" "Flask"
|
|
|
|
$flaskInstalled = $false
|
|
try {
|
|
$pipOut = & $pythonExe -m pip show flask 2>&1
|
|
if ($pipOut -match "Name:\s*Flask") {
|
|
$flaskVer = ($pipOut | Select-String "Version:\s*(.+)").Matches.Groups[1].Value
|
|
Write-Ok "Flask $flaskVer already installed"
|
|
$flaskInstalled = $true
|
|
}
|
|
} catch {}
|
|
|
|
if (-not $flaskInstalled) {
|
|
Write-Host " Installing Flask..." -ForegroundColor Gray
|
|
& $pythonExe -m pip install flask --quiet 2>&1
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Exit-WithError "Failed to install Flask. Try: $pythonExe -m pip install flask"
|
|
}
|
|
Write-Ok "Flask installed"
|
|
}
|
|
|
|
# ─── 4. Database check ────────────────────────────────────────────────────
|
|
|
|
Write-Step "3/6" "Database"
|
|
|
|
$configContent = Get-Content $configPath -Encoding UTF8
|
|
$dbMatch = $configContent | Select-String "dbPath\s*=\s*(.+)"
|
|
if (-not $dbMatch) {
|
|
Exit-WithError "[db] dbPath not found in config.ini"
|
|
}
|
|
$dbPathRaw = $dbMatch.Matches.Groups[1].Value.Trim()
|
|
|
|
if ([System.IO.Path]::IsPathRooted($dbPathRaw)) {
|
|
$dbPath = $dbPathRaw
|
|
} else {
|
|
$dbPath = [System.IO.Path]::GetFullPath((Join-Path $projectRoot $dbPathRaw))
|
|
}
|
|
|
|
Write-Host " DB path: $dbPath" -ForegroundColor Gray
|
|
|
|
if (-not (Test-Path $dbPath)) {
|
|
Exit-WithError ("DB not found: $dbPath`n`n" +
|
|
"To create the DB:`n" +
|
|
" 1. Set apiBase to production server in config.ini`n" +
|
|
" 2. Run ARC.exe and log in`n" +
|
|
" 3. Devices, profiles and materials will appear in the DB`n" +
|
|
" 4. Re-run this script")
|
|
}
|
|
|
|
Write-Ok "DB found: $dbPath"
|
|
|
|
# Write a temp Python helper that queries DB and outputs structured data
|
|
$dbHelperPy = Join-Path $env:TEMP "arc_db_check.py"
|
|
@'
|
|
import sqlite3, sys, os
|
|
|
|
sys.stdout.reconfigure(encoding='utf-8')
|
|
db_path = sys.argv[1]
|
|
mode = sys.argv[2] if len(sys.argv) > 2 else "count"
|
|
pool_dir = sys.argv[3] if len(sys.argv) > 3 else ""
|
|
|
|
conn = sqlite3.connect(db_path)
|
|
conn.row_factory = sqlite3.Row
|
|
|
|
if mode == "count":
|
|
cnt = conn.execute("""
|
|
SELECT COUNT(*) FROM devices d
|
|
JOIN bank_profiles bp ON bp.device_id = d.id
|
|
JOIN materials m ON m.device_id = d.id AND m.app_code = bp.code
|
|
WHERE bp.status = 'active' AND m.status = 'active'
|
|
AND m.material_id != '' AND bp.bank_profile_id != ''
|
|
""").fetchone()[0]
|
|
conn.close()
|
|
print(cnt)
|
|
sys.exit(0 if cnt > 0 else 1)
|
|
|
|
elif mode == "clean_events":
|
|
try:
|
|
cnt = conn.execute("SELECT COUNT(*) FROM events").fetchone()[0]
|
|
conn.execute("DELETE FROM events")
|
|
conn.commit()
|
|
print(cnt)
|
|
except Exception:
|
|
print(0)
|
|
conn.close()
|
|
sys.exit(0)
|
|
|
|
elif mode == "summary":
|
|
devices = conn.execute("SELECT id, name, api_id, adb_serial FROM devices").fetchall()
|
|
profiles = conn.execute("""
|
|
SELECT bp.code, bp.full_name, bp.phone, bp.status, d.name AS device
|
|
FROM bank_profiles bp JOIN devices d ON d.id = bp.device_id
|
|
WHERE bp.status = 'active' AND bp.bank_profile_id != ''
|
|
ORDER BY d.name, bp.code
|
|
""").fetchall()
|
|
materials = conn.execute("""
|
|
SELECT m.material_id, m.card_number, m.last_numbers, m.currency, m.status,
|
|
m.app_code, d.name AS device
|
|
FROM materials m JOIN devices d ON d.id = m.device_id
|
|
WHERE m.status = 'active' AND m.material_id != ''
|
|
ORDER BY d.name, m.app_code
|
|
""").fetchall()
|
|
conn.close()
|
|
|
|
print("DEVICES|" + str(len(devices)))
|
|
for d in devices:
|
|
serial = d['adb_serial'] or '-'
|
|
api = d['api_id'] or '-'
|
|
print(f" DEV|{d['name']}|{serial}|{api}")
|
|
|
|
print("PROFILES|" + str(len(profiles)))
|
|
for p in profiles:
|
|
name = p['full_name'] or '-'
|
|
phone = p['phone'] or '-'
|
|
print(f" PRF|{p['device']}|{p['code']}|{name}|{phone}")
|
|
|
|
print("MATERIALS|" + str(len(materials)))
|
|
for m in materials:
|
|
card = m['card_number'] or ('****' + m['last_numbers'] if m['last_numbers'] else '-')
|
|
print(f" MAT|{m['device']}|{m['app_code']}|{card}|{m['currency']}|{m['material_id'][:12]}")
|
|
|
|
pool_n = 0
|
|
if pool_dir and os.path.isdir(pool_dir):
|
|
pool_n = len([f for f in os.listdir(pool_dir) if f.endswith('.json')])
|
|
print(f"POOL|{pool_n}")
|
|
'@ | Set-Content -Path $dbHelperPy -Encoding UTF8
|
|
|
|
# Check active materials count
|
|
$matCount = & $pythonExe $dbHelperPy $dbPath "count" 2>&1
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Exit-WithError ("DB exists but no active materials found.`n`n" +
|
|
"To populate:`n" +
|
|
" 1. Set apiBase to production server`n" +
|
|
" 2. Run ARC.exe, log in, add devices and profiles`n" +
|
|
" 3. Re-run this script")
|
|
}
|
|
|
|
Write-Ok "Active materials in DB: $matCount"
|
|
|
|
# Clean events table
|
|
$eventsCleared = & $pythonExe $dbHelperPy $dbPath "clean_events" 2>&1
|
|
if ($eventsCleared -and [int]$eventsCleared -gt 0) {
|
|
Write-Ok "Cleared $eventsCleared events from DB"
|
|
} else {
|
|
Write-Ok "Events table already empty"
|
|
}
|
|
|
|
# ─── 5. Generate mock data ────────────────────────────────────────────────
|
|
|
|
Write-Step "4/6" "Generate test data"
|
|
|
|
# Clean old generated data
|
|
$oldProfile = Join-Path $scriptDir "default_profile.json"
|
|
if (Test-Path $oldProfile) {
|
|
Remove-Item $oldProfile -Force
|
|
Write-Host " Cleaned: default_profile.json" -ForegroundColor Gray
|
|
}
|
|
$scenariosDir = Join-Path $scriptDir "scenarios"
|
|
if (Test-Path $scenariosDir) {
|
|
$oldScenarios = Get-ChildItem "$scenariosDir\*.json" -ErrorAction SilentlyContinue
|
|
if ($oldScenarios) {
|
|
$oldScenarios | Remove-Item -Force
|
|
Write-Host " Cleaned: scenarios/ ($($oldScenarios.Count) files)" -ForegroundColor Gray
|
|
}
|
|
}
|
|
# -Clean: also wipe the transaction pool
|
|
$poolDir = Join-Path $scriptDir "scenarios\pool"
|
|
if ($Clean -and (Test-Path $poolDir)) {
|
|
$oldPool = Get-ChildItem "$poolDir\*.json" -ErrorAction SilentlyContinue
|
|
if ($oldPool) {
|
|
$oldPool | Remove-Item -Force
|
|
Write-Host " Cleaned: scenarios/pool/ ($($oldPool.Count) files)" -ForegroundColor Gray
|
|
}
|
|
}
|
|
|
|
$genScript = Join-Path $scriptDir "gen_mock_data.py"
|
|
if (-not (Test-Path $genScript)) {
|
|
Exit-WithError "gen_mock_data.py not found in $scriptDir"
|
|
}
|
|
|
|
$genOutput = & $pythonExe $genScript --config $configPath 2>&1
|
|
$genOutput | ForEach-Object { Write-Host " $_" }
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Exit-WithError "Data generation failed"
|
|
}
|
|
|
|
$profileJson = Join-Path $scriptDir "default_profile.json"
|
|
if (Test-Path $profileJson) {
|
|
Write-Ok "default_profile.json created"
|
|
} else {
|
|
Exit-WithError "default_profile.json was not created"
|
|
}
|
|
|
|
$poolDir = Join-Path $scriptDir "scenarios\pool"
|
|
$poolCount = 0
|
|
if (Test-Path $poolDir) {
|
|
$poolFiles = Get-ChildItem "$poolDir\*.json" -ErrorAction SilentlyContinue
|
|
if ($poolFiles) { $poolCount = $poolFiles.Count }
|
|
}
|
|
if ($poolCount -gt 0) {
|
|
Write-Ok "Transaction pool: $poolCount files"
|
|
} else {
|
|
Write-Warn "Transaction pool is empty - bootstrap will only create FETCH_PROFILE tasks"
|
|
Write-Host " To generate pool run: $pythonExe gen_fetch_transactions.py" -ForegroundColor Gray
|
|
}
|
|
|
|
# ─── 6. Switch config to mock ─────────────────────────────────────────────
|
|
|
|
Write-Step "5/6" "Switch config.ini to mock"
|
|
|
|
$mockBase = "http://127.0.0.1:$Port"
|
|
$configText = Get-Content $configPath -Raw -Encoding UTF8
|
|
|
|
# Find the active (non-commented) apiBase line
|
|
$configLines = Get-Content $configPath -Encoding UTF8
|
|
$activeIdx = -1
|
|
$currentBase = ""
|
|
for ($i = 0; $i -lt $configLines.Count; $i++) {
|
|
if ($configLines[$i] -match "^\s*apiBase\s*=\s*(.+)") {
|
|
$activeIdx = $i
|
|
$currentBase = $Matches[1].Trim()
|
|
break
|
|
}
|
|
}
|
|
|
|
if ($activeIdx -eq -1) {
|
|
Exit-WithError "apiBase not found in config.ini"
|
|
}
|
|
|
|
if ($currentBase -eq $mockBase) {
|
|
Write-Ok "apiBase already points to mock: $mockBase"
|
|
} else {
|
|
$backupPath = "$configPath.prod_backup"
|
|
if (-not (Test-Path $backupPath)) {
|
|
Copy-Item $configPath $backupPath
|
|
Write-Host " Backup saved: $backupPath" -ForegroundColor Gray
|
|
}
|
|
# Comment out old line, insert mock line after it
|
|
$configLines[$activeIdx] = "#$($configLines[$activeIdx])"
|
|
$before = $configLines[0..$activeIdx]
|
|
$after = if ($activeIdx + 1 -lt $configLines.Count) { $configLines[($activeIdx + 1)..($configLines.Count - 1)] } else { @() }
|
|
$configLines = $before + @("apiBase=$mockBase") + $after
|
|
$newContent = ($configLines -join "`r`n") + "`r`n"
|
|
[System.IO.File]::WriteAllText($configPath, $newContent, [System.Text.UTF8Encoding]::new($false))
|
|
Write-Ok "apiBase switched: $currentBase -> $mockBase"
|
|
}
|
|
|
|
if ($GenerateOnly) {
|
|
Write-Host "`n=== Done (generate only) ===" -ForegroundColor Green
|
|
Write-Host "To start server: $pythonExe mock_server.py --port $Port" -ForegroundColor Gray
|
|
exit 0
|
|
}
|
|
|
|
# ─── 7. Start mock server ─────────────────────────────────────────────────
|
|
|
|
Write-Step "6/6" "Start mock server"
|
|
|
|
# Kill old process on this port if any
|
|
$portCheck = netstat -ano 2>$null | Select-String ":${Port}\s.*LISTENING"
|
|
if ($portCheck) {
|
|
$oldPid = ($portCheck -split '\s+')[-1]
|
|
if ($oldPid -and $oldPid -ne "0") {
|
|
Write-Warn "Port $Port occupied by PID $oldPid - killing..."
|
|
taskkill /PID $oldPid /F 2>$null | Out-Null
|
|
Start-Sleep -Seconds 1
|
|
Write-Ok "Old process killed"
|
|
}
|
|
}
|
|
|
|
$mockScript = Join-Path $scriptDir "mock_server.py"
|
|
|
|
# ─── Summary banner with DB data ──────────────────────────────────────────
|
|
|
|
$poolDirArg = Join-Path $scriptDir "scenarios\pool"
|
|
$bannerLines = & $pythonExe $dbHelperPy $dbPath "summary" $poolDirArg 2>&1
|
|
|
|
Write-Host ""
|
|
Write-Host "================================================================" -ForegroundColor Cyan
|
|
Write-Host " ARC Mock Server - Summary " -ForegroundColor Cyan
|
|
Write-Host "================================================================" -ForegroundColor Cyan
|
|
|
|
foreach ($line in $bannerLines) {
|
|
$l = $line.ToString().Trim()
|
|
|
|
if ($l -match "^DEVICES\|(\d+)") {
|
|
Write-Host ""
|
|
Write-Host " Devices ($($Matches[1])):" -ForegroundColor White
|
|
Write-Host " ----------------------------------------------------------" -ForegroundColor DarkGray
|
|
Write-Host (" {0,-30} {1,-20} {2}" -f "Name", "ADB Serial", "API ID") -ForegroundColor DarkGray
|
|
}
|
|
elseif ($l -match "^PROFILES\|(\d+)") {
|
|
Write-Host ""
|
|
Write-Host " Bank profiles ($($Matches[1])):" -ForegroundColor White
|
|
Write-Host " ----------------------------------------------------------" -ForegroundColor DarkGray
|
|
Write-Host (" {0,-25} {1,-20} {2,-20} {3}" -f "Device", "Bank", "Name", "Phone") -ForegroundColor DarkGray
|
|
}
|
|
elseif ($l -match "^MATERIALS\|(\d+)") {
|
|
Write-Host ""
|
|
Write-Host " Materials ($($Matches[1])):" -ForegroundColor White
|
|
Write-Host " ----------------------------------------------------------" -ForegroundColor DarkGray
|
|
Write-Host (" {0,-25} {1,-20} {2,-20} {3,-5} {4}" -f "Device", "Bank", "Card", "Cur.", "Material ID") -ForegroundColor DarkGray
|
|
}
|
|
elseif ($l -match "^POOL\|(\d+)") {
|
|
Write-Host ""
|
|
if ([int]$Matches[1] -gt 0) {
|
|
Write-Host " Transaction pool: $($Matches[1]) tasks" -ForegroundColor Green
|
|
} else {
|
|
Write-Host " Transaction pool: empty (only FETCH_PROFILE at bootstrap)" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
elseif ($l -match "^\s*DEV\|([^|]+)\|([^|]+)\|(.+)") {
|
|
Write-Host (" {0,-30} {1,-20} {2}" -f $Matches[1], $Matches[2], $Matches[3]) -ForegroundColor Gray
|
|
}
|
|
elseif ($l -match "^\s*PRF\|([^|]+)\|([^|]+)\|([^|]+)\|(.+)") {
|
|
Write-Host (" {0,-25} {1,-20} {2,-20} {3}" -f $Matches[1], $Matches[2], $Matches[3], $Matches[4]) -ForegroundColor Gray
|
|
}
|
|
elseif ($l -match "^\s*MAT\|([^|]+)\|([^|]+)\|([^|]+)\|([^|]+)\|(.+)") {
|
|
Write-Host (" {0,-25} {1,-20} {2,-20} {3,-5} {4}" -f $Matches[1], $Matches[2], $Matches[3], $Matches[4], $Matches[5]) -ForegroundColor Gray
|
|
}
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host " ==========================================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
Write-Host " Mock server: " -NoNewline -ForegroundColor White
|
|
Write-Host "http://127.0.0.1:$Port" -ForegroundColor Green
|
|
Write-Host " HTML report: " -NoNewline -ForegroundColor White
|
|
Write-Host "http://127.0.0.1:${Port}/_admin/report/html" -ForegroundColor Green
|
|
Write-Host " State: " -NoNewline -ForegroundColor White
|
|
Write-Host "http://127.0.0.1:${Port}/_admin/state" -ForegroundColor Green
|
|
Write-Host ""
|
|
Write-Host " FT/material: $FtPerMaterial" -ForegroundColor Gray
|
|
Write-Host " Config: $configPath" -ForegroundColor Gray
|
|
Write-Host ""
|
|
Write-Host " Ctrl+C to stop the server" -ForegroundColor Yellow
|
|
Write-Host " After testing restore: apiBase=http://93.183.75.134:8005" -ForegroundColor Yellow
|
|
Write-Host ""
|
|
|
|
# Cleanup temp helper
|
|
Remove-Item $dbHelperPy -ErrorAction SilentlyContinue
|
|
|
|
# Open report in browser
|
|
Start-Process "http://127.0.0.1:${Port}/_admin/report/html"
|
|
|
|
# Launch server (blocks until Ctrl+C)
|
|
& $pythonExe $mockScript --host 127.0.0.1 --port $Port --ft-per-material $FtPerMaterial
|