Skip to content

Commit e147b97

Browse files
committed
CI: read symlink targets from git object store
The windows-plain-qemu "Install templates" step assumed the working tree represented git symlinks as 17-byte plaintext stubs (the core.symlinks=false case). The GitHub Windows runner actually preserves them as real NTFS symlinks, so Get-Content on the stub path returned the target file's YAML content and the resolver threw: Stub templates\ubuntu-lts.yaml points at minimumLimaVersion: 2.0.0 base: - template:_images/ubuntu-24.04 - template:_default/mounts which does not exist at templates\minimumLimaVersion: 2.0.0 ... Read symlink targets directly from the git object store via `git cat-file blob <sha>` instead of probing the working tree. The resolution is now independent of whether core.symlinks is true (runner) or false (plain Windows checkout). Signed-off-by: Jan Dubois <jan.dubois@suse.com>
1 parent bae5d20 commit e147b97

1 file changed

Lines changed: 39 additions & 27 deletions

File tree

.github/workflows/test.yml

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -496,11 +496,14 @@ jobs:
496496
# so we copy templates/ to _output/share/lima/templates/ ourselves.
497497
#
498498
# Wrinkle: several files under templates/ are git symlinks
499-
# (mode 120000) pointing at sibling files. The Windows checkout writes
500-
# them as plaintext stubs containing just the target filename, because
501-
# core.symlinks defaults to false on Windows. Some symlinks chain
502-
# (opensuse.yaml -> opensuse-leap.yaml -> opensuse-leap-16.yaml), so
503-
# the resolver follows the chain until it lands on a real blob.
499+
# (mode 120000) pointing at sibling files, and some chain
500+
# (opensuse.yaml -> opensuse-leap.yaml -> opensuse-leap-16.yaml).
501+
# The working-tree representation varies: the GitHub Windows runner
502+
# preserves them as NTFS symlinks, while a plain Windows checkout
503+
# with core.symlinks=false writes 17-byte plaintext stubs. We read
504+
# symlink targets directly from git's object store so the resolution
505+
# is independent of either representation, then overwrite each
506+
# destination with the final resolved blob.
504507
run: |
505508
$ErrorActionPreference = 'Stop'
506509
$srcRoot = 'templates'
@@ -509,35 +512,44 @@ jobs:
509512
New-Item -ItemType Directory -Force -Path $dstRoot | Out-Null
510513
Copy-Item -Path "$srcRoot\*" -Destination $dstRoot -Recurse -Force
511514
512-
# Build a set of paths git tracks as symlinks, keyed by Windows-style path.
513-
$stubPaths = @{}
515+
# Build {posix-path -> target} for every entry tracked as a symlink,
516+
# reading the target from git's object store.
517+
$linkTargets = @{}
514518
foreach ($line in (git ls-tree -r HEAD $srcRoot)) {
515-
if ($line -match '^120000\s') {
516-
$relPath = ($line -split "`t", 2)[1]
517-
$stubPaths[$relPath -replace '/', '\'] = $true
518-
}
519+
if ($line -notmatch '^120000\s') { continue }
520+
$parts = $line -split "`t", 2
521+
$sha = ($parts[0] -split '\s+')[2]
522+
$posixPath = $parts[1]
523+
$target = (git cat-file blob $sha).Trim()
524+
if ($LASTEXITCODE -ne 0) { throw "git cat-file $sha failed: $LASTEXITCODE" }
525+
$linkTargets[$posixPath] = $target
519526
}
520527
if ($LASTEXITCODE -ne 0) { throw "git ls-tree failed: $LASTEXITCODE" }
521528
522-
function Resolve-StubChain($path) {
529+
# Walk each chain in path space, then overwrite the destination.
530+
foreach ($posixPath in $linkTargets.Keys) {
531+
$resolved = $posixPath
523532
$depth = 0
524-
while ($stubPaths[$path]) {
525-
if ($depth++ -gt 16) { throw "Symlink chain too deep starting from $path" }
526-
$target = (Get-Content -Raw $path).Trim()
527-
$next = Join-Path (Split-Path $path) $target
528-
if (-not (Test-Path $next)) {
529-
throw "Stub $path points at $target which does not exist at $next"
533+
while ($linkTargets.ContainsKey($resolved)) {
534+
if ($depth++ -gt 16) { throw "Symlink chain too deep starting from $posixPath" }
535+
$target = $linkTargets[$resolved]
536+
$slash = $resolved.LastIndexOf('/')
537+
$resolved = if ($slash -ge 0) { "$($resolved.Substring(0, $slash))/$target" } else { $target }
538+
$segs = New-Object System.Collections.ArrayList
539+
foreach ($s in ($resolved -split '/')) {
540+
if ($s -eq '' -or $s -eq '.') { continue }
541+
if ($s -eq '..') {
542+
if ($segs.Count -gt 0) { $segs.RemoveAt($segs.Count - 1) | Out-Null }
543+
continue
544+
}
545+
$segs.Add($s) | Out-Null
530546
}
531-
$path = $next
547+
$resolved = $segs -join '/'
532548
}
533-
return $path
534-
}
535-
536-
foreach ($stub in $stubPaths.Keys) {
537-
$real = Resolve-StubChain $stub
538-
$dstPath = Join-Path '_output\share\lima' $stub
539-
Write-Host "Resolving symlink: $stub -> $real"
540-
Copy-Item -Force -Path $real -Destination $dstPath
549+
$srcFile = $resolved -replace '/', '\'
550+
$dstFile = Join-Path '_output\share\lima' ($posixPath -replace '/', '\')
551+
Write-Host "Resolving symlink: $posixPath -> $resolved"
552+
Copy-Item -Force -Path $srcFile -Destination $dstFile
541553
}
542554
- name: Scrub PATH and verify only native Windows toolchain is reachable
543555
run: |

0 commit comments

Comments
 (0)