Files
cmbot/scripts/install_local.ps1
T

167 lines
5.1 KiB
PowerShell
Raw Normal View History

2026-06-18 10:04:29 +08:00
<#
.SYNOPSIS
Install a built CMBot release into the local launcher layout.
.DESCRIPTION
Creates or updates this structure:
%LOCALAPPDATA%\CMBot\
update.ps1
app\
app.old\
data\
config\
logs\
output\
staging\
The script copies a built release directory (release\CMBot-x.y.z by default)
into app\, copies scripts\update.ps1 to the install root, and migrates
config files into data\config without overwriting existing user config.
.PARAMETER ReleaseDir
Built release directory to install. Defaults to release\CMBot-APP_VERSION.
.PARAMETER InstallRoot
Local install root. Defaults to %LOCALAPPDATA%\CMBot.
.PARAMETER LegacyDataDir
Optional old flat install/data root. When provided, config files are copied
from LegacyDataDir\config before falling back to app.old\config or release
defaults.
.PARAMETER Force
Allows replacing an existing app.old directory.
#>
[CmdletBinding()]
param(
[string]$ReleaseDir = "",
[string]$InstallRoot = (Join-Path $env:LOCALAPPDATA "CMBot"),
[string]$LegacyDataDir = "",
[switch]$Force
)
$ErrorActionPreference = "Stop"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$RootDir = Split-Path -Parent $ScriptDir
$VersionFile = Join-Path $RootDir "src\version.py"
$ReleaseRoot = Join-Path $RootDir "release"
$LauncherScript = Join-Path $ScriptDir "update.ps1"
$AppExeName = "CMBot"
$AppExe = "$AppExeName.exe"
function Read-VersionValue {
param(
[string]$Path,
[string]$Name
)
$pattern = "^\s*$Name\s*=\s*`"([^`"]+)`""
foreach ($line in Get-Content -LiteralPath $Path -Encoding UTF8) {
if ($line -match $pattern) {
return $Matches[1]
}
}
throw "Cannot find $Name in $Path"
}
function Resolve-ExistingPath {
param(
[string]$Path,
[string]$Name
)
if (-not (Test-Path -LiteralPath $Path)) {
throw "$Name not found: $Path"
}
return (Resolve-Path -LiteralPath $Path).Path
}
function Assert-Release {
param([string]$Path)
$exe = Join-Path $Path $AppExe
$version = Join-Path $Path "version.txt"
if (-not (Test-Path -LiteralPath $exe)) {
throw "Release missing executable: $exe"
}
if (-not (Test-Path -LiteralPath $version)) {
throw "Release missing version.txt: $version"
}
}
function Copy-ConfigIfMissing {
param(
[string]$SourceConfigDir,
[string]$TargetConfigDir,
[string]$FileName
)
if (-not $SourceConfigDir) {
return
}
$source = Join-Path $SourceConfigDir $FileName
$target = Join-Path $TargetConfigDir $FileName
if ((Test-Path -LiteralPath $source) -and -not (Test-Path -LiteralPath $target)) {
Copy-Item -LiteralPath $source -Destination $target
Write-Host "Migrated config: $FileName"
}
}
if (-not $ReleaseDir) {
$appVersion = Read-VersionValue -Path $VersionFile -Name "APP_VERSION"
$ReleaseDir = Join-Path $ReleaseRoot "$AppExeName-$appVersion"
}
$ReleaseDir = Resolve-ExistingPath -Path $ReleaseDir -Name "Release directory"
$LauncherScript = Resolve-ExistingPath -Path $LauncherScript -Name "Launcher script"
Assert-Release -Path $ReleaseDir
$InstallRoot = [System.IO.Path]::GetFullPath($InstallRoot)
$AppDir = Join-Path $InstallRoot "app"
$OldAppDir = Join-Path $InstallRoot "app.old"
$DataDir = Join-Path $InstallRoot "data"
$ConfigDir = Join-Path $DataDir "config"
$LogsDir = Join-Path $DataDir "logs"
$OutputDir = Join-Path $DataDir "output"
$StagingDir = Join-Path $InstallRoot "staging"
New-Item -ItemType Directory -Force -Path $InstallRoot | Out-Null
New-Item -ItemType Directory -Force -Path $ConfigDir | Out-Null
New-Item -ItemType Directory -Force -Path $LogsDir | Out-Null
New-Item -ItemType Directory -Force -Path $OutputDir | Out-Null
New-Item -ItemType Directory -Force -Path $StagingDir | Out-Null
if (Test-Path -LiteralPath $AppDir) {
if (Test-Path -LiteralPath $OldAppDir) {
if (-not $Force) {
throw "app.old already exists: $OldAppDir. Re-run with -Force to replace it."
}
Remove-Item -LiteralPath $OldAppDir -Recurse -Force
}
Move-Item -LiteralPath $AppDir -Destination $OldAppDir
}
Copy-Item -LiteralPath $ReleaseDir -Destination $AppDir -Recurse
Copy-Item -LiteralPath $LauncherScript -Destination (Join-Path $InstallRoot "update.ps1") -Force
$configSources = @()
if ($LegacyDataDir) {
$configSources += Join-Path ([System.IO.Path]::GetFullPath($LegacyDataDir)) "config"
}
if (Test-Path -LiteralPath $OldAppDir) {
$configSources += Join-Path $OldAppDir "config"
}
$configSources += Join-Path $AppDir "config"
foreach ($sourceConfig in $configSources) {
Copy-ConfigIfMissing -SourceConfigDir $sourceConfig -TargetConfigDir $ConfigDir -FileName "app_config.json"
Copy-ConfigIfMissing -SourceConfigDir $sourceConfig -TargetConfigDir $ConfigDir -FileName "templates.json"
}
Write-Host "Installed CMBot launcher layout:"
Write-Host " Root: $InstallRoot"
Write-Host " App: $AppDir"
Write-Host " Data: $DataDir"
Write-Host ""
Write-Host "Start with:"
Write-Host " powershell -ExecutionPolicy Bypass -File `"$InstallRoot\update.ps1`""