Browse Source

punk-runtime: deterministic ordinal listing order; AGENTS .ps1-twin knowledge corrected

The user-observed ordering discrepancy decomposed into two edition
divergences, both now handled:
- launch paths run DIFFERENT powershells: the .ps1 twin executes under
  the invoking shell (pwsh 7) while the .cmd routes via the wrap-pinned
  'cmd.exe /c powershell' (Windows PowerShell 5);
- between those editions BOTH Hashtable key enumeration order AND
  culture-sensitive Sort-Object collation differ (NLS vs ICU treat
  hyphens differently). Fix: ordinal comparison for every name ordering
  (candidates, platforms dirs, list -remote local+remote-only rows) in
  ps1, LC_ALL=C glob/ls/sort in bash - verified byte-identical
  list -remote output across cmd->powershell5, pwsh7-on-twin, and bash.

bin/AGENTS.md .ps1-twin paragraph corrected (was stale): the twin is
SELF-MATERIALIZED by the polyglot's batch layer - created when missing,
fc-compared and re-copied when content differs - so it self-heals after
a re-wrap on the next .cmd launch; no manual copy step (verified:
deleted twin regenerated byte-identical). Documented caveats: a
direct-.ps1-only user can ride a stale twin until a .cmd launch heals
it, and payload code must avoid edition-specific behaviour. Rewrapped;
roundtrip pin PASS; layout copy refreshed (twin deliberately NOT
hand-copied - the mechanism owns it now). Project 0.18.7.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 week ago
parent
commit
a423d840e3
  1. 4
      CHANGELOG.md
  2. 18
      bin/AGENTS.md
  3. 55
      bin/punk-runtime.cmd
  4. 2
      punkproject.toml
  5. 55
      src/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd
  6. 22
      src/scriptapps/bin/punk-runtime.bash
  7. 33
      src/scriptapps/bin/punk-runtime.ps1

4
CHANGELOG.md

@ -5,6 +5,10 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to
Entries are newest-first; one bullet per notable change. See the root `AGENTS.md`
"Project Versioning" section for the bump policy.
## [0.18.7] - 2026-07-22
- `bin/punk-runtime.cmd`: deterministic listing order everywhere. Investigation of an ordering discrepancy between launch paths found two edition divergences: the `.ps1` twin runs under the INVOKING powershell (pwsh 7) while the `.cmd` routes via wrap-pinned Windows PowerShell 5, and both Hashtable enumeration order AND culture-sensitive `Sort-Object` collation (NLS vs ICU) differ between those editions. All name orderings now use ordinal comparison (ps1) / `LC_ALL=C` (bash), which agree byte-for-byte across pwsh, powershell and bash. Also corrected `bin/AGENTS.md`: the `.ps1` twin is SELF-MATERIALIZED by the polyglot's batch layer (created when missing, `fc`-compared and re-copied when stale) - the previous "refresh both on re-wrap" manual-copy guidance was stale; twin verified regenerating byte-identical after deletion.
## [0.18.6] - 2026-07-22
- `bin/punk-runtime.cmd` `list -remote`: surfaces the selection state - summary lines show the platform's server default (per `defaults.txt`, best-effort fetch) and the locally active runtime (annotated `(= server default)` on match); the active runtime's row carries the local listing's `*` marker and the default's row (local or remote-only) is annotated `(server default)`. Also fixed a latent bash-payload bug the work exposed: CRLF server sha1sums made locally-present runtimes additionally appear as remote-only rows (`\r`-suffixed name failed the existence test; msys grep strips `\r`, bash `read` does not) - punkbin's maintenance script now writes LF sha1sums too.

18
bin/AGENTS.md

@ -55,9 +55,21 @@ external tool under its own name (`dtplite`, `sdx`, `kettle`), and `getpunk`
(already punkshell-specific; intended future single-download cross-platform entry
point). Policy decided by the user 2026-07-20 (G-096); the remaining pre-policy names
were swept under G-097 (2026-07-21): `punk-bits`, `punk-runtime`, `punk-tclargs` and the
punk- prefixed selfsign experiment scripts. Where launchability convenience warrants it a `.ps1` twin of the generated
`.cmd` ships alongside (windows users may start from cmd.exe or powershell); the twin
is a byte-copy under the other extension - refresh both on re-wrap.
punk- prefixed selfsign experiment scripts.
`.ps1` twin (corrected 2026-07-22 - the twin is SELF-MATERIALIZED, not manually
refreshed): the generated `.cmd`'s batch layer creates `<name>.ps1` beside itself
when missing AND `fc`-compares/re-copies it whenever content differs (powershell
needs a `.ps1` extension for `-File`), so the twin regenerates on any `.cmd` launch
and self-heals after a re-wrap - no manual copy step. The twin is a byte-copy of the
polyglot and is VCS-ignored (a runtime artifact, unlike the committed `.cmd`).
Caveats: a user who only ever launches the `.ps1` directly can ride a stale twin
until the next `.cmd`-path launch heals it; and the two launch paths run DIFFERENT
powershells - `./bin/<name>` in a powershell session resolves the `.ps1` and runs it
under the INVOKING shell (pwsh 7 or powershell 5), while the `.cmd` route is pinned
by the wrap toml (`cmd.exe /c powershell` = Windows PowerShell) - payload code must
be edition-portable and avoid implementation-defined behaviour (e.g. Hashtable
enumeration order differs between the editions; sort explicitly).
### Launch package modes (built punk shells)

