Files

135 lines
3.6 KiB
PowerShell

$ErrorActionPreference = "Stop"
$toolRoot = Split-Path -Parent $PSCommandPath
$projectRoot = (Resolve-Path (Join-Path $toolRoot "..\..")).Path
$serverPath = Join-Path $toolRoot "server.py"
$reviewRoot = Join-Path $projectRoot "epub_review_sessions"
$venvRoot = Join-Path $toolRoot ".venv"
$venvPython = Join-Path $venvRoot "Scripts\python.exe"
$requirements = Join-Path $toolRoot "requirements.txt"
$versionFile = Join-Path $toolRoot "version.py"
$defaultPort = 5177
$env:PYTHONIOENCODING = "utf-8"
function Get-PythonCommand {
$pyLauncher = Get-Command py -ErrorAction SilentlyContinue
if ($pyLauncher) {
return [pscustomobject]@{ Exe = $pyLauncher.Source; Args = @("-3") }
}
$python = Get-Command python -ErrorAction SilentlyContinue
if ($python) {
return [pscustomobject]@{ Exe = $python.Source; Args = @() }
}
throw "Python was not found. Install Python 3, then run this launcher again."
}
function Invoke-PythonCommand {
param(
[Parameter(Mandatory = $true)]
[string]$Exe,
[string[]]$Args = @()
)
& $Exe @Args
return $LASTEXITCODE
}
function Test-FlaskInstalled {
& $venvPython -c "import importlib.util, sys; sys.exit(0 if importlib.util.find_spec('flask') else 1)" 2>$null
return ($LASTEXITCODE -eq 0)
}
function Get-ExpectedVersion {
if (!(Test-Path $versionFile)) {
return ""
}
$content = Get-Content -Raw -Encoding UTF8 $versionFile
$match = [regex]::Match($content, 'version\s*=\s*"([^"]+)"')
if ($match.Success) {
return $match.Groups[1].Value
}
return ""
}
function Test-LocalPortOpen {
param(
[Parameter(Mandatory = $true)]
[int]$Port
)
$client = New-Object System.Net.Sockets.TcpClient
try {
$async = $client.BeginConnect("127.0.0.1", $Port, $null, $null)
if (!$async.AsyncWaitHandle.WaitOne(100, $false)) {
return $false
}
$client.EndConnect($async)
return $true
} catch {
return $false
} finally {
$client.Close()
}
}
function Get-RunningEditorUrl {
$expectedVersion = Get-ExpectedVersion
for ($port = $defaultPort; $port -lt ($defaultPort + 100); $port++) {
if (!(Test-LocalPortOpen -Port $port)) {
continue
}
$url = "http://127.0.0.1:$port"
try {
$versionPayload = Invoke-RestMethod -Uri "$url/api/version" -TimeoutSec 1 -ErrorAction Stop
if (!$expectedVersion -or $versionPayload.version -eq $expectedVersion) {
return "http://localhost:$port"
}
} catch {
continue
}
}
return ""
}
$runningUrl = Get-RunningEditorUrl
if ($runningUrl) {
Write-Host "EPUB review editor is already running."
Start-Process $runningUrl
Write-Host $runningUrl
Write-Host "review root: $reviewRoot"
exit 0
}
if (!(Test-Path $venvPython)) {
Write-Host "Creating local Python environment..."
$python = Get-PythonCommand
$venvArgs = @()
if ($python.Args) {
$venvArgs += $python.Args
}
$venvArgs += @("-m", "venv", $venvRoot)
if ((Invoke-PythonCommand -Exe $python.Exe -Args $venvArgs) -ne 0) {
throw "Failed to create local Python environment."
}
}
if (!(Test-FlaskInstalled)) {
Write-Host "Installing review editor dependencies..."
& $venvPython -m pip install -r $requirements
if ($LASTEXITCODE -ne 0) {
throw "Failed to install dependencies from requirements.txt."
}
if (!(Test-FlaskInstalled)) {
throw "Dependencies were installed, but Flask is still unavailable in the local Python environment."
}
}
Write-Host "Starting EPUB review editor..."
& $venvPython $serverPath --review-root $reviewRoot --daemon
if ($LASTEXITCODE -ne 0) {
throw "Failed to start EPUB review editor."
}