97 lines
5.1 KiB
PowerShell
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
|