55
bin/punk-runtime.cmd

@ -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 "$archdir" ]]; then
for f in "$archdir"/*; do
[[ -f "$f" ]] || continue
@ -1768,19 +1770,17 @@ case "$action" in
[[ -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
#server sha1sums may be CRLF: msys grep strips \r in text mode but
#bash read does not - without this a locally-present runtime also
#shows as a remote-only row (its \r-suffixed name fails the -f test)
line="${line%$'\r'}"
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 "$rname" && ! -f "$archdir/$rname" ]]; then
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
@ -1921,7 +1921,7 @@ case "$action" in
rtroot="${scriptdir}/runtime"
localdirs=""
if [[ -d "$rtroot" ]]; then
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"
@ -2359,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 (Test-Path -Path $archfolder -PathType Container)) {
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 -le 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.
@ -3063,7 +3077,13 @@ function psmain {
$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 -eq $remotedict[$key]) {
@ -3089,7 +3109,9 @@ function psmain {
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 ($localdict.ContainsKey($key))) {
$annot = ""
if ($platform_default -ne "" -and $key -eq $platform_default) { $annot = " (server default)" }
@ -3137,7 +3159,8 @@ function psmain {
#punkbin layout contract; third-party mirrors carry the same file)
$localdirs = @()
if (Test-Path -Path $rtfolder -PathType Container) {
$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 ( $PSBoundParameters.ContainsKey('remote') ) {
$manifesturl = "$artifacturl/platforms.txt"

2
punkproject.toml

@ -1,4 +1,4 @@
[project]
name = "punkshell"
version = "0.18.6"
version = "0.18.7"
license = "BSD-2-Clause"

55
src/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd vendored

@ -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 "$archdir" ]]; then
for f in "$archdir"/*; do
[[ -f "$f" ]] || continue
@ -1768,19 +1770,17 @@ case "$action" in
[[ -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
#server sha1sums may be CRLF: msys grep strips \r in text mode but
#bash read does not - without this a locally-present runtime also
#shows as a remote-only row (its \r-suffixed name fails the -f test)
line="${line%$'\r'}"
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 "$rname" && ! -f "$archdir/$rname" ]]; then
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
@ -1921,7 +1921,7 @@ case "$action" in
rtroot="${scriptdir}/runtime"
localdirs=""
if [[ -d "$rtroot" ]]; then
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"
@ -2359,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 (Test-Path -Path $archfolder -PathType Container)) {
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 -le 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.
@ -3063,7 +3077,13 @@ function psmain {
$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 -eq $remotedict[$key]) {
@ -3089,7 +3109,9 @@ function psmain {
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 ($localdict.ContainsKey($key))) {
$annot = ""
if ($platform_default -ne "" -and $key -eq $platform_default) { $annot = " (server default)" }
@ -3137,7 +3159,8 @@ function psmain {
#punkbin layout contract; third-party mirrors carry the same file)
$localdirs = @()
if (Test-Path -Path $rtfolder -PathType Container) {
$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 ( $PSBoundParameters.ContainsKey('remote') ) {
$manifesturl = "$artifacturl/platforms.txt"

22
src/scriptapps/bin/punk-runtime.bash

@ -173,9 +173,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 "$archdir" ]]; then
for f in "$archdir"/*; do
[[ -f "$f" ]] || continue
@ -488,19 +490,17 @@ case "$action" in
[[ -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
#server sha1sums may be CRLF: msys grep strips \r in text mode but
#bash read does not - without this a locally-present runtime also
#shows as a remote-only row (its \r-suffixed name fails the -f test)
line="${line%$'\r'}"
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 "$rname" && ! -f "$archdir/$rname" ]]; then
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
@ -641,7 +641,7 @@ case "$action" in
rtroot="${scriptdir}/runtime"
localdirs=""
if [[ -d "$rtroot" ]]; then
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"

33
src/scriptapps/bin/punk-runtime.ps1

@ -62,13 +62,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 (Test-Path -Path $archfolder -PathType Container)) {
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 -le 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.
@ -766,7 +780,13 @@ function psmain {
$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 -eq $remotedict[$key]) {
@ -792,7 +812,9 @@ function psmain {
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 ($localdict.ContainsKey($key))) {
$annot = ""
if ($platform_default -ne "" -and $key -eq $platform_default) { $annot = " (server default)" }
@ -840,7 +862,8 @@ function psmain {
#punkbin layout contract; third-party mirrors carry the same file)
$localdirs = @()
if (Test-Path -Path $rtfolder -PathType Container) {
$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 ( $PSBoundParameters.ContainsKey('remote') ) {
$manifesturl = "$artifacturl/platforms.txt"

Loading…
Cancel
Save