Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 77 additions & 8 deletions scripts/windows/deploy-pwsh.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,82 @@ param(

$ErrorActionPreference = "Stop"

function Get-DirectoryEntry {
param([Parameter(Mandatory)][string]$Path)

$parent = [IO.Path]::GetDirectoryName($Path)
$leaf = [IO.Path]::GetFileName($Path)
if ([string]::IsNullOrWhiteSpace($parent) -or [string]::IsNullOrWhiteSpace($leaf)) {
return $null
}

$directory = [IO.DirectoryInfo]::new($parent)
if (-not $directory.Exists) {
return $null
}

return @($directory.EnumerateFileSystemInfos() | Where-Object Name -eq $leaf | Select-Object -First 1)
}

function Ensure-DestinationDirectory {
param([Parameter(Mandatory)][string]$Destination)

$parent = [IO.Path]::GetDirectoryName($Destination)
if ([string]::IsNullOrWhiteSpace($parent)) {
throw "Destination has no parent directory: $Destination"
}

try {
[IO.Directory]::CreateDirectory($parent) | Out-Null
}
catch {
throw "Unable to create destination directory '$parent': $($_.Exception.Message)"
}

if (-not [IO.Directory]::Exists($parent)) {
throw "Destination directory is unavailable after creation: $parent"
}
}

function Remove-LegacyDestinationLink {
param([Parameter(Mandatory)][string]$Destination)

$entry = Get-DirectoryEntry -Path $Destination
if ($null -eq $entry -or ($entry.Attributes -band [IO.FileAttributes]::ReparsePoint) -eq 0) {
return
}

Write-Host "Replacing legacy PowerShell reparse point: $Destination" -ForegroundColor Yellow

if (($entry.Attributes -band [IO.FileAttributes]::Directory) -ne 0) {
[IO.Directory]::Delete($Destination)
}
else {
[IO.File]::Delete($Destination)
}
}

function Copy-RuntimeFile {
param(
[Parameter(Mandatory)][string]$Source,
[Parameter(Mandatory)][string]$Destination
)

if (-not [IO.File]::Exists($Source)) {
throw "PowerShell source file not found: $Source"
}

Ensure-DestinationDirectory -Destination $Destination
Remove-LegacyDestinationLink -Destination $Destination

try {
[IO.File]::Copy($Source, $Destination, $true)
}
catch {
throw "Unable to deploy PowerShell runtime file '$Source' to '$Destination': $($_.Exception.Message)"
}
}

$repo = (Resolve-Path -LiteralPath $RepoRoot).Path
$sourceRoot = Join-Path $repo "home\.chezmoitemplates\pwsh"
$destinationRoot = Join-Path $HOME ".config\pwsh"
Expand All @@ -17,14 +93,7 @@ $files = @(
)

foreach ($file in $files) {
$source = Join-Path $sourceRoot $file.Source
if (-not (Test-Path -LiteralPath $source -PathType Leaf)) {
throw "PowerShell source file not found: $source"
}

New-Item -ItemType Directory -Path (Split-Path -Parent $file.Destination) -Force | Out-Null

Copy-Item -LiteralPath $source -Destination $file.Destination -Force
Copy-RuntimeFile -Source (Join-Path $sourceRoot $file.Source) -Destination $file.Destination
}

if ($env:DOTFILES_SIGNING_REQUIRED -eq "1" -or (Get-ExecutionPolicy) -eq "AllSigned") {
Expand Down
4 changes: 4 additions & 0 deletions tests/windows/assert-allsigned.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ $runtimeFiles = @(
)
foreach ($path in $runtimeFiles) {
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { Fail "runtime PowerShell file is missing: $path" }
$item = Get-Item -LiteralPath $path -Force
if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
Fail "runtime PowerShell file remained a reparse point after deployment: $path"
}
$signatureFiles.Add($path)
}

Expand Down
14 changes: 14 additions & 0 deletions tests/windows/assert-state.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@ foreach ($path in $requiredFiles) {
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { Fail "expected deployed file is missing: $path" }
}

$runtimeFiles = @(
(Join-Path $HOME ".config\pwsh\env.ps1"),
(Join-Path $HOME ".config\pwsh\lib\helpers.ps1"),
(Join-Path $HOME ".config\pwsh\lib\aliases.ps1"),
$PROFILE.CurrentUserAllHosts
)
foreach ($path in $runtimeFiles) {
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { Fail "PowerShell runtime file is missing: $path" }
$item = Get-Item -LiteralPath $path -Force
if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
Fail "PowerShell runtime file remained a reparse point after deployment: $path"
}
}

if ($ExpectedCommit) {
$sourceCommit = ((git -C $sourcePath rev-parse HEAD) -join "").Trim()
if ($LASTEXITCODE -ne 0 -or $sourceCommit -ne $ExpectedCommit) { Fail "source commit $sourceCommit is not expected commit $ExpectedCommit" }
Expand Down
16 changes: 16 additions & 0 deletions tests/windows/prepare-ci.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,19 @@ function New-BrokenDirectorySymlinkFixture {
New-BrokenFileSymlinkFixture -Path (Join-Path $HOME ".fdignore") -Target (Join-Path $env:RUNNER_TEMP "legacy-fdignore")
New-BrokenDirectorySymlinkFixture -Path (Join-Path $HOME ".config\starship") -Target (Join-Path $env:RUNNER_TEMP "legacy-starship")
New-BrokenFileSymlinkFixture -Path (Join-Path $HOME ".dotfiles-ci-unrelated-broken-link") -Target (Join-Path $env:RUNNER_TEMP "unrelated-link")


function New-BrokenRuntimeSymlinkFixture {
param(
[Parameter(Mandatory)][string]$Path,
[Parameter(Mandatory)][string]$Name
)

$target = Join-Path $env:RUNNER_TEMP "legacy-pwsh-runtime\$Name"
New-BrokenFileSymlinkFixture -Path $Path -Target $target
}

New-BrokenRuntimeSymlinkFixture -Path (Join-Path $HOME ".config\pwsh\env.ps1") -Name "env.ps1"
New-BrokenRuntimeSymlinkFixture -Path (Join-Path $HOME ".config\pwsh\lib\aliases.ps1") -Name "aliases.ps1"
New-BrokenRuntimeSymlinkFixture -Path (Join-Path $HOME ".config\pwsh\lib\helpers.ps1") -Name "helpers.ps1"
New-BrokenRuntimeSymlinkFixture -Path $PROFILE.CurrentUserAllHosts -Name "profile.ps1"