# Release publish + WebView2 bootstrap download + Inno Setup ISCC # Requires Inno Setup 6 (ISCC.exe) # # 注意:与 YY.Admin\publish.cmd 输出目录不同;本脚本使用 bin\Release\...\win-x64\publish。 # 本地 F5 / 双击 bin 下 exe 时,SQLite 实际写在 %LocalAppData%\YY.Admin\Data\(不是工程或 bin 目录)。 # 同步步骤会优先把该目录下的库打进 publish,与其它机上「和你本机一致」的安装模板对齐。 param( [switch]$NoLocalSync ) $ErrorActionPreference = 'Stop' $Root = Split-Path -Parent $PSScriptRoot $Csproj = Join-Path $Root 'YY.Admin\YY.Admin.csproj' $Tfm = 'net8.0-windows10.0.19041' $Rid = 'win-x64' $BinReleaseWin64 = Join-Path $Root "YY.Admin\bin\Release\$Tfm\$Rid" $BinDebugWin64 = Join-Path $Root "YY.Admin\bin\Debug\$Tfm\$Rid" $PublishRel = "YY.Admin\bin\Release\$Tfm\$Rid\publish" $PublishDir = Join-Path $Root $PublishRel $ProjAdmin = Join-Path $Root 'YY.Admin' # 与 SqlSugar 解析一致:相对路径 SQLite 落在当前 Windows 用户的 LocalAppData $DevUserDataDir = if ($env:LOCALAPPDATA) { Join-Path $env:LOCALAPPDATA 'YY.Admin\Data' } else { '' } $DevUserAppSettingsDir = if ($env:LOCALAPPDATA) { Join-Path $env:LOCALAPPDATA 'YY.Admin\AppSettings' } else { '' } $RedistDir = Join-Path $PSScriptRoot 'redist' $WebView2Exe = Join-Path $RedistDir 'MicrosoftEdgeWebview2Setup.exe' $WebView2Url = 'https://go.microsoft.com/fwlink/p/?LinkId=2124703' $SnapshotDir = Join-Path ([System.IO.Path]::GetTempPath()) ("yyadmin-publish-snap-{0}" -f [Guid]::NewGuid().ToString('n')) Write-Host '>>> dotnet publish (Release, win-x64)...' # publish 会清空输出目录:若你平时只在 publish 里测,先把其中的库暂存,供同步步骤一并参与“最新”比较 $hadPublishRoot = Test-Path -LiteralPath $PublishDir if ($hadPublishRoot -and -not $NoLocalSync) { $snapDb = @() foreach ($dbName in @('Admin.NET.db', 'Slave.db')) { $pp = Join-Path $PublishDir $dbName if (Test-Path -LiteralPath $pp) { $snapDb += , $pp } } $pubApps = Join-Path $PublishDir 'AppSettings' $hasPubApps = Test-Path -LiteralPath $pubApps if ($snapDb.Count -gt 0 -or $hasPubApps) { New-Item -ItemType Directory -Force -Path $SnapshotDir | Out-Null foreach ($p in $snapDb) { Copy-Item -LiteralPath $p -Destination (Join-Path $SnapshotDir (Split-Path $p -Leaf)) -Force } if ($hasPubApps) { Copy-Item -LiteralPath $pubApps -Destination (Join-Path $SnapshotDir 'AppSettings') -Recurse -Force } } } dotnet publish $Csproj -c Release ` -p:IncludeNativeLibrariesForSelfExtract=true ` -p:EnableCompressionInSingleFile=true ` --verbosity minimal if (-not (Test-Path $PublishDir)) { throw "Publish output not found: $PublishDir" } $cfgPublish = Join-Path $PublishDir 'Configuration\appsettings.json' if (-not (Test-Path $cfgPublish)) { throw "Missing Configuration\appsettings.json under publish (ExcludeFromSingleFile required). Path: $cfgPublish" } if (-not $NoLocalSync) { Write-Host '>>> Sync local runtime data into publish (databases + AppSettings, match local test)...' function Get-BestExistingPath { param([string[]]$Paths) $bestItem = $null foreach ($p in $Paths) { if (-not $p -or -not (Test-Path -LiteralPath $p)) { continue } $fi = Get-Item -LiteralPath $p if (-not $bestItem) { $bestItem = $fi; continue } if ($fi.LastWriteTime -gt $bestItem.LastWriteTime) { $bestItem = $fi; continue } # 修改时间相同(例如复制残留)时优先体积更大的一份,一般数据更全 if ($fi.LastWriteTime -eq $bestItem.LastWriteTime -and $fi.Length -gt $bestItem.Length) { $bestItem = $fi } } if ($bestItem) { return $bestItem.FullName } return $null } # 同名库:当前用户 LocalAppData(F5 真数据源)、项目根、publish.cmd、bin、publish、快照… foreach ($dbName in @('Admin.NET.db', 'Slave.db')) { $paths = @() if ($DevUserDataDir -and (Test-Path -LiteralPath $DevUserDataDir)) { $paths += (Join-Path $DevUserDataDir $dbName) } $paths += @( (Join-Path $ProjAdmin $dbName), (Join-Path $ProjAdmin "publish\$dbName"), (Join-Path $BinReleaseWin64 $dbName), (Join-Path $BinDebugWin64 $dbName), (Join-Path $BinReleaseWin64 "publish\$dbName"), (Join-Path $BinDebugWin64 "publish\$dbName"), (Join-Path $PublishDir $dbName) ) if (Test-Path -LiteralPath $SnapshotDir) { $sp = Join-Path $SnapshotDir $dbName if (Test-Path -LiteralPath $sp) { $paths += $sp } } $src = Get-BestExistingPath -Paths $paths if ($src) { $dst = Join-Path $PublishDir $dbName Copy-Item -LiteralPath $src -Destination $dst -Force $dstItem = Get-Item -LiteralPath $dst $t = $dstItem.LastWriteTime.ToString('yyyy-MM-dd HH:mm') $len = $dstItem.Length Write-Host " $dbName <= $src (publish 时间: $t, 大小: $len 字节)" } else { Write-Host " (skip) $dbName — 未在任意候选路径找到(含当前 publish 文件夹)" } } # AppSettings\:先 Release、再 Debug,再上一版 publish 下的 AppSettings(后者覆盖,适配只在 publish 目录测试) foreach ($bin in @($BinReleaseWin64, $BinDebugWin64)) { $appSettingsSrc = Join-Path $bin 'AppSettings' if (Test-Path -LiteralPath $appSettingsSrc) { $appSettingsDst = Join-Path $PublishDir 'AppSettings' Copy-Item -LiteralPath $appSettingsSrc -Destination $appSettingsDst -Recurse -Force Write-Host " AppSettings\ <= $appSettingsSrc" } } $snapApps = Join-Path $SnapshotDir 'AppSettings' if (Test-Path -LiteralPath $snapApps) { $appSettingsDst = Join-Path $PublishDir 'AppSettings' Copy-Item -LiteralPath $snapApps -Destination $appSettingsDst -Recurse -Force Write-Host " AppSettings\ <= $snapApps (previous publish)" } # 最后覆盖为当前登录 Windows 用户在 LocalAppData 下的设置(与 F5 调试一致) if ($DevUserAppSettingsDir -and (Test-Path -LiteralPath $DevUserAppSettingsDir)) { $appSettingsDst = Join-Path $PublishDir 'AppSettings' Copy-Item -LiteralPath $DevUserAppSettingsDir -Destination $appSettingsDst -Recurse -Force Write-Host " AppSettings\ <= $DevUserAppSettingsDir (LocalAppData)" } } else { Write-Host '>>> Skip local sync (-NoLocalSync).' } New-Item -ItemType Directory -Force -Path $RedistDir | Out-Null if (-not (Test-Path $WebView2Exe)) { Write-Host '>>> Downloading WebView2 Evergreen bootstrapper...' Invoke-WebRequest -Uri $WebView2Url -OutFile $WebView2Exe -UseBasicParsing } function Find-InnoCompiler { if ($env:ISCC -and (Test-Path -LiteralPath $env:ISCC)) { return $env:ISCC } if ($env:INNO_SETUP_DIR) { $p = Join-Path $env:INNO_SETUP_DIR.TrimEnd('\') 'ISCC.exe' if (Test-Path -LiteralPath $p) { return $p } } $cmd = Get-Command 'iscc.exe' -ErrorAction SilentlyContinue if ($cmd -and $cmd.Source -and (Test-Path -LiteralPath $cmd.Source)) { return $cmd.Source } $candidates = @( 'D:\Inno Setup 6\ISCC.exe' "${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe" "${env:ProgramFiles}\Inno Setup 6\ISCC.exe" "${env:LocalAppData}\Programs\Inno Setup 6\ISCC.exe" ) foreach ($c in $candidates) { if ($c -and (Test-Path -LiteralPath $c)) { return $c } } return $null } $iscc = Find-InnoCompiler if (-not $iscc) { throw @' ISCC.exe not found. 1) Install Inno Setup 6: https://jrsoftware.org/isdl.php 2) Or set env ISCC to full path of ISCC.exe, e.g.: set ISCC=C:\Program Files (x86)\Inno Setup 6\ISCC.exe 3) Or set INNO_SETUP_DIR to the Inno Setup 6 folder. Then run this script again. '@ } Write-Host ">>> Using ISCC: $iscc" $iss = Join-Path $PSScriptRoot 'YY.Admin.Setup.iss' Write-Host '>>> Compiling installer (working dir: installer)...' Push-Location $PSScriptRoot try { & $iscc "`"$iss`"" } finally { Pop-Location } $outDir = Join-Path $Root '_installer_output' Write-Host ">>> Done. Output folder: $outDir"