Files

97 lines
5.1 KiB
PowerShell

param([switch]$FullCheck, [switch]$RebuildWeb, [switch]$BuildOnly)
$ErrorActionPreference = 'Stop'
$projectRoot = Split-Path -Parent $PSScriptRoot
Set-Location -LiteralPath $projectRoot
$buildScript = Join-Path $PSScriptRoot 'build.ps1'
$binary = Join-Path $projectRoot 'linkport.exe'
$sourceMode = Test-Path -LiteralPath $buildScript
if ($sourceMode) {
$binary = Join-Path $projectRoot 'bin\linkport.exe'
$candidate = Join-Path $projectRoot 'bin\dev-build\linkport.exe'
Write-Host 'Preparing latest linkport (cached frontend and Go compilation)...'
$buildArguments = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $buildScript, '-OutputPath', $candidate, '-Development')
if (!$FullCheck) { $buildArguments += '-SkipTests' }
if ($RebuildWeb) { $buildArguments += '-RebuildWeb' }
& powershell.exe @buildArguments
if ($LASTEXITCODE -ne 0 -or -not (Test-Path -LiteralPath $candidate)) {
throw 'Build failed. The existing service and data have not been changed.'
}
if ($BuildOnly) {
Write-Host "Build-only complete: $candidate"
exit 0
}
} elseif ($BuildOnly -or $FullCheck -or $RebuildWeb) {
throw 'Build options require the source checkout, not an extracted release package.'
} elseif (-not (Test-Path -LiteralPath $binary)) {
throw 'linkport.exe is missing. Extract the complete release ZIP again.'
}
$pathResolver = if ($sourceMode) { $candidate } else { $binary }
$dataPath = & $pathResolver data-path
if ($LASTEXITCODE -ne 0 -or $dataPath -isnot [string] -or ![IO.Path]::IsPathRooted($dataPath)) {
throw 'Cannot resolve the database path. The existing service and data have not been changed.'
}
$dataDirectory = Split-Path -Parent ([IO.Path]::GetFullPath($dataPath))
$backup = Join-Path $projectRoot ('bin\backups\' + (Get-Date -Format 'yyyyMMdd-HHmmss-fff'))
$dataPrefix = $dataDirectory.TrimEnd('\', '/') + [IO.Path]::DirectorySeparatorChar
if ([IO.Path]::GetFullPath($backup).StartsWith($dataPrefix, [StringComparison]::OrdinalIgnoreCase)) {
throw 'The data directory contains the backup destination. Use a separate data directory to avoid recursive backups.'
}
Write-Host 'Stopping previous linkport service...'
$ownedPaths = @((Join-Path $projectRoot 'linkport.exe'), (Join-Path $projectRoot 'bin\linkport.exe'))
foreach ($previousProcess in @(Get-Process -Name linkport -ErrorAction SilentlyContinue)) {
try {
if ($previousProcess.HasExited) { continue }
$previousPath = $previousProcess.Path
if (!$previousPath) {
if ($previousProcess.HasExited) { continue }
throw "Cannot determine the executable path of linkport PID $($previousProcess.Id). Stop it manually before retrying."
}
if ($previousPath -notin $ownedPaths) { continue }
Write-Host "Stopping owned linkport PID $($previousProcess.Id): $previousPath"
$previousProcess.Kill()
if (-not $previousProcess.WaitForExit(10000)) { throw "Previous linkport PID $($previousProcess.Id) did not exit within 10 seconds." }
} catch {
if (!$previousProcess.HasExited) { throw }
} finally { $previousProcess.Dispose() }
}
Write-Host 'Previous linkport service check complete.'
if (Test-Path -LiteralPath $dataDirectory) {
$hashProvider = [Security.Cryptography.SHA256]::Create()
try {
$lockHash = ([BitConverter]::ToString($hashProvider.ComputeHash([Text.Encoding]::UTF8.GetBytes(([IO.Path]::GetFullPath($dataPath)).ToLowerInvariant())))).Replace('-', '').ToLowerInvariant()
} finally { $hashProvider.Dispose() }
$createdMutex = $false
$dataMutex = New-Object Threading.Mutex($false, "Local\linkport-$lockHash", [ref]$createdMutex)
try {
if (!$createdMutex) { throw 'The selected database is in use by another linkport instance.' }
Write-Host "Backing up data directory (excluding audit and runtime logs): $dataDirectory"
New-Item -ItemType Directory -Path $backup -Force | Out-Null
$backupDirectory = Join-Path $backup (Split-Path $dataDirectory -Leaf)
New-Item -ItemType Directory -Path $backupDirectory -Force | Out-Null
$databaseFiles = @($dataPath, "$dataPath-wal", "$dataPath-shm", "$dataPath-journal")
foreach ($entry in Get-ChildItem -LiteralPath $dataDirectory -Force) {
if ($entry.FullName -notin $databaseFiles) {
if ($entry.PSIsContainer -and $entry.Name -in @('audit', 'logs')) { continue }
if (!$entry.PSIsContainer -and ($entry.Name -like '*.log' -or $entry.Name -like '*.log.*')) { continue }
}
Copy-Item -LiteralPath $entry.FullName -Destination $backupDirectory -Recurse -Force
}
Write-Host "Data backup: $backup"
} finally {
$dataMutex.Dispose()
}
}
if ($sourceMode) {
New-Item -ItemType Directory -Force (Split-Path $binary -Parent) | Out-Null
Copy-Item -LiteralPath $candidate -Destination $binary -Force
}
$env:LINKPORT_AUTH_ENABLED = 'false'
$env:LINKPORT_ADMIN_USER = ''
$env:LINKPORT_ADMIN_PASSWORD = ''
$env:LINKPORT_SECURE_COOKIE = 'false'
$env:LINKPORT_TLS_CERT = ''
$env:LINKPORT_TLS_KEY = ''
Write-Host "SQLite: $dataPath"
& $binary
exit $LASTEXITCODE