Build Charac server and client with OIDC, SSH sessions, and packages
Verify / verify (ubuntu-latest, linux-bionic-arm64) (push) Canceled after 0s
Verify / verify (ubuntu-latest, linux-x64) (push) Canceled after 0s
Verify / verify (windows-latest, win-x64) (push) Canceled after 0s
Verify / postgres (push) Canceled after 0s

This commit is contained in:
Nitload
2026-10-05 14:02:50 +08:00
parent 4bc3552167
commit 0ea679932e
185 changed files with 10653 additions and 772 deletions
+143
View File
@@ -0,0 +1,143 @@
param(
[Parameter(Mandatory = $true)]
[ValidateSet('ServerRpm', 'ClientRpm', 'ClientMsi', 'ClientApkDebug', 'ClientTermuxDeb')]
[string]$Target,
[string]$NfpmPath,
[string]$WixPath
)
$ErrorActionPreference = 'Stop'
$repository = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path
$version = ([xml](Get-Content -LiteralPath (Join-Path $repository 'Directory.Build.props') -Raw)).Project.PropertyGroup.Version
$packages = Join-Path $repository 'artifacts/packages'
$scratch = Join-Path $repository 'temp/packaging'
New-Item -ItemType Directory -Path $packages, $scratch -Force | Out-Null
function Assert-Payload([string]$path, [string]$executable) {
if (-not (Test-Path -LiteralPath (Join-Path $path $executable) -PathType Leaf)) {
throw "Publish the matching runtime first: $path"
}
$unexpected = Get-ChildItem -LiteralPath $path -Recurse -File | Where-Object {
$_.Name -eq 'workspace-access.config' -or $_.Extension -in @('.key', '.pem', '.pfx') -or
$_.Name -like '*Tests*'
}
if ($unexpected) { throw 'Publish payload contains a private configuration, key, or test assembly.' }
}
function Add-PackageFile([System.Collections.Generic.List[string]]$lines,
[string]$source, [string]$destination, [string]$mode = '0644') {
$normalized = $source.Replace('\', '/')
$lines.Add(' - src: ' + (ConvertTo-Json -InputObject $normalized -Compress))
$lines.Add(' dst: ' + (ConvertTo-Json -InputObject $destination -Compress))
$lines.Add(' file_info:')
$lines.Add(" mode: $mode")
}
if ($Target -eq 'ClientApkDebug') {
$source = Join-Path $repository 'temp/CharacAndroid/bin/Debug/net10.0-android/com.nitload.charac-Signed.apk'
if (-not (Test-Path -LiteralPath $source -PathType Leaf)) {
throw 'Build src/android/CharacAndroid.csproj in Debug first.'
}
$output = Join-Path $packages "charac-client_${version}_android-debug.apk"
[IO.File]::Copy($source, $output, $true)
Write-Output $output
exit 0
}
if ($Target -eq 'ClientMsi') {
$payload = Join-Path $repository 'artifacts/publish/win-x64/client'
Assert-Payload $payload 'charac.exe'
if (-not $WixPath) { $WixPath = Join-Path $repository 'temp/tools/wix.exe' }
if (-not (Test-Path -LiteralPath $WixPath -PathType Leaf)) { throw 'WiX CLI 6.0.2 is required; pass -WixPath.' }
$output = Join-Path $packages "charac-client_${version}_win-x64.msi"
& $WixPath build '-arch' 'x64' '-d' "PackageVersion=$version" '-d' "PayloadDir=$payload" '-d' "ConfigTemplatePath=$(Join-Path $repository 'client.config.example')" '-pdbtype' 'none' '-o' $output (Join-Path $PSScriptRoot 'windows/Client.wxs')
if ($LASTEXITCODE -ne 0) { throw "WiX failed with exit code $LASTEXITCODE." }
Write-Output $output
exit 0
}
if ($Target -eq 'ClientTermuxDeb') {
$payload = Join-Path $repository 'artifacts/publish/linux-bionic-arm64/client'
Assert-Payload $payload 'charac.dll'
if (-not $NfpmPath) { $NfpmPath = Join-Path $repository 'temp/tools/nfpm/nfpm.exe' }
if (-not (Test-Path -LiteralPath $NfpmPath -PathType Leaf)) { throw 'nFPM 2.47.0 is required; pass -NfpmPath.' }
$prefix = '/data/data/com.termux/files/usr'
$lines = [System.Collections.Generic.List[string]]::new()
$lines.Add('name: charac')
$lines.Add("version: $version")
$lines.Add('release: 1')
$lines.Add('arch: aarch64')
$lines.Add('platform: linux')
$lines.Add('maintainer: nitload')
$lines.Add('vendor: nitload')
$lines.Add('license: Proprietary')
$lines.Add('description: Charac CLI for Termux')
$lines.Add('depends:')
$lines.Add(' - dotnet-runtime-10.0')
$lines.Add('contents:')
foreach ($file in (Get-ChildItem -LiteralPath $payload -Recurse -File | Sort-Object FullName)) {
$relative = [IO.Path]::GetRelativePath($payload, $file.FullName).Replace('\', '/')
if ($file.Extension -eq '.pdb' -or $relative.StartsWith('WorkspaceAccessClient', [StringComparison]::OrdinalIgnoreCase)) { continue }
$mode = if ($relative -eq 'charac') { '0755' } else { '0644' }
Add-PackageFile $lines $file.FullName "$prefix/opt/charac/$relative" $mode
}
Add-PackageFile $lines (Join-Path $PSScriptRoot 'termux/charac') "$prefix/bin/charac" '0755'
$config = Join-Path $scratch 'charac-termux.yaml'
[IO.File]::WriteAllLines($config, [string[]]$lines)
$output = Join-Path $packages "charac_${version}-1_aarch64.deb"
& $NfpmPath package --config $config --packager deb --target $output
if ($LASTEXITCODE -ne 0) { throw "nFPM failed with exit code $LASTEXITCODE." }
Write-Output $output
exit 0
}
$kind = if ($Target -eq 'ServerRpm') { 'server' } else { 'client' }
$executable = if ($kind -eq 'server') { 'char_rac_server' } else { 'charac' }
$payload = Join-Path $repository "artifacts/publish/linux-x64/$kind"
Assert-Payload $payload $executable
if (-not $NfpmPath) { $NfpmPath = Join-Path $repository 'temp/tools/nfpm/nfpm.exe' }
if (-not (Test-Path -LiteralPath $NfpmPath -PathType Leaf)) { throw 'nFPM 2.47.0 is required; pass -NfpmPath.' }
$name = "charac-$kind"
$lines = [System.Collections.Generic.List[string]]::new()
$lines.Add("name: $name")
$lines.Add("version: $version")
$lines.Add('release: 1')
$lines.Add('arch: amd64')
$lines.Add('platform: linux')
$lines.Add('maintainer: nitload')
$lines.Add('vendor: nitload')
$lines.Add('license: Proprietary')
$lines.Add("description: Charac $kind")
if ($kind -eq 'server') {
$lines.Add('depends:')
$lines.Add(' - systemd')
$lines.Add('scripts:')
$lines.Add(' postinstall: ' + (ConvertTo-Json -InputObject (Join-Path $PSScriptRoot 'linux/server-postinstall.sh') -Compress))
$lines.Add(' postremove: ' + (ConvertTo-Json -InputObject (Join-Path $PSScriptRoot 'linux/server-postremove.sh') -Compress))
}
$lines.Add('contents:')
$files = Get-ChildItem -LiteralPath $payload -Recurse -File | Sort-Object FullName
foreach ($file in $files) {
$relative = [IO.Path]::GetRelativePath($payload, $file.FullName).Replace('\', '/')
if ($file.Extension -eq '.pdb' -or $relative.StartsWith('deploy/', [StringComparison]::OrdinalIgnoreCase)) { continue }
$mode = if ($relative -eq $executable) { '0755' } else { '0644' }
Add-PackageFile $lines $file.FullName "/opt/charac/$kind/$relative" $mode
}
if ($kind -eq 'server') {
Add-PackageFile $lines (Join-Path $PSScriptRoot 'linux/charac-server.service') '/usr/lib/systemd/system/charac-server.service'
Add-PackageFile $lines (Join-Path $PSScriptRoot 'linux/charac.sysusers') '/usr/lib/sysusers.d/charac.conf'
Add-PackageFile $lines (Join-Path $repository 'workspace-access.config.example') '/usr/share/doc/charac-server/workspace-access.config.example'
} else {
Add-PackageFile $lines (Join-Path $repository 'client.config.example') '/usr/share/doc/charac-client/client.config.example'
# The self-contained Client is already named charac; link it into PATH.
$lines.Add(' - src: /opt/charac/client/charac')
$lines.Add(' dst: /usr/bin/charac')
$lines.Add(' type: symlink')
}
$config = Join-Path $scratch "$name.yaml"
[IO.File]::WriteAllLines($config, [string[]]$lines)
$output = Join-Path $packages "${name}-${version}-1.x86_64.rpm"
& $NfpmPath package --config $config --packager rpm --target $output
if ($LASTEXITCODE -ne 0) { throw "nFPM failed with exit code $LASTEXITCODE." }
Write-Output $output