diff --git a/packaging/README.md b/packaging/README.md index 9703c61..3da2d65 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -21,8 +21,6 @@ This directory builds a Windows deliverable with: **Offline:** Setup ships portable PostgreSQL, `.venv` (when built with `-CreateVenv`), and WinSW. First-run uses `-NonInteractive -DbMode bundled` — **no GitHub/EDB download on the target PC**. Service install uses bundled WinSW (pass `-AllowDownload` only on a build/dev machine if the binary is missing). Auto-update still needs network later, and is unchecked by default. -**OS:** Windows 10/11 or Windows Server **2016+** recommended. Packaging scripts are UTF-8 **with BOM** so Chinese UI works on Windows PowerShell 5.x. Bundled Python in current releases is **3.13+**, which does **not** support Windows Server 2012 R2 — use Server 2016+ or a newer desktop OS. - ## Build (developer machine) Prerequisites: Python 3.11+, Node 20+, PowerShell, network (to download PG binaries once). diff --git a/packaging/_common.ps1 b/packaging/_common.ps1 index b69c87b..4bba789 100644 --- a/packaging/_common.ps1 +++ b/packaging/_common.ps1 @@ -1,4 +1,4 @@ -# Shared path helpers for Windows packaging scripts. +# Shared path helpers for Windows packaging scripts. # Dot-source: . "$PSScriptRoot\_common.ps1" $ErrorActionPreference = "Stop" @@ -148,7 +148,6 @@ function Get-NetxDataEnvMap { "NETX_AUTH_MCP_TOKEN_FILE" = (ConvertTo-NetxFsPath (Join-Path $d "data\auth\mcp_token")) "NETX_AUTH_SECRET_FILE" = (ConvertTo-NetxFsPath (Join-Path $d "data\auth\jwt_secret")) "NETX_SCHEDULER_HEARTBEAT_PATH" = (ConvertTo-NetxFsPath (Join-Path $d "data\runtime\scheduler_heartbeat.json")) - "NETX_RUN_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\runtime")) "NETX_BIZ_STATE_SPOOL_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\biz_state_spool")) "NETX_NE_COLLECTION_DATA_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\ne_collections")) "NETX_NE_EXEC_JOB_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\ne_exec_jobs")) diff --git a/packaging/build_release.ps1 b/packaging/build_release.ps1 index a1f1437..b8fc5c4 100644 --- a/packaging/build_release.ps1 +++ b/packaging/build_release.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$Version = "", [string]$OutDir = "", [switch]$SkipWebBuild = $false, @@ -80,22 +80,6 @@ $webOut = Join-Path $stage "web\dist" New-Item -ItemType Directory -Path (Split-Path $webOut -Parent) -Force | Out-Null Copy-Item -Path $dist -Destination $webOut -Recurse -Force -function Write-Utf8BomFile { - param([string]$Path) - # Windows PowerShell 4/5 (Server 2012+) mis-parses UTF-8 without BOM when scripts contain CJK. - $utf8Bom = New-Object System.Text.UTF8Encoding $true - $bytes = [IO.File]::ReadAllBytes($Path) - $hasBom = ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) - $text = if ($hasBom) { - [Text.Encoding]::UTF8.GetString($bytes, 3, $bytes.Length - 3) - } else { - [Text.Encoding]::UTF8.GetString($bytes) - } - $text = $text -replace "`r`n", "`n" -replace "`n", "`r`n" - if (-not $text.EndsWith("`r`n")) { $text += "`r`n" } - [IO.File]::WriteAllText($Path, $text, $utf8Bom) -} - $packOut = Join-Path $stage "packaging" New-Item -ItemType Directory -Path $packOut -Force | Out-Null Copy-Item -Path (Join-Path $PSScriptRoot "_common.ps1") -Destination $packOut -Force @@ -103,15 +87,13 @@ foreach ($name in @( "download_postgres.ps1", "setup_first_run.ps1", "start_netx_app.ps1", "stop_netx_app.ps1", "update_netx.ps1", "check_update.ps1", "launch_shortcut.ps1", "netx_tray.ps1", "install_autostart.ps1", "install_service.ps1", + "service_run.ps1", "install_update_task.ps1", "sign_release.ps1", "build_release.ps1", "publish_release.ps1", "publish_forgejo_release.ps1", "README.md", "manifest.example.json" )) { $src = Join-Path $PSScriptRoot $name if (Test-Path $src) { Copy-Item $src (Join-Path $packOut $name) -Force } } -Get-ChildItem -Path $packOut -Filter *.ps1 -File | ForEach-Object { Write-Utf8BomFile -Path $_.FullName } -Get-ChildItem -Path (Join-Path $stage "scripts") -Filter *.ps1 -File -ErrorAction SilentlyContinue | - ForEach-Object { Write-Utf8BomFile -Path $_.FullName } Copy-Item -Path (Join-Path $PSScriptRoot "config") -Destination (Join-Path $packOut "config") -Recurse -Force Copy-Item -Path (Join-Path $PSScriptRoot "installer") -Destination (Join-Path $packOut "installer") -Recurse -Force $assetsSrc = Join-Path $PSScriptRoot "assets" @@ -157,15 +139,6 @@ $builtAt = (Get-Date).ToUniversalTime().ToString("o") Set-Content -Path (Join-Path $stage ".portable") -Value "1" -Encoding ascii -# Root .cmd launchers (Explorer / Start Menu friendly; ASCII-only). -$cmdSrc = Join-Path $PSScriptRoot "cmd" -foreach ($cmdName in @("NetX-FirstRun.cmd", "NetX-Start.cmd", "NetX-Tray.cmd")) { - $c = Join-Path $cmdSrc $cmdName - if (Test-Path $c) { - Copy-Item -Path $c -Destination (Join-Path $stage $cmdName) -Force - } -} - if ($CreateVenv) { Write-Host "==> Creating .venv in stage (requires Python 3.11+ on PATH)" $py = (Get-Command python -ErrorAction SilentlyContinue) diff --git a/packaging/check_update.ps1 b/packaging/check_update.ps1 index 7f90413..75f552f 100644 --- a/packaging/check_update.ps1 +++ b/packaging/check_update.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [string]$UpdateUrl = "", diff --git a/packaging/cmd/NetX-FirstRun.cmd b/packaging/cmd/NetX-FirstRun.cmd deleted file mode 100644 index c07282e..0000000 --- a/packaging/cmd/NetX-FirstRun.cmd +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -setlocal -set "ROOT=%~dp0" -if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%" -cd /d "%ROOT%" -powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%ROOT%\packaging\launch_shortcut.ps1" -Action setup -ProgramRoot "%ROOT%" -DataRoot "%ProgramData%\NetX" -exit /b %ERRORLEVEL% diff --git a/packaging/cmd/NetX-Start.cmd b/packaging/cmd/NetX-Start.cmd deleted file mode 100644 index 67f3675..0000000 --- a/packaging/cmd/NetX-Start.cmd +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -setlocal -set "ROOT=%~dp0" -if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%" -cd /d "%ROOT%" -powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%ROOT%\packaging\launch_shortcut.ps1" -Action start -ProgramRoot "%ROOT%" -DataRoot "%ProgramData%\NetX" -exit /b %ERRORLEVEL% diff --git a/packaging/cmd/NetX-Tray.cmd b/packaging/cmd/NetX-Tray.cmd deleted file mode 100644 index 262f21e..0000000 --- a/packaging/cmd/NetX-Tray.cmd +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -setlocal -set "ROOT=%~dp0" -if "%ROOT:~-1%"=="\" set "ROOT=%ROOT:~0,-1%" -cd /d "%ROOT%" -powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%ROOT%\packaging\launch_shortcut.ps1" -Action tray -ProgramRoot "%ROOT%" -DataRoot "%ProgramData%\NetX" -StartOnLaunch -exit /b %ERRORLEVEL% diff --git a/packaging/download_postgres.ps1 b/packaging/download_postgres.ps1 index 6398fd1..38c7b41 100644 --- a/packaging/download_postgres.ps1 +++ b/packaging/download_postgres.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$Version = "16.4-1", [string]$OutDir = "" ) diff --git a/packaging/install_autostart.ps1 b/packaging/install_autostart.ps1 index 50510df..d5c2ebd 100644 --- a/packaging/install_autostart.ps1 +++ b/packaging/install_autostart.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [switch]$Remove = $false ) diff --git a/packaging/install_service.ps1 b/packaging/install_service.ps1 index f9e87f6..ff97f17 100644 --- a/packaging/install_service.ps1 +++ b/packaging/install_service.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [ValidateSet("winsw", "task")] diff --git a/packaging/install_update_task.ps1 b/packaging/install_update_task.ps1 index 07b3ab9..9abd2c3 100644 --- a/packaging/install_update_task.ps1 +++ b/packaging/install_update_task.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [ValidateSet("Daily", "AtLogOn", "Hourly")] diff --git a/packaging/installer/netx.iss b/packaging/installer/netx.iss index 5eb1683..0c68bdb 100644 --- a/packaging/installer/netx.iss +++ b/packaging/installer/netx.iss @@ -1,10 +1,10 @@ -; NetX Windows installer (Inno Setup 6+) +; NetX Windows installer (Inno Setup 6+) ; Compile after: packaging\build_release.ps1 ; ISCC.exe packaging\installer\netx.iss #define MyAppName "NetX" #ifndef MyAppVersion - #define MyAppVersion "0.4.5" + #define MyAppVersion "0.4.2" #endif #define MyAppPublisher "NetX" #define MyAppURL "https://github.com/hansjone/netx" @@ -34,7 +34,7 @@ WizardStyle=modern ArchitecturesAllowed=x64compatible ArchitecturesInstallIn64BitMode=x64compatible PrivilegesRequired=admin -; Data lives under {commonappdata}\NetX 鈥?not overwritten by upgrades +; Data lives under {commonappdata}\NetX — not overwritten by upgrades CloseApplications=yes ShowLanguageDialog=yes @@ -50,19 +50,20 @@ english.StartTrayNow=Start NetX tray now english.EnableAutostart=Start NetX tray at Windows logon english.EnableAutoUpdate=Enable daily silent auto-update (needs network later) english.InstallService=Install as Windows Service (uses bundled WinSW, offline) -chinesesimplified.CreateDesktopIcon=鍒涘缓妗岄潰蹇嵎鏂瑰紡 -chinesesimplified.SetupOptions=瀹夎閫夐」: -chinesesimplified.RunFirstSetup=瀹夎鍚庤繍琛岄娆¢厤缃紙鍐呯疆鏁版嵁搴擄紝鍙绾匡級 -chinesesimplified.StartTrayNow=绔嬪嵆鍚姩 NetX 鎵樼洏 -chinesesimplified.EnableAutostart=寮€鏈烘椂鑷姩鍚姩 NetX 鎵樼洏 -chinesesimplified.EnableAutoUpdate=鍚敤姣忔棩闈欓粯鑷姩鏇存柊锛堜互鍚庨渶瑕佽仈缃戯級 -chinesesimplified.InstallService=瀹夎涓?Windows 鏈嶅姟锛堜娇鐢ㄥ凡鎹嗙粦鐨?WinSW锛屽彲绂荤嚎锛? +chinesesimplified.CreateDesktopIcon=创建桌面快捷方式 +chinesesimplified.SetupOptions=安装选项: +chinesesimplified.RunFirstSetup=安装后运行首次配置(内置数据库,可离线) +chinesesimplified.StartTrayNow=立即启动 NetX 托盘 +chinesesimplified.EnableAutostart=开机时自动启动 NetX 托盘 +chinesesimplified.EnableAutoUpdate=启用每日静默自动更新(以后需要联网) +chinesesimplified.InstallService=安装为 Windows 服务(使用已捆绑的 WinSW,可离线) + [Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked Name: "firstrun"; Description: "{cm:RunFirstSetup}"; GroupDescription: "{cm:SetupOptions}"; Flags: checkedonce [Files] -; Entire release stage 鈫?{app}. Exclude .portable so installed builds use ProgramData. +; Entire release stage → {app}. Exclude .portable so installed builds use ProgramData. Source: "{#StageDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: ".portable" [Dirs] @@ -74,20 +75,16 @@ Name: "{commonappdata}\NetX\pgdata" Name: "{commonappdata}\NetX\backups" [Icons] -; Prefer .cmd targets so Server 2012 / classic Start Menu shows normal program entries. -; Also pin First-time setup + Start to common desktop (always), not only optional tray icon. -Name: "{group}\NetX Tray"; Filename: "{app}\NetX-Tray.cmd"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" -Name: "{group}\Start NetX"; Filename: "{app}\NetX-Start.cmd"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" +Name: "{group}\NetX Tray"; Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\packaging\launch_shortcut.ps1"" -Action tray -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -StartOnLaunch"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" +Name: "{group}\Start NetX"; Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\packaging\launch_shortcut.ps1"" -Action start -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" Name: "{group}\Stop NetX"; Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\packaging\launch_shortcut.ps1"" -Action stop -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" Name: "{group}\Check for updates"; Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\packaging\launch_shortcut.ps1"" -Action update -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" Name: "{group}\Open NetX UI"; Filename: "http://127.0.0.1:8890/"; IconFilename: "{app}\packaging\assets\netx.ico" -Name: "{group}\First-time setup"; Filename: "{app}\NetX-FirstRun.cmd"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" +Name: "{group}\First-time setup"; Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\packaging\launch_shortcut.ps1"" -Action setup -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" Name: "{group}\Install Windows Service (admin)"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_service.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -Start"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" Name: "{group}\Enable silent auto-update (daily)"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_update_task.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" Name: "{group}\Enable start at logon"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_autostart.ps1"" -ProgramRoot ""{app}"""; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" -Name: "{commondesktop}\NetX First-time setup"; Filename: "{app}\NetX-FirstRun.cmd"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" -Name: "{commondesktop}\NetX Start"; Filename: "{app}\NetX-Start.cmd"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico" -Name: "{commondesktop}\NetX"; Filename: "{app}\NetX-Tray.cmd"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"; Tasks: desktopicon +Name: "{autodesktop}\NetX"; Filename: "powershell.exe"; Parameters: "-NoProfile -ExecutionPolicy Bypass -File ""{app}\packaging\launch_shortcut.ps1"" -Action tray -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -StartOnLaunch"; WorkingDir: "{app}"; IconFilename: "{app}\packaging\assets\netx.ico"; Tasks: desktopicon [Run] ; First-run is NonInteractive + bundled DB so offline machines succeed without prompts or downloads. @@ -98,6 +95,5 @@ Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\p Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_service.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -Start"; WorkingDir: "{app}"; Description: "{cm:InstallService}"; Flags: postinstall skipifsilent unchecked [UninstallDelete] -; Do NOT delete {commonappdata}\NetX 鈥?preserves DB and secrets across reinstall +; Do NOT delete {commonappdata}\NetX — preserves DB and secrets across reinstall Type: filesandordirs; Name: "{app}" - diff --git a/packaging/launch_shortcut.ps1 b/packaging/launch_shortcut.ps1 index 5a43966..f9f9da7 100644 --- a/packaging/launch_shortcut.ps1 +++ b/packaging/launch_shortcut.ps1 @@ -1,4 +1,4 @@ -param( +param( [ValidateSet("tray", "start", "stop", "setup", "update")] [string]$Action = "tray", [string]$ProgramRoot = "", @@ -50,10 +50,9 @@ function Ensure-NetxEnv { & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $setup ` -ProgramRoot $prog -DataRoot $data -NonInteractive -DbMode bundled if ($LASTEXITCODE -ne 0 -or -not (Test-Path $envPath)) { - $cmd = Join-Path $prog "NetX-FirstRun.cmd" throw (T ` - "First-time setup failed.`nDouble-click: $cmd`nOr: Start Menu → All Programs → NetX → First-time setup`nLog: $log" ` - "首次配置失败。`n请双击: $cmd`n或: 开始菜单 → 所有程序 → NetX → First-time setup`n日志: $log") + "First-time setup failed. Run Start Menu → NetX → First-time setup.`nLog: $log" ` + "首次配置失败。请运行「开始菜单 → NetX → First-time setup」。`n日志: $log") } } diff --git a/packaging/manifest.example.json b/packaging/manifest.example.json index 1d23d3e..3e49db5 100644 --- a/packaging/manifest.example.json +++ b/packaging/manifest.example.json @@ -1,11 +1,11 @@ -{ +{ "channel": "stable", - "latest": "0.4.5", + "latest": "0.4.2", "min_compatible": "0.3.0", - "notes_url": "https://github.com/hansjone/netx/releases/tag/v0.4.5", + "notes_url": "https://github.com/hansjone/netx/releases/tag/v0.4.2", "windows": { - "url": "https://github.com/hansjone/netx/releases/download/v0.4.5/NetX-0.4.5-win64.zip", - "setup_url": "https://github.com/hansjone/netx/releases/download/v0.4.5/NetX-Setup-0.4.5.exe", + "url": "https://github.com/hansjone/netx/releases/download/v0.4.2/NetX-0.4.2-win64.zip", + "setup_url": "https://github.com/hansjone/netx/releases/download/v0.4.2/NetX-Setup-0.4.2.exe", "sha256": "", "size": 0 } diff --git a/packaging/netx_tray.ps1 b/packaging/netx_tray.ps1 index e822fa7..7c19b4f 100644 --- a/packaging/netx_tray.ps1 +++ b/packaging/netx_tray.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [switch]$StartOnLaunch = $true, diff --git a/packaging/publish_forgejo_release.ps1 b/packaging/publish_forgejo_release.ps1 index da5629d..40fd352 100644 --- a/packaging/publish_forgejo_release.ps1 +++ b/packaging/publish_forgejo_release.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$Version = "", [string]$ForgejoBase = "http://10.0.0.131:3000", [string]$Owner = "hansjone", diff --git a/packaging/publish_release.ps1 b/packaging/publish_release.ps1 index 6d9e648..19fa044 100644 --- a/packaging/publish_release.ps1 +++ b/packaging/publish_release.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$Version = "", [switch]$SkipBuild = $false, [switch]$SkipInstaller = $false, diff --git a/packaging/service_run.ps1 b/packaging/service_run.ps1 index e514352..40cc61f 100644 --- a/packaging/service_run.ps1 +++ b/packaging/service_run.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [int]$HealthFailLimit = 6, diff --git a/packaging/setup_first_run.ps1 b/packaging/setup_first_run.ps1 index 6a73e65..8889308 100644 --- a/packaging/setup_first_run.ps1 +++ b/packaging/setup_first_run.ps1 @@ -1,4 +1,4 @@ -param( +param( [ValidateSet("bundled", "external", "")] [string]$DbMode = "", [string]$ProgramRoot = "", @@ -153,37 +153,21 @@ if ($DbMode -eq "bundled") { $env:PGPASSWORD = $BundledPassword try { - function Invoke-NetxPsql { - param([string]$Sql, [string]$Database = "postgres") - $out = & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d $Database -v ON_ERROR_STOP=1 -tAc $Sql 2>&1 - if ($LASTEXITCODE -ne 0) { - throw "psql_failed ($LASTEXITCODE): $Sql`n$out" - } - return (($out | Out-String).Trim()) - } - - $role = Invoke-NetxPsql -Sql "SELECT 1 FROM pg_roles WHERE rolname='netx'" - if ($role -eq "1") { - Invoke-NetxPsql -Sql "ALTER ROLE netx WITH LOGIN PASSWORD '$sqlPw'" | Out-Null + $role = & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='netx'" + if ($role -notmatch "1") { + & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 ` + -c "CREATE ROLE netx LOGIN PASSWORD '$sqlPw';" } else { - Invoke-NetxPsql -Sql "CREATE ROLE netx LOGIN PASSWORD '$sqlPw'" | Out-Null + & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 ` + -c "ALTER ROLE netx WITH LOGIN PASSWORD '$sqlPw';" } - $db = Invoke-NetxPsql -Sql "SELECT 1 FROM pg_database WHERE datname='netx'" - if ($db -ne "1") { - Invoke-NetxPsql -Sql "CREATE DATABASE netx OWNER netx" | Out-Null - } - Invoke-NetxPsql -Sql "GRANT ALL PRIVILEGES ON DATABASE netx TO netx" | Out-Null - # Verify login as app role (catches auth/hba mismatches early). - $prev = $env:PGPASSWORD - $env:PGPASSWORD = $BundledPassword - try { - $ping = & $psql -h 127.0.0.1 -p $BundledPort -U netx -d netx -v ON_ERROR_STOP=1 -tAc "SELECT 1" 2>&1 - if ($LASTEXITCODE -ne 0 -or (($ping | Out-String).Trim()) -ne "1") { - throw "netx_role_login_failed: $ping" - } - } finally { - $env:PGPASSWORD = $prev + $db = & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='netx'" + if ($db -notmatch "1") { + & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 ` + -c "CREATE DATABASE netx OWNER netx;" } + & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 ` + -c "GRANT ALL PRIVILEGES ON DATABASE netx TO netx;" } finally { Remove-Item Env:PGPASSWORD -ErrorAction SilentlyContinue } diff --git a/packaging/sign_release.ps1 b/packaging/sign_release.ps1 index a859447..121c8d9 100644 --- a/packaging/sign_release.ps1 +++ b/packaging/sign_release.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory = $true)] [string[]]$Files, [string]$Thumbprint = "", diff --git a/packaging/start_netx_app.ps1 b/packaging/start_netx_app.ps1 index 6a80f9d..d57781c 100644 --- a/packaging/start_netx_app.ps1 +++ b/packaging/start_netx_app.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [switch]$SkipBrowser = $false, diff --git a/packaging/stop_netx_app.ps1 b/packaging/stop_netx_app.ps1 index 4d04f19..174c631 100644 --- a/packaging/stop_netx_app.ps1 +++ b/packaging/stop_netx_app.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$ProgramRoot = "", [string]$DataRoot = "", [switch]$KeepPostgres = $false diff --git a/packaging/update_netx.ps1 b/packaging/update_netx.ps1 index 0f12cc5..c959f66 100644 --- a/packaging/update_netx.ps1 +++ b/packaging/update_netx.ps1 @@ -1,4 +1,4 @@ -param( +param( [Parameter(Mandatory = $true)] [string]$PackagePath, [string]$ProgramRoot = "", diff --git a/pyproject.toml b/pyproject.toml index 8c54492..8e30807 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "netx-ops" -version = "0.4.5" +version = "0.4.2" description = "netx operations tool: alarm-centric workflows with REST API and stdio MCP" readme = "README.md" requires-python = ">=3.11" @@ -43,4 +43,3 @@ netx-topology-mcp = "netx_topology_mcp.server:main" [tool.setuptools.packages.find] where = ["."] include = ["netx_api*"] - diff --git a/scripts/init_pg.ps1 b/scripts/init_pg.ps1 index cfcb909..d9c02de 100644 --- a/scripts/init_pg.ps1 +++ b/scripts/init_pg.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$PgHost = "127.0.0.1", [int]$PgPort = 5432, [string]$SuperUser = "postgres", diff --git a/scripts/start_netx.ps1 b/scripts/start_netx.ps1 index 7053271..ed2caec 100644 --- a/scripts/start_netx.ps1 +++ b/scripts/start_netx.ps1 @@ -1,4 +1,4 @@ -param( +param( [string]$BindHost = "127.0.0.1", [int]$Port = 8890, [int]$WebPort = 5173, @@ -23,16 +23,9 @@ if ($Backgtound -and -not $Background) { $projectRoot = Split-Path -Parent $PSScriptRoot Set-Location $projectRoot -# Prefer writable data-root runtime dir (Program Files is not writable after Setup install). -if ($env:NETX_RUN_DIR) { - $runDir = $env:NETX_RUN_DIR -} elseif ($env:NETX_SCHEDULER_HEARTBEAT_PATH) { - $runDir = Split-Path -Parent ($env:NETX_SCHEDULER_HEARTBEAT_PATH -replace '/', '\') -} else { - $runDir = Join-Path $PSScriptRoot ".run" -} +$runDir = Join-Path $PSScriptRoot ".run" if (-not (Test-Path $runDir)) { - New-Item -ItemType Directory -Path $runDir -Force | Out-Null + New-Item -ItemType Directory -Path $runDir | Out-Null } $pidFile = Join-Path $runDir "netx.pid" diff --git a/scripts/stop_netx.ps1 b/scripts/stop_netx.ps1 index 1106bb3..2d91466 100644 --- a/scripts/stop_netx.ps1 +++ b/scripts/stop_netx.ps1 @@ -1,4 +1,4 @@ -param( +param( [int]$Port = 8890, [int]$WebPort = 5173, # Windows often ignores graceful Stop-Process on python; default hard-kill. @@ -9,13 +9,7 @@ $ErrorActionPreference = "Continue" $useForce = if ($NoForce) { $false } else { [bool]$Force } -if ($env:NETX_RUN_DIR) { - $runDir = $env:NETX_RUN_DIR -} elseif ($env:NETX_SCHEDULER_HEARTBEAT_PATH) { - $runDir = Split-Path -Parent ($env:NETX_SCHEDULER_HEARTBEAT_PATH -replace '/', '\') -} else { - $runDir = Join-Path $PSScriptRoot ".run" -} +$runDir = Join-Path $PSScriptRoot ".run" $pidFile = Join-Path $runDir "netx.pid" $workerPidFile = Join-Path $runDir "worker.pid" $webPidFile = Join-Path $runDir "web.pid"