From 2ce3edc3905f8e6ba52396e6aee3431e4e636ce8 Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Wed, 22 Jul 2026 12:32:24 +1000 Subject: [PATCH] punk-runtime: 'platforms ?-remote?' action - server platform discovery via punkbin platforms.txt Raw-file artifact servers have no directory listing, so served-platform discovery rides a root-level platforms.txt manifest, now part of the punkbin layout contract (generated by punkbin's src/build_sha1sums.tcl; committed in punkbin locally - 7b8a244 - push remains the maintainer's call; third-party mirrors using the layout carry the same file). Both payloads in parity (rewrapped; roundtrip pin PASS; layout copy + .ps1 twin refreshed): 'platforms' lists local bin/runtime/* folders with the local platform marked; 'platforms -remote' fetches the manifest (cached-copy fallback), marks local platform / local-dir presence / local-only dirs, and points at 'list -remote -platform ' for per-platform runtimes. Servers without the manifest get an actionable message naming the -platform escape hatch and the canon reference ('help platforms'). Verified end-to-end through the wrapped cmd against a file:// mirror simulation of the local punkbin checkout, including the no-manifest fallback path. Project 0.18.2. Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com --- CHANGELOG.md | 4 + bin/AGENTS.md | 9 +- bin/punk-runtime.cmd | 178 +++++++++++++++++- goals/G-103-runtime-kit-family.md | 7 + punkproject.toml | 2 +- .../punk/project-0.1/bin/punk-runtime.cmd | 178 +++++++++++++++++- src/scriptapps/bin/punk-runtime.bash | 84 ++++++++- src/scriptapps/bin/punk-runtime.ps1 | 94 ++++++++- 8 files changed, 539 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15b5f23d..4387ea71 100644 --- a/CHANGELOG.md +++ b/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.2] - 2026-07-22 + +- `bin/punk-runtime.cmd`: new `platforms ?-remote?` action - lists local `bin/runtime/*` platform folders (local platform marked), or the platforms the artifact server serves via the server's new root-level `platforms.txt` discovery manifest (raw-file servers have no directory listing; the manifest is now part of the punkbin layout contract, generated by punkbin's maintenance script, and third-party mirrors using the layout carry the same file). Local presence marked, cached-copy fallback, actionable message for pre-convention servers. + ## [0.18.1] - 2026-07-22 - `punk::platform` records + `help platforms` gain a `buildsuite` axis (supported/planned/candidate/none): whether the punkshell zig buildsuites produce runtimes for a platform - deliberately separate from the artifact-tree tiers, since punkbin-structured repos can host runtimes built by any mechanism (a platform can be runtime-tier hosted while buildsuite=none, e.g. netbsd/dragonflybsd). openbsd/netbsd/dragonflybsd records now carry the runtime tier (hosted third-party runtimes possible). diff --git a/bin/AGENTS.md b/bin/AGENTS.md index da28d3c0..f30078d8 100644 --- a/bin/AGENTS.md +++ b/bin/AGENTS.md @@ -113,7 +113,14 @@ whose metadata `target` disagrees with the folder it sits in (`!TARGET-MISMATCH` `run` is LOCAL ONLY - it rejects a leading `-platform` and ignores the env override (later `run` args pass through to the runtime untouched). A no-args invocation prints a short usage block; the `help` action gives the full operator reference (actions, -options, env vars incl `PUNKBIN_URL`, examples). Platform names follow the CANONICAL +options, env vars incl `PUNKBIN_URL`, examples). `platforms ?-remote?` enumerates +platform folders: local `bin/runtime/*` dirs (local platform marked), or - with +`-remote` - the platforms the artifact server serves, read from the server's +root-level `platforms.txt` discovery manifest (part of the punkbin layout contract, +generated by punkbin's `src/build_sha1sums.tcl`; third-party mirrors using the layout +carry the same file - raw-file servers have no directory listing, so the manifest IS +the discovery mechanism), with local presence marked and cached-copy fallback; +servers without the manifest get an actionable message. Platform names follow the CANONICAL punkshell platform-dir names defined by the `punk::platform` module and surfaced as `help platforms` in the punk shell (cpu tokens normalized: amd64->x86_64, aarch64->arm64; the bash payload's local-platform prongs emit canonical names - the diff --git a/bin/punk-runtime.cmd b/bin/punk-runtime.cmd index ed9541f1..72a3cadc 100755 --- a/bin/punk-runtime.cmd +++ b/bin/punk-runtime.cmd @@ -1396,7 +1396,7 @@ action="${1:-}" [[ $# -gt 0 ]] && shift platform_opt="" case "$action" in - fetch|list|use) + fetch|list|use|platforms) newargs=() while [[ $# -gt 0 ]]; do if [[ "$1" == "-platform" ]]; then @@ -1512,11 +1512,12 @@ metadata_summary() { #operator help (the 'help' action; the no-args case shows show_usage only). #Keep in sync with the ps1 payload's Show-PunkRuntimeHelp/Show-PunkRuntimeUsage. show_usage() { - echo "Usage: $0 {fetch|list|use|run|help}" + echo "Usage: $0 {fetch|list|use|run|platforms|help}" echo " fetch ?? ?-platform

? download+verify a runtime from punkbin" echo " list ?-remote? ?-platform

? installed (or server) runtimes + metadata" echo " use ?-platform

? select active / materialize -r artifact" echo " run ?args...? launch the active local-platform runtime" + echo " platforms ?-remote? local platform folders / platforms the server serves" echo " help full help (options, env vars, examples)" } show_help() { @@ -1548,6 +1549,13 @@ show_help() { echo " Resolution: PUNK_ACTIVE_RUNTIME env > active.toml > sole" echo " installed candidate. Takes no -platform (foreign binaries are" echo " not runnable here)." + echo " platforms ?-remote?" + echo " List local platform folders under bin/runtime/. With -remote," + echo " list the platforms the artifact server serves - read from the" + echo " server's platforms.txt discovery manifest (part of the punkbin" + echo " layout; third-party mirrors carry the same file), with local" + echo " presence marked. Servers without the manifest get an actionable" + echo " message (name platforms explicitly with -platform)." echo "" echo "Platforms: punkbin platform-dir names (e.g win32-x86_64, linux-x86_64," echo " macosx) - not zig triples. Default is the local platform; override" @@ -1561,6 +1569,7 @@ show_help() { echo " PUNK_ACTIVE_RUNTIME (run-time selection override)" echo "" echo "Examples:" + echo " $0 platforms -remote" echo " $0 fetch tclsh9.0.5-punk-r1.exe" echo " $0 use tclsh9.0.5-punk-r1.exe (materializes tclsh9.0.5-punk.exe)" echo " $0 list -remote -platform linux-x86_64" @@ -1854,6 +1863,77 @@ case "$action" in #exactly the runtime's argument list) $activeruntime_fullpath "$@" ;; + "platforms") + #enumerate platform folders: local (bin/runtime/*) and, with -remote, the + #server's platforms.txt discovery manifest (raw-file servers have no + #directory listing - the manifest is part of the punkbin layout contract; + #third-party mirrors carry the same file). -platform is ignored here + #(this action enumerates ALL platforms). + 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) + fi + if [[ "${1:-}" == "-remote" ]]; then + manifesturl="${url_kitbase}/platforms.txt" + manifestlocal="${rtroot}/platforms.txt" + mkdir -p "$rtroot" + if curl -fsSL --output "$manifestlocal" "$manifesturl"; then + echo "Fetched $manifesturl" + elif [[ -f "$manifestlocal" ]]; then + echo "WARNING: could not fetch $manifesturl - using cached copy at $manifestlocal" + else + echo "No platforms.txt available from $manifesturl" + echo "(pre-convention punkbin or third-party mirror without the discovery manifest)" + echo "Name platforms explicitly with -platform; canonical names: 'help platforms' in the punk shell" + exit 1 + fi + echo "-----------------------------------------------------------------------" + echo "Platforms served by ${url_kitbase}" + echo "-----------------------------------------------------------------------" + remoteplatforms="" + while IFS= read -r line; do + line="${line#"${line%%[![:space:]]*}"}" + [[ -z "$line" || "${line:0:1}" == "#" ]] && continue + remoteplatforms="$remoteplatforms $line" + marks="" + [[ "$line" == "$local_platform" ]] && marks="local platform" + if printf '%s\n' $localdirs | grep -qx "$line"; then + [[ -n "$marks" ]] && marks="$marks, " + marks="${marks}local dir present" + fi + if [[ -n "$marks" ]]; then + printf ' %-25s (%s)\n' "$line" "$marks" + else + printf ' %-25s\n' "$line" + fi + done < "$manifestlocal" + for d in $localdirs; do + if ! printf '%s\n' $remoteplatforms | grep -qx "$d"; then + printf ' %-25s (local dir only - not served remotely)\n' "$d" + fi + done + echo "-----------------------------------------------------------------------" + echo "Use: '$0 list -remote -platform ' to see a platform's runtimes" + else + echo "-----------------------------------------------------------------------" + echo "Local platform folders under $rtroot" + echo "-----------------------------------------------------------------------" + if [[ -z "$localdirs" ]]; then + echo " (none - 'fetch' creates the local platform's folder)" + fi + for d in $localdirs; do + if [[ "$d" == "$local_platform" ]]; then + printf '* %-25s (local platform)\n' "$d" + else + printf ' %-25s\n' "$d" + fi + done + echo "-----------------------------------------------------------------------" + echo "Use: '$0 platforms -remote' to see platforms served by the artifact server" + echo "Canonical platform names: 'help platforms' in the punk shell" + fi + ;; "help") show_help ;; @@ -2241,11 +2321,12 @@ function Get-PunkRuntimeCandidates { #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. function Show-PunkRuntimeUsage { - write-host "Usage: punk-runtime.cmd {fetch|list|use|run|help}" + write-host "Usage: punk-runtime.cmd {fetch|list|use|run|platforms|help}" write-host " fetch ?? ?-platform

? download+verify a runtime from punkbin" write-host " list ?-remote? ?-platform

? installed (or server) runtimes + metadata" write-host " use ?-platform

? select active / materialize -r artifact" write-host " run ?args...? launch the active local-platform runtime" + write-host " platforms ?-remote? local platform folders / platforms the server serves" write-host " help full help (options, env vars, examples)" } function Show-PunkRuntimeHelp { @@ -2277,6 +2358,13 @@ function Show-PunkRuntimeHelp { write-host " Resolution: PUNK_ACTIVE_RUNTIME env > active.toml > sole" write-host " installed candidate. Takes no -platform (foreign binaries are" write-host " not runnable here)." + write-host " platforms ?-remote?" + write-host " List local platform folders under bin/runtime/. With -remote," + write-host " list the platforms the artifact server serves - read from the" + write-host " server's platforms.txt discovery manifest (part of the punkbin" + write-host " layout; third-party mirrors carry the same file), with local" + write-host " presence marked. Servers without the manifest get an actionable" + write-host " message (name platforms explicitly with -platform)." write-host "" write-host "Platforms: punkbin platform-dir names (e.g win32-x86_64, linux-x86_64," write-host " macosx) - not zig triples. Default is the local platform; override" @@ -2290,6 +2378,7 @@ function Show-PunkRuntimeHelp { write-host " PUNK_ACTIVE_RUNTIME (run-time selection override)" write-host "" write-host "Examples:" + write-host " punk-runtime.cmd platforms -remote" write-host " punk-runtime.cmd fetch tclsh9.0.5-punk-r1.exe" write-host " punk-runtime.cmd use tclsh9.0.5-punk-r1.exe (materializes tclsh9.0.5-punk.exe)" write-host " punk-runtime.cmd list -remote -platform linux-x86_64" @@ -2380,7 +2469,9 @@ function psmain { [Parameter(Mandatory=$false, Position = 0)][string] $action = "" ) dynamicparam { - if ($action -eq 'list') { + if ($action -eq 'list' -or $action -eq 'platforms') { + #shared dynamic params: -remote for both; -platform is meaningful to + #'list' and ignored by 'platforms' (which enumerates ALL platforms) $parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ ParameterSetName = "listruntime" Mandatory = $false @@ -2477,7 +2568,7 @@ function psmain { 'action' { write-host "got action " $PSBoundParameters.action Set-Variable -Name $_ -Value $PSBoundParameters."$_" - $known_actions = @("fetch", "list", "use", "run", "help") + $known_actions = @("fetch", "list", "use", "run", "platforms", "help") if (-not($known_actions -contains $action)) { write-host "action '$action' not understood. Known_actions: $known_actions" exit 1 @@ -2903,6 +2994,83 @@ function psmain { } } } + 'platforms' { + #enumerate platform folders: local (bin/runtime/*) and, with + #-remote, the server's platforms.txt discovery manifest (raw-file + #servers have no directory listing - the manifest is part of the + #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) + } + if ( $PSBoundParameters.ContainsKey('remote') ) { + $manifesturl = "$artifacturl/platforms.txt" + $manifestlocal = Join-Path -Path $rtfolder -ChildPath "platforms.txt" + if (-not (Test-Path -Path $rtfolder -PathType Container)) { + new-item -Path $rtfolder -ItemType Directory -force | out-null + } + try { + Invoke-WebRequest -Uri $manifesturl -OutFile $manifestlocal -ErrorAction Stop + Write-Host "Fetched $manifesturl" + } catch { + if (Test-Path -Path $manifestlocal -PathType Leaf) { + Write-Host "WARNING: could not fetch ${manifesturl}: $($_.Exception.Message)" + Write-Host "WARNING: using cached copy at $manifestlocal" + } else { + Write-Host "No platforms.txt available from ${manifesturl}: $($_.Exception.Message)" + Write-Host "(pre-convention punkbin or third-party mirror without the discovery manifest)" + Write-Host "Name platforms explicitly with -platform; canonical names: 'help platforms' in the punk shell" + exit 1 + } + } + $remoteplatforms = @() + foreach ($line in (Get-Content -Path $manifestlocal)) { + $line = $line.Trim() + if ($line -eq "" -or $line.StartsWith("#")) { continue } + $remoteplatforms += $line + } + Write-host "-----------------------------------------------------------------------" + Write-Host "Platforms served by $artifacturl" + Write-host "-----------------------------------------------------------------------" + foreach ($p in $remoteplatforms) { + $marks = @() + if ($p -eq $script:PunkLocalPlatform) { $marks += "local platform" } + if ($localdirs -contains $p) { $marks += "local dir present" } + $lhs = "$p".PadRight(25, ' ') + if ($marks.Count -gt 0) { + write-host " $lhs ($($marks -join ', '))" + } else { + write-host " $lhs" + } + } + foreach ($d in $localdirs) { + if (-not ($remoteplatforms -contains $d)) { + $lhs = "$d".PadRight(25, ' ') + write-host " $lhs (local dir only - not served remotely)" + } + } + Write-host "-----------------------------------------------------------------------" + Write-Host "Use: 'list -remote -platform ' to see a platform's runtimes" + } else { + Write-host "-----------------------------------------------------------------------" + Write-Host "Local platform folders under $rtfolder" + Write-host "-----------------------------------------------------------------------" + if ($localdirs.Count -eq 0) { + write-host " (none - 'fetch' creates the local platform's folder)" + } + foreach ($d in $localdirs) { + $lhs = "$d".PadRight(25, ' ') + if ($d -eq $script:PunkLocalPlatform) { + write-host "* $lhs (local platform)" + } else { + write-host " $lhs" + } + } + Write-host "-----------------------------------------------------------------------" + Write-Host "Use: 'platforms -remote' to see platforms served by the artifact server" + Write-Host "Canonical platform names: 'help platforms' in the punk shell" + } + } 'help' { Show-PunkRuntimeHelp } diff --git a/goals/G-103-runtime-kit-family.md b/goals/G-103-runtime-kit-family.md index ef8c72ed..04e2336c 100644 --- a/goals/G-103-runtime-kit-family.md +++ b/goals/G-103-runtime-kit-family.md @@ -402,3 +402,10 @@ Remaining for acceptance: applies). - record the 8.6-family deferral note against G-101 when closing (the acceptance's explicit deferral - no work item here). +- 2026-07-22: punkbin layout contract gained a root-level platforms.txt + discovery manifest (generated by punkbin src/build_sha1sums.tcl; committed + locally in punkbin 7b8a244, push = user decision) - raw-file artifact + servers have no directory listing, so the manifest is how punk-runtime's + new 'platforms -remote' action (and third-party mirrors per the Context + "compatible repos" note) enumerate served platforms. Verified end-to-end + against a file:// mirror simulation of the local punkbin checkout. diff --git a/punkproject.toml b/punkproject.toml index ff3ffdc8..d88e31ae 100644 --- a/punkproject.toml +++ b/punkproject.toml @@ -1,4 +1,4 @@ [project] name = "punkshell" -version = "0.18.1" +version = "0.18.2" license = "BSD-2-Clause" diff --git a/src/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd b/src/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd index ed9541f1..72a3cadc 100644 --- a/src/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd +++ b/src/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd @@ -1396,7 +1396,7 @@ action="${1:-}" [[ $# -gt 0 ]] && shift platform_opt="" case "$action" in - fetch|list|use) + fetch|list|use|platforms) newargs=() while [[ $# -gt 0 ]]; do if [[ "$1" == "-platform" ]]; then @@ -1512,11 +1512,12 @@ metadata_summary() { #operator help (the 'help' action; the no-args case shows show_usage only). #Keep in sync with the ps1 payload's Show-PunkRuntimeHelp/Show-PunkRuntimeUsage. show_usage() { - echo "Usage: $0 {fetch|list|use|run|help}" + echo "Usage: $0 {fetch|list|use|run|platforms|help}" echo " fetch ?? ?-platform

? download+verify a runtime from punkbin" echo " list ?-remote? ?-platform

? installed (or server) runtimes + metadata" echo " use ?-platform

? select active / materialize -r artifact" echo " run ?args...? launch the active local-platform runtime" + echo " platforms ?-remote? local platform folders / platforms the server serves" echo " help full help (options, env vars, examples)" } show_help() { @@ -1548,6 +1549,13 @@ show_help() { echo " Resolution: PUNK_ACTIVE_RUNTIME env > active.toml > sole" echo " installed candidate. Takes no -platform (foreign binaries are" echo " not runnable here)." + echo " platforms ?-remote?" + echo " List local platform folders under bin/runtime/. With -remote," + echo " list the platforms the artifact server serves - read from the" + echo " server's platforms.txt discovery manifest (part of the punkbin" + echo " layout; third-party mirrors carry the same file), with local" + echo " presence marked. Servers without the manifest get an actionable" + echo " message (name platforms explicitly with -platform)." echo "" echo "Platforms: punkbin platform-dir names (e.g win32-x86_64, linux-x86_64," echo " macosx) - not zig triples. Default is the local platform; override" @@ -1561,6 +1569,7 @@ show_help() { echo " PUNK_ACTIVE_RUNTIME (run-time selection override)" echo "" echo "Examples:" + echo " $0 platforms -remote" echo " $0 fetch tclsh9.0.5-punk-r1.exe" echo " $0 use tclsh9.0.5-punk-r1.exe (materializes tclsh9.0.5-punk.exe)" echo " $0 list -remote -platform linux-x86_64" @@ -1854,6 +1863,77 @@ case "$action" in #exactly the runtime's argument list) $activeruntime_fullpath "$@" ;; + "platforms") + #enumerate platform folders: local (bin/runtime/*) and, with -remote, the + #server's platforms.txt discovery manifest (raw-file servers have no + #directory listing - the manifest is part of the punkbin layout contract; + #third-party mirrors carry the same file). -platform is ignored here + #(this action enumerates ALL platforms). + 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) + fi + if [[ "${1:-}" == "-remote" ]]; then + manifesturl="${url_kitbase}/platforms.txt" + manifestlocal="${rtroot}/platforms.txt" + mkdir -p "$rtroot" + if curl -fsSL --output "$manifestlocal" "$manifesturl"; then + echo "Fetched $manifesturl" + elif [[ -f "$manifestlocal" ]]; then + echo "WARNING: could not fetch $manifesturl - using cached copy at $manifestlocal" + else + echo "No platforms.txt available from $manifesturl" + echo "(pre-convention punkbin or third-party mirror without the discovery manifest)" + echo "Name platforms explicitly with -platform; canonical names: 'help platforms' in the punk shell" + exit 1 + fi + echo "-----------------------------------------------------------------------" + echo "Platforms served by ${url_kitbase}" + echo "-----------------------------------------------------------------------" + remoteplatforms="" + while IFS= read -r line; do + line="${line#"${line%%[![:space:]]*}"}" + [[ -z "$line" || "${line:0:1}" == "#" ]] && continue + remoteplatforms="$remoteplatforms $line" + marks="" + [[ "$line" == "$local_platform" ]] && marks="local platform" + if printf '%s\n' $localdirs | grep -qx "$line"; then + [[ -n "$marks" ]] && marks="$marks, " + marks="${marks}local dir present" + fi + if [[ -n "$marks" ]]; then + printf ' %-25s (%s)\n' "$line" "$marks" + else + printf ' %-25s\n' "$line" + fi + done < "$manifestlocal" + for d in $localdirs; do + if ! printf '%s\n' $remoteplatforms | grep -qx "$d"; then + printf ' %-25s (local dir only - not served remotely)\n' "$d" + fi + done + echo "-----------------------------------------------------------------------" + echo "Use: '$0 list -remote -platform ' to see a platform's runtimes" + else + echo "-----------------------------------------------------------------------" + echo "Local platform folders under $rtroot" + echo "-----------------------------------------------------------------------" + if [[ -z "$localdirs" ]]; then + echo " (none - 'fetch' creates the local platform's folder)" + fi + for d in $localdirs; do + if [[ "$d" == "$local_platform" ]]; then + printf '* %-25s (local platform)\n' "$d" + else + printf ' %-25s\n' "$d" + fi + done + echo "-----------------------------------------------------------------------" + echo "Use: '$0 platforms -remote' to see platforms served by the artifact server" + echo "Canonical platform names: 'help platforms' in the punk shell" + fi + ;; "help") show_help ;; @@ -2241,11 +2321,12 @@ function Get-PunkRuntimeCandidates { #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. function Show-PunkRuntimeUsage { - write-host "Usage: punk-runtime.cmd {fetch|list|use|run|help}" + write-host "Usage: punk-runtime.cmd {fetch|list|use|run|platforms|help}" write-host " fetch ?? ?-platform

? download+verify a runtime from punkbin" write-host " list ?-remote? ?-platform

? installed (or server) runtimes + metadata" write-host " use ?-platform

? select active / materialize -r artifact" write-host " run ?args...? launch the active local-platform runtime" + write-host " platforms ?-remote? local platform folders / platforms the server serves" write-host " help full help (options, env vars, examples)" } function Show-PunkRuntimeHelp { @@ -2277,6 +2358,13 @@ function Show-PunkRuntimeHelp { write-host " Resolution: PUNK_ACTIVE_RUNTIME env > active.toml > sole" write-host " installed candidate. Takes no -platform (foreign binaries are" write-host " not runnable here)." + write-host " platforms ?-remote?" + write-host " List local platform folders under bin/runtime/. With -remote," + write-host " list the platforms the artifact server serves - read from the" + write-host " server's platforms.txt discovery manifest (part of the punkbin" + write-host " layout; third-party mirrors carry the same file), with local" + write-host " presence marked. Servers without the manifest get an actionable" + write-host " message (name platforms explicitly with -platform)." write-host "" write-host "Platforms: punkbin platform-dir names (e.g win32-x86_64, linux-x86_64," write-host " macosx) - not zig triples. Default is the local platform; override" @@ -2290,6 +2378,7 @@ function Show-PunkRuntimeHelp { write-host " PUNK_ACTIVE_RUNTIME (run-time selection override)" write-host "" write-host "Examples:" + write-host " punk-runtime.cmd platforms -remote" write-host " punk-runtime.cmd fetch tclsh9.0.5-punk-r1.exe" write-host " punk-runtime.cmd use tclsh9.0.5-punk-r1.exe (materializes tclsh9.0.5-punk.exe)" write-host " punk-runtime.cmd list -remote -platform linux-x86_64" @@ -2380,7 +2469,9 @@ function psmain { [Parameter(Mandatory=$false, Position = 0)][string] $action = "" ) dynamicparam { - if ($action -eq 'list') { + if ($action -eq 'list' -or $action -eq 'platforms') { + #shared dynamic params: -remote for both; -platform is meaningful to + #'list' and ignored by 'platforms' (which enumerates ALL platforms) $parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ ParameterSetName = "listruntime" Mandatory = $false @@ -2477,7 +2568,7 @@ function psmain { 'action' { write-host "got action " $PSBoundParameters.action Set-Variable -Name $_ -Value $PSBoundParameters."$_" - $known_actions = @("fetch", "list", "use", "run", "help") + $known_actions = @("fetch", "list", "use", "run", "platforms", "help") if (-not($known_actions -contains $action)) { write-host "action '$action' not understood. Known_actions: $known_actions" exit 1 @@ -2903,6 +2994,83 @@ function psmain { } } } + 'platforms' { + #enumerate platform folders: local (bin/runtime/*) and, with + #-remote, the server's platforms.txt discovery manifest (raw-file + #servers have no directory listing - the manifest is part of the + #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) + } + if ( $PSBoundParameters.ContainsKey('remote') ) { + $manifesturl = "$artifacturl/platforms.txt" + $manifestlocal = Join-Path -Path $rtfolder -ChildPath "platforms.txt" + if (-not (Test-Path -Path $rtfolder -PathType Container)) { + new-item -Path $rtfolder -ItemType Directory -force | out-null + } + try { + Invoke-WebRequest -Uri $manifesturl -OutFile $manifestlocal -ErrorAction Stop + Write-Host "Fetched $manifesturl" + } catch { + if (Test-Path -Path $manifestlocal -PathType Leaf) { + Write-Host "WARNING: could not fetch ${manifesturl}: $($_.Exception.Message)" + Write-Host "WARNING: using cached copy at $manifestlocal" + } else { + Write-Host "No platforms.txt available from ${manifesturl}: $($_.Exception.Message)" + Write-Host "(pre-convention punkbin or third-party mirror without the discovery manifest)" + Write-Host "Name platforms explicitly with -platform; canonical names: 'help platforms' in the punk shell" + exit 1 + } + } + $remoteplatforms = @() + foreach ($line in (Get-Content -Path $manifestlocal)) { + $line = $line.Trim() + if ($line -eq "" -or $line.StartsWith("#")) { continue } + $remoteplatforms += $line + } + Write-host "-----------------------------------------------------------------------" + Write-Host "Platforms served by $artifacturl" + Write-host "-----------------------------------------------------------------------" + foreach ($p in $remoteplatforms) { + $marks = @() + if ($p -eq $script:PunkLocalPlatform) { $marks += "local platform" } + if ($localdirs -contains $p) { $marks += "local dir present" } + $lhs = "$p".PadRight(25, ' ') + if ($marks.Count -gt 0) { + write-host " $lhs ($($marks -join ', '))" + } else { + write-host " $lhs" + } + } + foreach ($d in $localdirs) { + if (-not ($remoteplatforms -contains $d)) { + $lhs = "$d".PadRight(25, ' ') + write-host " $lhs (local dir only - not served remotely)" + } + } + Write-host "-----------------------------------------------------------------------" + Write-Host "Use: 'list -remote -platform ' to see a platform's runtimes" + } else { + Write-host "-----------------------------------------------------------------------" + Write-Host "Local platform folders under $rtfolder" + Write-host "-----------------------------------------------------------------------" + if ($localdirs.Count -eq 0) { + write-host " (none - 'fetch' creates the local platform's folder)" + } + foreach ($d in $localdirs) { + $lhs = "$d".PadRight(25, ' ') + if ($d -eq $script:PunkLocalPlatform) { + write-host "* $lhs (local platform)" + } else { + write-host " $lhs" + } + } + Write-host "-----------------------------------------------------------------------" + Write-Host "Use: 'platforms -remote' to see platforms served by the artifact server" + Write-Host "Canonical platform names: 'help platforms' in the punk shell" + } + } 'help' { Show-PunkRuntimeHelp } diff --git a/src/scriptapps/bin/punk-runtime.bash b/src/scriptapps/bin/punk-runtime.bash index 44e0f7cd..46711e19 100644 --- a/src/scriptapps/bin/punk-runtime.bash +++ b/src/scriptapps/bin/punk-runtime.bash @@ -116,7 +116,7 @@ action="${1:-}" [[ $# -gt 0 ]] && shift platform_opt="" case "$action" in - fetch|list|use) + fetch|list|use|platforms) newargs=() while [[ $# -gt 0 ]]; do if [[ "$1" == "-platform" ]]; then @@ -232,11 +232,12 @@ metadata_summary() { #operator help (the 'help' action; the no-args case shows show_usage only). #Keep in sync with the ps1 payload's Show-PunkRuntimeHelp/Show-PunkRuntimeUsage. show_usage() { - echo "Usage: $0 {fetch|list|use|run|help}" + echo "Usage: $0 {fetch|list|use|run|platforms|help}" echo " fetch ?? ?-platform

? download+verify a runtime from punkbin" echo " list ?-remote? ?-platform

? installed (or server) runtimes + metadata" echo " use ?-platform

? select active / materialize -r artifact" echo " run ?args...? launch the active local-platform runtime" + echo " platforms ?-remote? local platform folders / platforms the server serves" echo " help full help (options, env vars, examples)" } show_help() { @@ -268,6 +269,13 @@ show_help() { echo " Resolution: PUNK_ACTIVE_RUNTIME env > active.toml > sole" echo " installed candidate. Takes no -platform (foreign binaries are" echo " not runnable here)." + echo " platforms ?-remote?" + echo " List local platform folders under bin/runtime/. With -remote," + echo " list the platforms the artifact server serves - read from the" + echo " server's platforms.txt discovery manifest (part of the punkbin" + echo " layout; third-party mirrors carry the same file), with local" + echo " presence marked. Servers without the manifest get an actionable" + echo " message (name platforms explicitly with -platform)." echo "" echo "Platforms: punkbin platform-dir names (e.g win32-x86_64, linux-x86_64," echo " macosx) - not zig triples. Default is the local platform; override" @@ -281,6 +289,7 @@ show_help() { echo " PUNK_ACTIVE_RUNTIME (run-time selection override)" echo "" echo "Examples:" + echo " $0 platforms -remote" echo " $0 fetch tclsh9.0.5-punk-r1.exe" echo " $0 use tclsh9.0.5-punk-r1.exe (materializes tclsh9.0.5-punk.exe)" echo " $0 list -remote -platform linux-x86_64" @@ -574,6 +583,77 @@ case "$action" in #exactly the runtime's argument list) $activeruntime_fullpath "$@" ;; + "platforms") + #enumerate platform folders: local (bin/runtime/*) and, with -remote, the + #server's platforms.txt discovery manifest (raw-file servers have no + #directory listing - the manifest is part of the punkbin layout contract; + #third-party mirrors carry the same file). -platform is ignored here + #(this action enumerates ALL platforms). + 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) + fi + if [[ "${1:-}" == "-remote" ]]; then + manifesturl="${url_kitbase}/platforms.txt" + manifestlocal="${rtroot}/platforms.txt" + mkdir -p "$rtroot" + if curl -fsSL --output "$manifestlocal" "$manifesturl"; then + echo "Fetched $manifesturl" + elif [[ -f "$manifestlocal" ]]; then + echo "WARNING: could not fetch $manifesturl - using cached copy at $manifestlocal" + else + echo "No platforms.txt available from $manifesturl" + echo "(pre-convention punkbin or third-party mirror without the discovery manifest)" + echo "Name platforms explicitly with -platform; canonical names: 'help platforms' in the punk shell" + exit 1 + fi + echo "-----------------------------------------------------------------------" + echo "Platforms served by ${url_kitbase}" + echo "-----------------------------------------------------------------------" + remoteplatforms="" + while IFS= read -r line; do + line="${line#"${line%%[![:space:]]*}"}" + [[ -z "$line" || "${line:0:1}" == "#" ]] && continue + remoteplatforms="$remoteplatforms $line" + marks="" + [[ "$line" == "$local_platform" ]] && marks="local platform" + if printf '%s\n' $localdirs | grep -qx "$line"; then + [[ -n "$marks" ]] && marks="$marks, " + marks="${marks}local dir present" + fi + if [[ -n "$marks" ]]; then + printf ' %-25s (%s)\n' "$line" "$marks" + else + printf ' %-25s\n' "$line" + fi + done < "$manifestlocal" + for d in $localdirs; do + if ! printf '%s\n' $remoteplatforms | grep -qx "$d"; then + printf ' %-25s (local dir only - not served remotely)\n' "$d" + fi + done + echo "-----------------------------------------------------------------------" + echo "Use: '$0 list -remote -platform ' to see a platform's runtimes" + else + echo "-----------------------------------------------------------------------" + echo "Local platform folders under $rtroot" + echo "-----------------------------------------------------------------------" + if [[ -z "$localdirs" ]]; then + echo " (none - 'fetch' creates the local platform's folder)" + fi + for d in $localdirs; do + if [[ "$d" == "$local_platform" ]]; then + printf '* %-25s (local platform)\n' "$d" + else + printf ' %-25s\n' "$d" + fi + done + echo "-----------------------------------------------------------------------" + echo "Use: '$0 platforms -remote' to see platforms served by the artifact server" + echo "Canonical platform names: 'help platforms' in the punk shell" + fi + ;; "help") show_help ;; diff --git a/src/scriptapps/bin/punk-runtime.ps1 b/src/scriptapps/bin/punk-runtime.ps1 index 6b4df331..552312d5 100644 --- a/src/scriptapps/bin/punk-runtime.ps1 +++ b/src/scriptapps/bin/punk-runtime.ps1 @@ -73,11 +73,12 @@ function Get-PunkRuntimeCandidates { #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. function Show-PunkRuntimeUsage { - write-host "Usage: punk-runtime.cmd {fetch|list|use|run|help}" + write-host "Usage: punk-runtime.cmd {fetch|list|use|run|platforms|help}" write-host " fetch ?? ?-platform

? download+verify a runtime from punkbin" write-host " list ?-remote? ?-platform

? installed (or server) runtimes + metadata" write-host " use ?-platform

? select active / materialize -r artifact" write-host " run ?args...? launch the active local-platform runtime" + write-host " platforms ?-remote? local platform folders / platforms the server serves" write-host " help full help (options, env vars, examples)" } function Show-PunkRuntimeHelp { @@ -109,6 +110,13 @@ function Show-PunkRuntimeHelp { write-host " Resolution: PUNK_ACTIVE_RUNTIME env > active.toml > sole" write-host " installed candidate. Takes no -platform (foreign binaries are" write-host " not runnable here)." + write-host " platforms ?-remote?" + write-host " List local platform folders under bin/runtime/. With -remote," + write-host " list the platforms the artifact server serves - read from the" + write-host " server's platforms.txt discovery manifest (part of the punkbin" + write-host " layout; third-party mirrors carry the same file), with local" + write-host " presence marked. Servers without the manifest get an actionable" + write-host " message (name platforms explicitly with -platform)." write-host "" write-host "Platforms: punkbin platform-dir names (e.g win32-x86_64, linux-x86_64," write-host " macosx) - not zig triples. Default is the local platform; override" @@ -122,6 +130,7 @@ function Show-PunkRuntimeHelp { write-host " PUNK_ACTIVE_RUNTIME (run-time selection override)" write-host "" write-host "Examples:" + write-host " punk-runtime.cmd platforms -remote" write-host " punk-runtime.cmd fetch tclsh9.0.5-punk-r1.exe" write-host " punk-runtime.cmd use tclsh9.0.5-punk-r1.exe (materializes tclsh9.0.5-punk.exe)" write-host " punk-runtime.cmd list -remote -platform linux-x86_64" @@ -212,7 +221,9 @@ function psmain { [Parameter(Mandatory=$false, Position = 0)][string] $action = "" ) dynamicparam { - if ($action -eq 'list') { + if ($action -eq 'list' -or $action -eq 'platforms') { + #shared dynamic params: -remote for both; -platform is meaningful to + #'list' and ignored by 'platforms' (which enumerates ALL platforms) $parameterAttribute = [System.Management.Automation.ParameterAttribute]@{ ParameterSetName = "listruntime" Mandatory = $false @@ -309,7 +320,7 @@ function psmain { 'action' { write-host "got action " $PSBoundParameters.action Set-Variable -Name $_ -Value $PSBoundParameters."$_" - $known_actions = @("fetch", "list", "use", "run", "help") + $known_actions = @("fetch", "list", "use", "run", "platforms", "help") if (-not($known_actions -contains $action)) { write-host "action '$action' not understood. Known_actions: $known_actions" exit 1 @@ -735,6 +746,83 @@ function psmain { } } } + 'platforms' { + #enumerate platform folders: local (bin/runtime/*) and, with + #-remote, the server's platforms.txt discovery manifest (raw-file + #servers have no directory listing - the manifest is part of the + #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) + } + if ( $PSBoundParameters.ContainsKey('remote') ) { + $manifesturl = "$artifacturl/platforms.txt" + $manifestlocal = Join-Path -Path $rtfolder -ChildPath "platforms.txt" + if (-not (Test-Path -Path $rtfolder -PathType Container)) { + new-item -Path $rtfolder -ItemType Directory -force | out-null + } + try { + Invoke-WebRequest -Uri $manifesturl -OutFile $manifestlocal -ErrorAction Stop + Write-Host "Fetched $manifesturl" + } catch { + if (Test-Path -Path $manifestlocal -PathType Leaf) { + Write-Host "WARNING: could not fetch ${manifesturl}: $($_.Exception.Message)" + Write-Host "WARNING: using cached copy at $manifestlocal" + } else { + Write-Host "No platforms.txt available from ${manifesturl}: $($_.Exception.Message)" + Write-Host "(pre-convention punkbin or third-party mirror without the discovery manifest)" + Write-Host "Name platforms explicitly with -platform; canonical names: 'help platforms' in the punk shell" + exit 1 + } + } + $remoteplatforms = @() + foreach ($line in (Get-Content -Path $manifestlocal)) { + $line = $line.Trim() + if ($line -eq "" -or $line.StartsWith("#")) { continue } + $remoteplatforms += $line + } + Write-host "-----------------------------------------------------------------------" + Write-Host "Platforms served by $artifacturl" + Write-host "-----------------------------------------------------------------------" + foreach ($p in $remoteplatforms) { + $marks = @() + if ($p -eq $script:PunkLocalPlatform) { $marks += "local platform" } + if ($localdirs -contains $p) { $marks += "local dir present" } + $lhs = "$p".PadRight(25, ' ') + if ($marks.Count -gt 0) { + write-host " $lhs ($($marks -join ', '))" + } else { + write-host " $lhs" + } + } + foreach ($d in $localdirs) { + if (-not ($remoteplatforms -contains $d)) { + $lhs = "$d".PadRight(25, ' ') + write-host " $lhs (local dir only - not served remotely)" + } + } + Write-host "-----------------------------------------------------------------------" + Write-Host "Use: 'list -remote -platform ' to see a platform's runtimes" + } else { + Write-host "-----------------------------------------------------------------------" + Write-Host "Local platform folders under $rtfolder" + Write-host "-----------------------------------------------------------------------" + if ($localdirs.Count -eq 0) { + write-host " (none - 'fetch' creates the local platform's folder)" + } + foreach ($d in $localdirs) { + $lhs = "$d".PadRight(25, ' ') + if ($d -eq $script:PunkLocalPlatform) { + write-host "* $lhs (local platform)" + } else { + write-host " $lhs" + } + } + Write-host "-----------------------------------------------------------------------" + Write-Host "Use: 'platforms -remote' to see platforms served by the artifact server" + Write-Host "Canonical platform names: 'help platforms' in the punk shell" + } + } 'help' { Show-PunkRuntimeHelp }