@ -1453,9 +1453,11 @@ set_active() {
echo " active runtime for $archtail set to: $1 (recorded in $active_file) "
}
#installed runtime candidates - exclude directories, build copies and
#non-runtime files (ps1-payload parity: files only, same extension excludes)
#non-runtime files (ps1-payload parity: files only, same extension excludes).
#LC_ALL=C: glob expansion order is collation-dependent - C-locale byte order
#matches the ps1 payload's ordinal sorting, so listings agree everywhere.
list_candidates() {
local f
local f LC_ALL=C
if [[ - d " $ a r c h d i r " ] ] ; t h e n
for f in " $archdir " /*; do
[[ -f " $f " ]] || continue
@ -1532,7 +1534,11 @@ show_help() {
echo " (variant, tcl patchlevel, revision, piperepl policy, source "
echo " artifact of a materialized copy; a !TARGET-MISMATCH flag marks "
echo " a runtime filed under the wrong platform folder). -remote "
echo " compares local runtimes against the server's sha1sums. "
echo " compares local runtimes against the server's sha1sums, marks "
echo " the locally ACTIVE runtime (*) and annotates the platform's "
echo " recommended runtime ((server default), per the server's "
echo " defaults.txt when available) - so active-vs-default is "
echo " visible at a glance. "
echo " use <name> ?-platform <p>? "
echo " Select the runtime that 'run' launches (records active.toml in "
echo " the platform folder). An immutable -r<N> ARTIFACT name is "
@ -1721,12 +1727,32 @@ case "$action" in
echo " No sha1 tool found (tried sha1sum, shasum, sha1, openssl) - cannot compare local runtimes. "
exit 1
fi
#server-default + local-active surfacing (G-103): the server's curated
#defaults.txt names the recommended runtime per platform - best-effort
#fetch (cached/absent both fine for a listing), then mark the matching
#row and the locally active one so " is my active the recommended
#default?" is answerable at a glance.
activename=$(get_active)
platform_default=" "
defaultslocal=" ${scriptdir}/runtime/defaults.txt "
curl -fsL --silent --output " $defaultslocal " " ${url_kitbase}/defaults.txt " 2 > /dev/null || :
if [[ - f " $ d e f a u l t s l o c a l " ] ] ; t h e n
platform_default=$(awk -v p=" $archtail " '$1==p {print $2; exit}' " $defaultslocal " )
fi
echo " ----------------------------------------------------------------------- "
echo " Runtimes for $archtail "
echo " Local $archdir "
echo " Remote ${url_kitbase}/${archtail} "
if [[ - n " $ p l a t f o r m _ d e f a u l t " ] ] ; t h e n
echo " server default for $archtail: $platform_default "
fi
if [[ - n " $ a c t i v e n a m e " ] ] ; t h e n
matchnote=" "
[[ -n " $platform_default " && " $activename " == " $platform_default " ]] && matchnote=" (= server default) "
echo " active (local): $activename$matchnote "
fi
echo " ----------------------------------------------------------------------- "
echo " Local Remote "
echo " Local Remote"
echo " ----------------------------------------------------------------------- "
for f in $(list_candidates); do
local_sha1=$(lcase " $(sha1_of " $archdir/$f" ) " )
@ -1738,16 +1764,25 @@ case "$action" in
else
rhs=" UPDATE AVAILABLE "
fi
printf '%-35s % s\n' " $f " " $rhs "
mark=" "
[[ " $f " == " $activename " ]] && mark=" * "
annot=" "
[[ -n " $platform_default " && " $f " == " $platform_default " ]] && annot=" (server default) "
printf '%s% -35s %s% s\n' " $mark " " $f " " $rhs " " $annot "
done
#remote-only entries
while IFS= read -r line; do
rname=$(printf '%s' " $line " | sed -n 's/^[ 0-9a-fA-F]\{40\} \*\(.*\)$/\1/p')
#remote-only entries, sorted (ps1-payload parity - its dict enumeration
#is explicitly sorted). tr strips CRLF \r: msys grep strips it in text
#mode but bash read does not - without this a locally-present runtime
#also shows as a remote-only row (\r-suffixed name fails the -f test)
tr -d '\r' < " $sha1local " | sed -n 's/^[ 0-9a-fA-F]\{40\} \*\(.*\)$/\1/p' | LC_ALL=C sort | while IFS= read -r rname; do
if [[ - n " $ r n a m e " & & ! - f " $ a r c h d i r / $ r n a m e " ] ] ; t h e n
printf '%-35s % s\n' " - " " $rname "
annot=" "
[[ -n " $platform_default " && " $rname " == " $platform_default " ]] && annot=" (server default) "
printf ' %-35s % s%s\n' " - " " $rname " " $annot "
fi
done < " $sha1local "
done
echo " ----------------------------------------------------------------------- "
echo " * = active (local selection) "
else
if [[ - d " $ a r c h d i r " ] ] ; t h e n
candidates=$(list_candidates)
@ -1886,7 +1921,7 @@ case "$action" in
rtroot=" ${scriptdir}/runtime "
localdirs=" "
if [[ - d " $ r t r o o t " ] ] ; t h e n
localdirs=$(ls -1 " $rtroot " 2 > /dev/null | while read -r d; do [[ -d " $rtroot/$d " ]] && echo " $d " ; done)
localdirs=$(LC_ALL=C ls -1 " $rtroot " 2 > /dev/null | while read -r d; do [[ -d " $rtroot/$d " ]] && echo " $d " ; done)
fi
if [[ " $ { 1 : - } " == " -remote " ]]; then
manifesturl=" ${url_kitbase}/platforms.txt "
@ -2324,13 +2359,27 @@ function Set-PunkActiveRuntime {
[System.IO.File]::WriteAllText($activefile, " active = ` " $name`" `n " , [System.Text.UTF8Encoding]::new($false))
Write-Host " active runtime set to: $name (recorded in $activefile) "
}
#installed runtime candidates - exclude build copies and non-runtime files
#installed runtime candidates - exclude build copies and non-runtime files.
#ORDINAL name order: culture-sensitive Sort-Object collates differently between
#windows powershell (NLS) and pwsh (ICU) - both launch paths exist (the .ps1
#twin runs under the invoking shell) - and ordinal matches the bash payload's
#LC_ALL=C ordering, so listings agree byte-for-byte everywhere.
function Get-PunkRuntimeCandidates {
param([string] $archfolder)
if (-not ( T e s t - P a t h - P a t h $ a r c h f o l d e r - P a t h T y p e C o n t a i n e r ) ) {
return @()
}
return @(get-childItem -Path $archfolder -File | Where-object Name -Notlike '*_BUILDCOPY*' | Where-object {-not ($(" .txt " ," .toml " ," .tm " ," .tmp " ," .log " ) -contains $_.Extension) } | Sort-Object Name)
$files = @(get-childItem -Path $archfolder -File | Where-object Name -Notlike '*_BUILDCOPY*' | Where-object {-not ($(" .txt " ," .toml " ," .tm " ," .tmp " ," .log " ) -contains $_.Extension) })
if ($files.Count - l e 1 ) {
return $files
}
$byname = @{}
foreach ($f in $files) { $byname[$f.Name] = $f }
$names = @($byname.Keys)
[array]::Sort($names, [System.StringComparer]::Ordinal)
$out = @()
foreach ($n in $names) { $out += $byname[$n] }
return $out
}
#operator help (the 'help' action; the no-args case shows the Usage block only).
#Keep in sync with the bash payload's show_help/show_usage.
@ -2363,7 +2412,11 @@ function Show-PunkRuntimeHelp {
write-host " (variant, tcl patchlevel, revision, piperepl policy, source "
write-host " artifact of a materialized copy; a !TARGET-MISMATCH flag marks "
write-host " a runtime filed under the wrong platform folder). -remote "
write-host " compares local runtimes against the server's sha1sums. "
write-host " compares local runtimes against the server's sha1sums, marks "
write-host " the locally ACTIVE runtime (*) and annotates the platform's "
write-host " recommended runtime ((server default), per the server's "
write-host " defaults.txt when available) - so active-vs-default is "
write-host " visible at a glance. "
write-host " use <name> ?-platform <p>? "
write-host " Select the runtime that 'run' launches (records active.toml in "
write-host " the platform folder). An immutable -r<N> ARTIFACT name is "
@ -2980,19 +3033,57 @@ function psmain {
}
}
#server-default + local-active surfacing (G-103): the server's
#curated defaults.txt names the recommended runtime per platform -
#best-effort fetch (cached/absent both fine for a listing), then
#mark the matching row and the locally active one so " is my
#active the recommended default?" is answerable at a glance.
$activename = Get-PunkActiveRuntime $archfolder
$platform_default = " "
$defaultslocal = Join-Path -Path $rtfolder -ChildPath " defaults.txt "
try {
Invoke-WebRequest -Uri " $artifacturl/defaults.txt " -OutFile $defaultslocal -ErrorAction Stop
} catch { }
if (Test-Path - P a t h $ d e f a u l t s l o c a l - P a t h T y p e L e a f ) {
foreach ($line in (Get-Content -Path $defaultslocal)) {
$line = $line.Trim()
if ($line - e q " " - o r $ l i n e . S t a r t s W i t h ( " # " ) ) { c o n t i n u e }
$parts = -split $line
if ($parts.Count - g e 2 - a n d $ p a r t s [ 0 ] - e q $ a r c h ) {
$platform_default = $parts[1]
break
}
}
}
Write-host " ----------------------------------------------------------------------- "
Write-host " Runtimes for $arch "
Write-host " Local $archfolder "
Write-host " Remote $archurl "
if ($platform_default - n e " " ) {
Write-host " server default for ${arch}: $platform_default "
}
if ($activename - n e " " ) {
$matchnote = " "
if ($platform_default - n e " " - a n d $ a c t i v e n a m e - e q $ p l a t f o r m _ d e f a u l t ) {
$matchnote = " (= server default) "
}
Write-host " active (local): $activename$matchnote "
}
Write-host " ----------------------------------------------------------------------- "
Write-host " Local Remote "
Write-host " Local Remote"
Write-host " ----------------------------------------------------------------------- "
# 12345678910234567892023456789302345
# 12345678910234567892023456789302345
$G = " `e[32m " #Green
$Y = " `e[33m " #Yellow
$R = " `e[31m " #Red
$RST = " `e[m "
foreach ($key in $localdict.Keys) {
#explicit ORDINAL sort: Hashtable key enumeration order is
#undefined (and differs between the powershell editions), and
#culture-sensitive Sort-Object collates differently too (NLS vs
#ICU) - ordinal agrees across editions and with bash LC_ALL=C
$localkeys = @($localdict.Keys)
[array]::Sort($localkeys, [System.StringComparer]::Ordinal)
foreach ($key in $localkeys) {
$local_sha1 = $($localdict[$key])
if ($remotedict.ContainsKey($key)) {
if ($local_sha1 - e q $ r e m o t e d i c t [ $ k e y ] ) {
@ -3009,18 +3100,27 @@ function psmain {
#ansi problems from cmd.exe not in windows terminal - review
$C = " "
$RST = " "
$mark = " "
if ($key - e q $ a c t i v e n a m e ) { $ m a r k = " * " }
$annot = " "
if ($platform_default - n e " " - a n d $ k e y - e q $ p l a t f o r m _ d e f a u l t ) { $ a n n o t = " ( s e r v e r d e f a u l t ) " }
$lhs = " $key " .PadRight(35, ' ')
write-host -nonewline " ${C}${lhs}${RST} "
write-host $rhs
write-host -nonewline " ${mark}${ C}${lhs}${RST} "
write-host " $rhs$annot "
}
$lhs_missing = " - " .PadRight(35, ' ')
foreach ($key in $remotedict.Keys) {
$remotekeys = @($remotedict.Keys)
[array]::Sort($remotekeys, [System.StringComparer]::Ordinal)
foreach ($key in $remotekeys) {
if (-not ( $ l o c a l d i c t . C o n t a i n s K e y ( $ k e y ) ) ) {
write-host -nonewline $lhs_missing
write-host $key
$annot = " "
if ($platform_default - n e " " - a n d $ k e y - e q $ p l a t f o r m _ d e f a u l t ) { $ a n n o t = " ( s e r v e r d e f a u l t ) " }
write-host -nonewline " $lhs_missing "
write-host " $key$annot "
}
}
Write-host " ----------------------------------------------------------------------- "
Write-host " * = active (local selection) "
} else {
if (test-path - P a t h $ a r c h f o l d e r - T y p e C o n t a i n e r ) {
@ -3059,7 +3159,8 @@ function psmain {
#punkbin layout contract; third-party mirrors carry the same file)
$localdirs = @()
if (Test-Path - P a t h $ r t f o l d e r - P a t h T y p e C o n t a i n e r ) {
$localdirs = @(Get-ChildItem -Path $rtfolder -Directory | Select-Object -ExpandProperty Name | Sort-Object)
$localdirs = @(Get-ChildItem -Path $rtfolder -Directory | Select-Object -ExpandProperty Name)
[array]::Sort($localdirs, [System.StringComparer]::Ordinal)
}
if ( $ P S B o u n d P a r a m e t e r s . C o n t a i n s K e y ( ' r e m o t e ' ) ) {
$manifesturl = " $artifacturl/platforms.txt "