Files

139 lines
5.7 KiB
PowerShell

[CmdletBinding()]
param()
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Get-Sha256([string]$Path) {
return (Get-FileHash -Algorithm SHA256 -LiteralPath $Path).Hash.ToLowerInvariant()
}
function Get-UserPathValue {
if ($env:THT_USER_PATH_FILE) {
if (Test-Path -LiteralPath $env:THT_USER_PATH_FILE) {
return [System.IO.File]::ReadAllText($env:THT_USER_PATH_FILE)
}
return ''
}
return [Environment]::GetEnvironmentVariable('Path', 'User')
}
function Set-UserPathValue([string]$Value) {
if ($env:THT_USER_PATH_FILE) {
[System.IO.File]::WriteAllText($env:THT_USER_PATH_FILE, $Value)
return
}
[Environment]::SetEnvironmentVariable('Path', $Value, 'User')
}
function Add-InstallDirectoryToUserPath([string]$InstallDirectory) {
$currentPath = Get-UserPathValue
$entries = @($currentPath -split ';' | Where-Object { $_ -ne '' })
if ($entries | Where-Object { $_.TrimEnd('\\') -ieq $InstallDirectory.TrimEnd('\\') }) {
return $false
}
$newPath = (@($entries) + $InstallDirectory) -join ';'
Set-UserPathValue $newPath
return $true
}
function Replace-InstalledBinary([string]$StagedBinary, [string]$TargetBinary) {
$backupBinary = $null
$replacedExistingBinary = $false
try {
if (Test-Path -LiteralPath $TargetBinary -PathType Leaf) {
$backupBinary = Join-Path (Split-Path -Parent $TargetBinary) ('.tht-previous-' + [guid]::NewGuid() + '.exe')
[System.IO.File]::Replace($StagedBinary, $TargetBinary, $backupBinary, $true)
$replacedExistingBinary = $true
} else {
[System.IO.File]::Move($StagedBinary, $TargetBinary)
}
& $TargetBinary --help | Out-Null
if ($LASTEXITCODE -ne 0) { throw 'installed tht did not pass its help check' }
if ($backupBinary -and (Test-Path -LiteralPath $backupBinary -PathType Leaf)) {
Remove-Item -LiteralPath $backupBinary -Force -ErrorAction Stop
}
} catch {
$installFailure = $_
if ($replacedExistingBinary -and $backupBinary -and (Test-Path -LiteralPath $backupBinary -PathType Leaf)) {
try {
[System.IO.File]::Replace($backupBinary, $TargetBinary, $null, $true)
$backupBinary = $null
} catch {
throw "tht replacement failed; the previous executable remains at $backupBinary. Original failure: $installFailure. Restore failure: $_"
}
}
throw $installFailure
} finally {
Remove-Item -LiteralPath $StagedBinary -Force -ErrorAction SilentlyContinue
}
}
$repositoryRoot = Split-Path -Parent $PSScriptRoot
$buildOutput = $null
$sourceArtifactForInstall = $null
$installDirectory = if ($env:THT_INSTALL_DIRECTORY) {
$env:THT_INSTALL_DIRECTORY
} else {
Join-Path $env:LOCALAPPDATA 'ThothII\bin'
}
$installDirectory = [System.IO.Path]::GetFullPath($installDirectory)
if ($env:THT_BUILD_ARTIFACT) {
$sourceArtifact = $env:THT_BUILD_ARTIFACT
if (-not (Test-Path -LiteralPath $sourceArtifact -PathType Leaf)) {
throw 'THT_BUILD_ARTIFACT is not a regular file'
}
if (-not $env:THT_BUILD_ARTIFACT_SHA256 -or $env:THT_BUILD_ARTIFACT_SHA256 -notmatch '^[0-9A-Fa-f]{64}$') {
throw 'THT_BUILD_ARTIFACT_SHA256 must be a 64-character SHA-256 digest'
}
if ((Get-Sha256 $sourceArtifact) -ne $env:THT_BUILD_ARTIFACT_SHA256.ToLowerInvariant()) {
throw 'packaged tht artifact checksum does not match'
}
$sourceArtifactForInstall = $sourceArtifact
} else {
if ($env:PROCESSOR_ARCHITECTURE -notin @('AMD64', 'x86_64')) {
throw "unsupported Windows processor architecture: $env:PROCESSOR_ARCHITECTURE (supported: AMD64)"
}
$buildOutput = Join-Path ([System.IO.Path]::GetTempPath()) ("tht-build-" + [guid]::NewGuid())
New-Item -ItemType Directory -Path $buildOutput -Force | Out-Null
$previousOutput = $env:THT_THT_OUTPUT_DIRECTORY
$env:THT_THT_OUTPUT_DIRECTORY = $buildOutput
try {
& bash (Join-Path $repositoryRoot 'scripts/build-tht.sh') --all
if ($LASTEXITCODE -ne 0) { throw 'the repository-pinned Docker build failed' }
} finally {
$env:THT_THT_OUTPUT_DIRECTORY = $previousOutput
}
$sourceArtifactForInstall = Join-Path $buildOutput 'tht-windows-amd64.exe'
if (-not (Test-Path -LiteralPath $sourceArtifactForInstall -PathType Leaf)) {
throw 'the repository-pinned Docker build did not produce tht-windows-amd64.exe'
}
}
if ((Get-Item -LiteralPath $sourceArtifactForInstall).Length -eq 0) { throw 'native artifact is empty' }
New-Item -ItemType Directory -Path $installDirectory -Force | Out-Null
$stagedBinary = Join-Path $installDirectory ('.tht-' + [guid]::NewGuid() + '.exe')
try {
Copy-Item -LiteralPath $sourceArtifactForInstall -Destination $stagedBinary -Force
& $stagedBinary --help | Out-Null
if ($LASTEXITCODE -ne 0) { throw 'native artifact did not pass its help check' }
Replace-InstalledBinary $stagedBinary (Join-Path $installDirectory 'tht.exe')
} finally {
Remove-Item -LiteralPath $stagedBinary -Force -ErrorAction SilentlyContinue
if ($buildOutput) { Remove-Item -LiteralPath $buildOutput -Recurse -Force -ErrorAction SilentlyContinue }
}
$pathChanged = Add-InstallDirectoryToUserPath $installDirectory
if ($env:Path -notlike "*$installDirectory*") {
$env:Path = "$installDirectory;$env:Path"
}
& (Join-Path $installDirectory 'tht.exe') --help | Out-Null
if ($LASTEXITCODE -ne 0) { throw 'installed tht did not pass its help check' }
Write-Output "Installed tht at $(Join-Path $installDirectory 'tht.exe')"
if ($pathChanged) {
Write-Output 'Added ThothII to your user PATH. Open a new terminal before using tht there.'
}