Browse Source

G-103/G-105 groundwork: punk-runtime -platform surface, help action, no-args usage

Cross-build staging surface (both payloads in parity, rewrapped polyglot,
layout copy + .ps1 twin refreshed, roundtrip pin PASS):

- fetch/list/use accept -platform <p> (punkbin platform-DIR names, never
  zig triples); resolution: -platform arg > PUNK_RUNTIME_PLATFORM env >
  detected local platform; shape-only lowercase validation (server URL
  paths are case-sensitive - ps1 uses -cnotmatch; default -notmatch is
  case-insensitive and passed Win32-X86_64-class typos in testing).
- foreign fetch requires an explicit runtime name (fetch defaults only
  make sense for the platform you stand on).
- use -platform manages that folder's active.toml/materialization - the
  marker travels with the folder when deployed (provisioning story; unix
  exec bits restored at deploy time).
- list flags !TARGET-MISMATCH when a runtime's metadata target disagrees
  with the folder it sits in (cross-fetch misfiling guard).
- run stays LOCAL ONLY: rejects a leading -platform, ignores the env
  override, later args pass through to the runtime untouched.
- new 'help' action (actions, options, env vars, examples) and a real
  usage block on no-args invocation (was a bare action list).
- bash FreeBSD platform dir aligned to punkbin's actual freebsd-x86_64
  (was freebsd-amd64; the G-105 platform-dir naming-alignment item).

Verified on both payloads directly and through the wrapped cmd: noargs,
help, local list unchanged, foreign use-materialization + mismatch flags,
foreign-fetch refusal, run guard, env override (and run's immunity to
it), bad-name validation. Project 0.17.9.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 week ago
parent
commit
d3bfc4484c
  1. 4
      CHANGELOG.md
  2. 18
      bin/AGENTS.md
  3. 396
      bin/punk-runtime.cmd
  4. 22
      goals/G-103-runtime-kit-family.md
  5. 10
      goals/G-105-buildsuite-cross-target.md
  6. 2
      punkproject.toml
  7. 396
      src/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd
  8. 222
      src/scriptapps/bin/punk-runtime.bash
  9. 174
      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.17.9] - 2026-07-22
- `bin/punk-runtime.cmd` (G-103/G-105 groundwork): cross-platform staging surface - `fetch`/`list`/`use` accept `-platform <p>` (punkbin platform-dir names; default = local platform, overridable via `PUNK_RUNTIME_PLATFORM` env) for listing/fetching/selecting runtimes of OTHER platforms (cross-build staging and guest provisioning); foreign fetches require an explicit runtime name; `list` flags runtimes whose metadata `target` disagrees with their folder (`!TARGET-MISMATCH`); `run` stays local-only (rejects `-platform`, ignores the env override). New `help` action (full operator reference: actions, options, env vars, examples) and a proper usage block on no-args invocation. Bash payload's FreeBSD platform dir aligned to punkbin's actual `freebsd-x86_64` (was `freebsd-amd64`). Layout-shipped copy refreshed.
## [0.17.8] - 2026-07-22
- punk::console 0.8.0 (G-106): the powershell console-mode fallback (raw mode on twapi-less windows runtimes) is now dependable and quiet. The persistent pwsh/powershell server starts lazily on first raw enable/disable (loading punk::console no longer spawns a process or prints "twapi not present..." to stderr), is shared process-wide, watches the owning process's pid and exits with it (no orphan pwsh processes), and no longer dies mid-session (the old 20s keepalive with no ping sender, plus a listener defect that killed it after the first message, are both fixed). disableRaw now works via the server on runtimes without `-inputmode` (tcl 8.6 path); enableRaw confirms the flip via the live tcl9 `-inputmode` read before returning. The server script resolves from env `PUNK_PS_CONSOLEMODE_SCRIPT`, the project tree, or an embedded copy in the module - kits and unusual cwds no longer depend on argv0-relative luck. `PUNK_PS_CONSOLEMODE_DEBUG=1` surfaces diagnostics. `scriptlib/utils/pwsh` reconciled to the one canonical server script (experiment variants retired, README added).

18
bin/AGENTS.md

@ -99,6 +99,24 @@ projects reference), copies the metadata toml alongside, and selects the working
(dotted tcl patchlevels make generic last-dot stripping wrong for extensionless unix
names). Candidate listing excludes directories and `.txt/.toml/.tm/.tmp/.log` files.
Cross-platform surface (G-105 groundwork; both payloads): `fetch`/`list`/`use` accept
`-platform <p>` where `<p>` is a punkbin platform-DIR name (`win32-x86_64`,
`linux-x86_64`, `macosx`, ... - never zig triples; the buildsuite maps triples to
platform dirs at build time). Resolution: `-platform` arg > `PUNK_RUNTIME_PLATFORM`
env > the detected local platform; validation is shape-only, lowercase (the artifact
server's URL paths are case-sensitive - the server is the truth for what exists).
Foreign-platform folders serve cross-build staging/provisioning: a foreign `fetch`
requires an explicit runtime name (no foreign defaults), `use -platform` manages that
folder's `active.toml`/materialization (the marker travels with the folder when
deployed; unix exec bits are restored at deploy time), and `list` flags a runtime
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). The bash payload's FreeBSD platform
dir was aligned to punkbin's actual folder name (`freebsd-x86_64`; previously
`freebsd-amd64`).
### Interactive verification shells
- Interactive console/repl verification should cover both Tcl generations - behaviour can differ materially (e.g. the Tcl 8.6 windows console channel driver vs the Tcl 9 rewrite). Use a Tcl 8.6-based punk shell (`punksys.exe`) and a current Tcl 9-based punk shell (named for the Tcl release it embeds, e.g. `punk902z.exe` at the time of writing - ask the user which is current rather than assuming). `info patchlevel` in-session confirms the runtime.

396
bin/punk-runtime.cmd

@ -1299,55 +1299,57 @@ arch=$(uname -m) #machine/architecture
plat=$(uname -s) #platform/system
#even though most of the platform prongs are very similar,
#we keep the code separate so it can be tweaked easily for unexpected differences
#each prong sets archdir (local folder) and, where a runtime is published for the
#platform, rt_default (default runtime name). archtail (server folder) is derived
#from archdir below.
#each prong sets local_platform (the punkbin/bin-runtime platform-DIR name) and,
#where a runtime is published for the platform, rt_default (default runtime name).
if [[ "$plat" = "Linux"* ]]; then
if [[ "$arch" = "x86_64"* ]]; then
archdir="${scriptdir}/runtime/linux-x86_64"
local_platform="linux-x86_64"
rt_default="tclkit-902-Linux64-intel-dyn"
runtime_available=1
elif [[ "$arch" = "arm"* ]]; then
archdir="${scriptdir}/runtime/linux-arm"
local_platform="linux-arm"
rt_default="tclkit-902-Linux64-arm-dyn"
runtime_available=1
else
archdir="${scriptdir}/runtime/linux-$arch"
local_platform="linux-$arch"
fi
os="linux"
elif [[ "$plat" = "Darwin"* ]]; then
os="macosx"
#assumed to be Mach-O 'universal binaries' for both x86-64 and arm? - REVIEW
archdir="${scriptdir}/runtime/macosx"
local_platform="macosx"
rt_default="tclkit-902-Darwin64-dyn"
runtime_available=1
elif [[ "$plat" = "FreeBSD"* ]]; then
archdir="${scriptdir}/runtime/freebsd-amd64"
#aligned 2026-07-22 to the punkbin repo's actual folder name (freebsd-x86_64;
#this payload previously said freebsd-amd64 - the G-105 platform-dir naming
#alignment item)
local_platform="freebsd-x86_64"
os="freebsd"
elif [[ "$plat" == "DragonFly"* ]]; then
archdir="${scriptdir}/runtime/dragonflybsd-$arch"
local_platform="dragonflybsd-$arch"
os="dragonflybsd"
elif [[ "$plat" == "NetBSD"* ]]; then
archdir="${scriptdir}/runtime/netbsd-$arch"
local_platform="netbsd-$arch"
os="netbsd"
elif [[ "$plat" == "OpenBSD"* ]]; then
archdir="${scriptdir}/runtime/openbsd-amd64"
local_platform="openbsd-amd64"
os="openbsd"
elif [[ "$plat" == "MINGW32"* ]]; then
#REVIEW
os="win32"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
elif [[ "$plat" == "MINGW64"* ]]; then
#REVIEW
os="win32"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
elif [[ "$plat" == "CYGWIN_NT"* ]]; then
os="win32"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
elif [[ "$plat" == "MSYS_NT"* ]]; then
@ -1360,14 +1362,61 @@ elif [[ "$plat" == "MSYS_NT"* ]]; then
#"c:/windows/system32/" is quite likely in the path ahead of msys,git etc.
#This breaks calls to various unix utils such as sed etc (wsl related?)
export PATH="$shellfolder${PATH:+:${PATH}}"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
else
archdir="${scriptdir}/runtime/other"
local_platform="other"
os="other"
fi
archtail="${archdir##*/}" #server folder name e.g linux-x86_64
#-- platform resolution (G-105 cross-build staging) ---------------------------
#The prongs above detect the LOCAL platform. fetch/list/use accept
#'-platform <p>' to aim at another punkbin platform-dir (cross-build staging /
#provisioning); resolution: -platform arg > PUNK_RUNTIME_PLATFORM env > local.
#Values are punkbin platform-dir names (e.g win32-x86_64, linux-x86_64, macosx)
#- NOT zig triples (the buildsuite maps triples to platform dirs at build time).
#Validation is shape-only: the server's sha1sums/404 is the truth for what
#exists. 'run' is LOCAL ONLY (foreign binaries are not runnable here) - only a
#LEADING -platform is rejected there; later args belong to the launched runtime.
action="${1:-}"
[[ $# -gt 0 ]] && shift
platform_opt=""
case "$action" in
fetch|list|use)
newargs=()
while [[ $# -gt 0 ]]; do
if [[ "$1" == "-platform" ]]; then
shift
if [[ $# -eq 0 ]]; then
echo "option -platform requires a value (a punkbin platform-dir name, e.g linux-x86_64)"
exit 1
fi
platform_opt="$1"
else
newargs+=("$1")
fi
shift
done
set -- ${newargs[@]+"${newargs[@]}"}
;;
run)
if [[ "${1:-}" == "-platform" ]]; then
echo "'run' launches the LOCAL platform's active runtime - it takes no -platform option"
echo "(foreign-platform folders are cross-build staging; deploy them to their platform to run)"
exit 1
fi
;;
esac
platform="${platform_opt:-${PUNK_RUNTIME_PLATFORM:-$local_platform}}"
if ! [[ "$platform" =~ ^[a-z0-9][a-z0-9_-]*$ ]]; then
echo "invalid platform name '$platform' (expected a punkbin platform-dir name such as win32-x86_64, linux-x86_64, macosx)"
exit 1
fi
is_local=0
[[ "$platform" == "$local_platform" ]] && is_local=1
archdir="${scriptdir}/runtime/${platform}"
archtail="$platform" #server folder name e.g linux-x86_64
active_file="${archdir}/active.toml"
#sha1 of a file - tool varies by platform (sha1sum: linux/coreutils, shasum: macosx,
@ -1425,7 +1474,7 @@ rootname_of() {
#by the buildsuite kit-family-artifacts step / fetched from punkbin). Prints a
#short "[variant=... tcl=... rN ...]" summary for list output, "" when absent.
metadata_summary() {
local exename="$1" tomlfile parts variant tclpatch revision piperepl artname
local exename="$1" tomlfile parts variant tclpatch revision piperepl artname target
tomlfile="$archdir/$(rootname_of "$exename").toml"
[[ -f "$tomlfile" ]] || return 0
variant=$(sed -n 's/^[[:space:]]*variant[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" | head -n 1)
@ -1433,6 +1482,7 @@ metadata_summary() {
revision=$(sed -n 's/^[[:space:]]*revision[[:space:]]*=[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$tomlfile" | head -n 1)
piperepl=$(sed -n 's/^[[:space:]]*piperepl[[:space:]]*=[[:space:]]*\(true\|false\).*/\1/p' "$tomlfile" | head -n 1)
artname=$(sed -n 's/^[[:space:]]*name[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" | head -n 1)
target=$(sed -n 's/^[[:space:]]*target[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" | head -n 1)
parts=""
[[ -n "$variant" ]] && parts="$parts variant=$variant"
[[ -n "$tclpatch" ]] && parts="$parts tcl=$tclpatch"
@ -1441,8 +1491,70 @@ metadata_summary() {
elif [[ "$piperepl" == "false" ]]; then parts="$parts piperepl=off"; fi
#a materialized working copy records which immutable artifact it came from
[[ -n "$artname" && "$artname" != "$exename" ]] && parts="$parts from=$artname"
#integrity flag: a runtime filed under a platform folder its metadata says it
#was not built for (cross-platform fetch/staging misfiling)
[[ -n "$target" && "$target" != "$archtail" ]] && parts="$parts !TARGET-MISMATCH:$target"
[[ -n "$parts" ]] && printf '[%s]' "${parts# }"
}
#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 " fetch ?<name>? ?-platform <p>? download+verify a runtime from punkbin"
echo " list ?-remote? ?-platform <p>? installed (or server) runtimes + metadata"
echo " use <name> ?-platform <p>? select active / materialize -r<N> artifact"
echo " run ?args...? launch the active local-platform runtime"
echo " help full help (options, env vars, examples)"
}
show_help() {
echo "punk-runtime - manage the plain Tcl runtimes under bin/runtime/<platform>/"
echo ""
show_usage
echo ""
echo "Actions:"
echo " fetch ?<name>? ?-platform <p>?"
echo " Download a runtime from the punkbin artifact server into"
echo " bin/runtime/<p>/ with sha1 verification against the server's"
echo " sha1sums.txt. -r<N>-named family artifacts also fetch their"
echo " <rootname>.toml metadata record. Omitting <name> fetches the"
echo " local platform's default runtime; a FOREIGN platform fetch"
echo " requires an explicit <name>."
echo " list ?-remote? ?-platform <p>?"
echo " List installed runtimes with artifact-metadata summaries"
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 " 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"
echo " MATERIALIZED into its WORKING name (name minus -r<N> - what"
echo " mapvfs and projects reference), metadata toml copied alongside."
echo " run ?args...?"
echo " Launch the ACTIVE runtime of the LOCAL platform, passing args."
echo " Resolution: PUNK_ACTIVE_RUNTIME env > active.toml > sole"
echo " installed candidate. Takes no -platform (foreign binaries are"
echo " not runnable here)."
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"
echo " order: -platform argument > PUNK_RUNTIME_PLATFORM env var."
echo " Foreign-platform folders serve cross-build staging and provisioning:"
echo " active.toml travels with the folder when it is deployed to its real"
echo " platform (unix exec bits are restored at deploy time - e.g rsync/tar/"
echo " chmod on the receiving side)."
echo ""
echo "Env: PUNKBIN_URL (artifact server base url), PUNK_RUNTIME_PLATFORM,"
echo " PUNK_ACTIVE_RUNTIME (run-time selection override)"
echo ""
echo "Examples:"
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"
echo " $0 fetch tclsh9.0.5-punk-r1 -platform linux-x86_64"
echo " $0 use tclsh9.0.5-punk-r1 -platform linux-x86_64"
echo " $0 run myscript.tcl arg1 arg2"
}
#G-103 artifact-tier names carry -r<N> before the (optional) .exe suffix; prints
#the WORKING name (artifact minus -r<N>) when the name is artifact-tier, else ""
working_name_of() {
@ -1451,13 +1563,20 @@ working_name_of() {
if [[ "$w" != "$1" ]]; then printf '%s' "$w"; fi
}
case "$1" in
case "$action" in
"fetch")
runtime="$rt_default"
if [[ -n "$2" ]]; then
runtime="$2"
if [[ -n "${1:-}" ]]; then
runtime="$1"
elif [[ "$is_local" -ne 1 ]]; then
#fetch-name defaults only make sense for the platform we are standing
#on - a foreign-platform fetch (cross-build staging) names its runtime
echo "No default runtime for foreign platform '$platform' - name it explicitly:"
echo " $0 fetch <runtimename> -platform $platform"
echo " (see available names: $0 list -remote -platform $platform)"
exit 1
fi
if [[ ( "$runtime_available" -eq 1 || -n "$2" ) && "$archtail" != "other" && -n "$runtime" ]]; then
if [[ ( "$runtime_available" -eq 1 || -n "${1:-}" ) && "$archtail" != "other" && -n "$runtime" ]]; then
url="${url_kitbase}/${archtail}/${runtime}"
output="${archdir}/${runtime}"
sha1url="${url_kitbase}/${archtail}/sha1sums.txt"
@ -1547,7 +1666,7 @@ case "$1" in
fi
;;
"list")
if [[ "$2" == "-remote" ]]; then
if [[ "${1:-}" == "-remote" ]]; then
#compare local runtimes with those listed on the artifact server
#(functional parity with the powershell payload's 'list -remote')
sha1url="${url_kitbase}/${archtail}/sha1sums.txt"
@ -1620,9 +1739,12 @@ case "$1" in
fi
;;
"use")
if [[ -z "$2" ]]; then
echo "Usage: $0 use <runtimename>"
echo "Installed candidates:"
#with -platform: manage THAT platform folder's selection/materialization
#(cross-build staging - active.toml travels with the folder when deployed;
#'run' on this machine only ever consults the local platform)
if [[ -z "${1:-}" ]]; then
echo "Usage: $0 use <runtimename> ?-platform <p>?"
echo "Installed candidates ($platform):"
for f in $(list_candidates); do
echo " $f"
done
@ -1632,14 +1754,14 @@ case "$1" in
fi
exit 1
fi
case "$2" in
case "$1" in
*_BUILDCOPY|*.txt|*.toml|*.tm|*.tmp)
echo "'$2' is not a selectable runtime"
echo "'$1' is not a selectable runtime"
exit 1
;;
esac
if [[ ! -f "$archdir/$2" ]]; then
echo "No runtime named '$2' found in $archdir"
if [[ ! -f "$archdir/$1" ]]; then
echo "No runtime named '$1' found in $archdir"
echo "Installed candidates:"
for f in $(list_candidates); do
echo " $f"
@ -1650,26 +1772,35 @@ case "$1" in
#artifact into its WORKING name (name minus -r<N> - what mapvfs and
#projects reference), copies its metadata toml alongside, and selects
#the working name. Republishing artifacts never churns consumers.
working=$(working_name_of "$2")
#(chmod is a no-op when staging unix runtimes from windows filesystems -
#exec bits are restored at deploy time, e.g rsync/tar/chmod on the guest.)
working=$(working_name_of "$1")
if [[ -n "$working" ]]; then
cp -f "$archdir/$2" "$archdir/$working"
cp -f "$archdir/$1" "$archdir/$working"
chmod +x "$archdir/$working"
srctoml="$archdir/$(rootname_of "$2").toml"
srctoml="$archdir/$(rootname_of "$1").toml"
desttoml="$archdir/$(rootname_of "$working").toml"
if [[ -f "$srctoml" ]]; then
cp -f "$srctoml" "$desttoml"
echo "materialized $working from artifact $2 (metadata toml copied alongside)"
echo "materialized $working from artifact $1 (metadata toml copied alongside)"
else
echo "materialized $working from artifact $2 (no metadata toml found beside the artifact)"
echo "materialized $working from artifact $1 (no metadata toml found beside the artifact)"
fi
set_active "$working"
else
set_active "$2"
set_active "$1"
fi
;;
"run")
#resolution order: PUNK_ACTIVE_RUNTIME env override, active.toml, single
#installed candidate - otherwise error with candidates (no last-in-list guessing)
#installed candidate - otherwise error with candidates (no last-in-list guessing).
#LOCAL platform only: the -platform arg is rejected in the scan above, and a
#PUNK_RUNTIME_PLATFORM env override is likewise ignored here (foreign
#binaries are not runnable; the env override serves list/fetch/use).
if [[ "$is_local" -ne 1 ]]; then
archdir="${scriptdir}/runtime/${local_platform}"
active_file="${archdir}/active.toml"
fi
activeruntime=""
if [[ -n "$PUNK_ACTIVE_RUNTIME" ]]; then
activeruntime="$PUNK_ACTIVE_RUNTIME"
@ -1706,13 +1837,22 @@ case "$1" in
fi
activeruntime_fullpath="$archdir/$activeruntime"
#echo "using $activeruntime_fullpath"
shift
#echo "args: $@"
#(the action was already shifted off during the option scan - "$@" is
#exactly the runtime's argument list)
$activeruntime_fullpath "$@"
;;
"help")
show_help
;;
"")
#no action: short usage + pointer at the fuller help
show_usage
echo ""
echo "'$0 help' gives options, env vars and examples."
;;
*)
echo "Usage: $0 {fetch|list|use|run}"
echo "received $@"
echo "unknown action '$action'"
show_usage
exit 1
;;
esac
@ -2085,6 +2225,91 @@ function Get-PunkRuntimeCandidates {
}
return @(get-childItem -Path $archfolder -File | Where-object Name -Notlike '*_BUILDCOPY*' | Where-object {-not ($(".txt",".toml",".tm",".tmp",".log") -contains $_.Extension) } | Sort-Object Name)
}
#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 " fetch ?<name>? ?-platform <p>? download+verify a runtime from punkbin"
write-host " list ?-remote? ?-platform <p>? installed (or server) runtimes + metadata"
write-host " use <name> ?-platform <p>? select active / materialize -r<N> artifact"
write-host " run ?args...? launch the active local-platform runtime"
write-host " help full help (options, env vars, examples)"
}
function Show-PunkRuntimeHelp {
write-host "punk-runtime - manage the plain Tcl runtimes under bin/runtime/<platform>/"
write-host ""
Show-PunkRuntimeUsage
write-host ""
write-host "Actions:"
write-host " fetch ?<name>? ?-platform <p>?"
write-host " Download a runtime from the punkbin artifact server into"
write-host " bin/runtime/<p>/ with sha1 verification against the server's"
write-host " sha1sums.txt. -r<N>-named family artifacts also fetch their"
write-host " <rootname>.toml metadata record. Omitting <name> fetches the"
write-host " local platform's default runtime; a FOREIGN platform fetch"
write-host " requires an explicit <name>."
write-host " list ?-remote? ?-platform <p>?"
write-host " List installed runtimes with artifact-metadata summaries"
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 " 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"
write-host " MATERIALIZED into its WORKING name (name minus -r<N> - what"
write-host " mapvfs and projects reference), metadata toml copied alongside."
write-host " run ?args...?"
write-host " Launch the ACTIVE runtime of the LOCAL platform, passing args."
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 ""
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"
write-host " order: -platform argument > PUNK_RUNTIME_PLATFORM env var."
write-host " Foreign-platform folders serve cross-build staging and provisioning:"
write-host " active.toml travels with the folder when it is deployed to its real"
write-host " platform (unix exec bits are restored at deploy time - e.g rsync/tar/"
write-host " chmod on the receiving side)."
write-host ""
write-host "Env: PUNKBIN_URL (artifact server base url), PUNK_RUNTIME_PLATFORM,"
write-host " PUNK_ACTIVE_RUNTIME (run-time selection override)"
write-host ""
write-host "Examples:"
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"
write-host " punk-runtime.cmd fetch tclsh9.0.5-punk-r1 -platform linux-x86_64"
write-host " punk-runtime.cmd use tclsh9.0.5-punk-r1 -platform linux-x86_64"
write-host " punk-runtime.cmd run myscript.tcl arg1 arg2"
}
#platform (target) resolution for fetch/list/use: -platform arg > PUNK_RUNTIME_PLATFORM
#env > the local default. Values are punkbin/bin-runtime platform-DIR names (e.g
#win32-x86_64, linux-x86_64, macosx) - NOT zig triples (the buildsuite maps triples to
#platform dirs at build time; punk-runtime speaks only the punkbin tier). Validation is
#deliberately shape-only: the server's sha1sums/404 is the truth for what exists.
#This payload runs on windows - the local default stays win32-x86_64 (a windows-arm
#default becomes a question when punkbin carries such a folder).
$script:PunkLocalPlatform = "win32-x86_64"
function Resolve-PunkRuntimePlatform {
param([string] $requested)
$plat = $script:PunkLocalPlatform
if ($requested) {
$plat = $requested
} elseif ($env:PUNK_RUNTIME_PLATFORM) {
$plat = $env:PUNK_RUNTIME_PLATFORM
}
#-cnotmatch: platform-dir names are lowercase and the artifact-server URL path
#is case-sensitive (default -notmatch is case-insensitive and would pass typos
#like Win32-X86_64 through to a server 404); bash payload parity (=~ is
#case-sensitive there)
if ($plat -cnotmatch '^[a-z0-9][a-z0-9_-]*$') {
write-host "invalid platform name '$plat' (expected a punkbin platform-dir name such as win32-x86_64, linux-x86_64, macosx)"
exit 1
}
return $plat
}
#name minus a .exe suffix only - dotted tcl patchlevels (tclsh9.0.5-punk) make
#generic last-dot extension stripping wrong for extensionless unix names
function Get-PunkRuntimeRootName {
@ -2098,7 +2323,7 @@ function Get-PunkRuntimeRootName {
#by the buildsuite kit-family-artifacts step / fetched from punkbin). Returns a
#short "[variant=... tcl=... rN ...]" summary for list output, "" when absent.
function Get-PunkRuntimeMetadataSummary {
param([string] $archfolder, [string] $exename)
param([string] $archfolder, [string] $exename, [string] $expectedplatform = "")
$tomlfile = Join-Path -Path $archfolder -ChildPath ((Get-PunkRuntimeRootName $exename) + ".toml")
if (-not (Test-Path -Path $tomlfile -PathType Leaf)) {
return ""
@ -2124,6 +2349,11 @@ function Get-PunkRuntimeMetadataSummary {
}
#a materialized working copy records which immutable artifact it came from
if ($fields.ContainsKey('name') -and $fields['name'] -ne $exename) { $parts += "from=$($fields['name'])" }
#integrity flag: a runtime filed under a platform folder its metadata says it
#was not built for (cross-platform fetch/staging misfiling)
if ($expectedplatform -ne "" -and $fields.ContainsKey('target') -and $fields['target'] -ne $expectedplatform) {
$parts += "!TARGET-MISMATCH:$($fields['target'])"
}
if ($parts.Count -eq 0) {
return ""
}
@ -2147,8 +2377,19 @@ function psmain {
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'remote', [switch], $attributeCollection
)
#-platform (G-105 cross-build staging): punkbin platform-dir name to list for
$platformAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "listruntime"
Mandatory = $false
}
$platformAttributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$platformAttributeCollection.Add($platformAttribute)
$dynParam2 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'platform', [string], $platformAttributeCollection
)
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('remote', $dynParam1)
$paramDictionary.Add('platform', $dynParam2)
return $paramDictionary
} elseif ($action -eq 'fetch' -or $action -eq 'use') {
#GetDynamicParamDictionary ParameterDefinitions
@ -2164,8 +2405,21 @@ function psmain {
'runtime', [string], $attributeCollection
)
#-platform (G-105 cross-build staging): punkbin platform-dir name to fetch
#into / select within (default: the local platform)
$platformAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "fetchruntime"
Mandatory = $false
}
$platformAttributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$platformAttributeCollection.Add($platformAttribute)
$dynParam2 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'platform', [string], $platformAttributeCollection
)
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('runtime', $dynParam1)
$paramDictionary.Add('platform', $dynParam2)
return $paramDictionary
} elseif ($action -eq 'run') {
#GetDynamicParamDictionary ParameterDefinitions
@ -2210,7 +2464,7 @@ function psmain {
'action' {
write-host "got action " $PSBoundParameters.action
Set-Variable -Name $_ -Value $PSBoundParameters."$_"
$known_actions = @("fetch", "list", "use", "run")
$known_actions = @("fetch", "list", "use", "run", "help")
if (-not($known_actions -contains $action)) {
write-host "action '$action' not understood. Known_actions: $known_actions"
exit 1
@ -2242,16 +2496,25 @@ function psmain {
}
switch ($action) {
'fetch' {
$arch = "win32-x86_64"
$arch = Resolve-PunkRuntimePlatform $PSBoundParameters["platform"]
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$archurl = "$artifacturl/$arch"
$sha1url = "$archurl/sha1sums.txt"
$runtime = "tclsh902z.exe"
foreach ($boundparam in $PSBoundParameters.Keys) {
write-host "fetchopt: $boundparam $($PSBoundParameters[$boundparam])"
}
$runtime = ""
if ( $PSBoundParameters["runtime"].Length ) {
$runtime = $PSBoundParameters["runtime"]
} elseif ($arch -eq $script:PunkLocalPlatform) {
$runtime = "tclsh902z.exe"
} else {
#fetch-name defaults only make sense for the platform we are standing
#on - a foreign-platform fetch (cross-build staging) names its runtime
write-host "No default runtime for foreign platform '$arch' - name it explicitly:"
write-host " punk-runtime.cmd fetch <runtimename> -platform $arch"
write-host " (see available names: punk-runtime.cmd list -remote -platform $arch)"
exit 1
}
$fileurl = "$archurl/$runtime"
@ -2363,8 +2626,11 @@ function psmain {
}
}
'use' {
#select the active runtime for subsequent 'run' calls
$arch = "win32-x86_64"
#select the active runtime for subsequent 'run' calls. With -platform:
#manage THAT platform folder's selection/materialization (cross-build
#staging - the active.toml travels with the folder when deployed; 'run'
#on this machine only ever consults the local platform).
$arch = Resolve-PunkRuntimePlatform $PSBoundParameters["platform"]
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$candidates = Get-PunkRuntimeCandidates $archfolder
$rtname = ""
@ -2372,8 +2638,8 @@ function psmain {
$rtname = $PSBoundParameters["runtime"]
}
if ($rtname -eq "") {
write-host "Usage: punk-runtime.cmd use <runtimename>"
write-host "Installed candidates:"
write-host "Usage: punk-runtime.cmd use <runtimename> ?-platform <p>?"
write-host "Installed candidates ($arch):"
foreach ($f in $candidates) {
write-host " $($f.Name)"
}
@ -2417,8 +2683,16 @@ function psmain {
'run' {
#launch the active runtime, passing arguments.
#resolution order: PUNK_ACTIVE_RUNTIME env override, active.toml, single
#installed candidate - otherwise error with candidates (no last-in-list guessing)
$arch = "win32-x86_64"
#installed candidate - otherwise error with candidates (no last-in-list guessing).
#LOCAL PLATFORM ONLY - a foreign platform's binaries are not runnable here.
#Only a LEADING -platform is rejected: everything after 'run' belongs to
#the runtime, so a later arg spelled -platform must pass through untouched.
if ($PSBoundParameters.opts.Length -gt 0 -and $PSBoundParameters.opts[0] -eq '-platform') {
write-host "'run' launches the LOCAL platform's active runtime - it takes no -platform option"
write-host "(foreign-platform folders are cross-build staging; deploy them to their platform to run)"
exit 1
}
$arch = $script:PunkLocalPlatform
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
if (-not(Test-Path -Path $archfolder -PathType Container)) {
write-host "No runtimes seem to be installed for $arch`nPlease use 'punk-runtime.cmd fetch' to install"
@ -2494,8 +2768,8 @@ function psmain {
}
}
'list' {
#todo - option to list for other os-arch
$arch = 'win32-x86_64'
#-platform lists another platform's folder/server dir (cross-build staging)
$arch = Resolve-PunkRuntimePlatform $PSBoundParameters["platform"]
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt"
$archurl = "$artifacturl/$arch"
@ -2595,7 +2869,7 @@ function psmain {
write-host "$(${dircontents}.count) runtime(s) in $archfolder"
Write-host "-----------------------------------------------------------------------"
foreach ($f in $dircontents) {
$meta = Get-PunkRuntimeMetadataSummary $archfolder $f.Name
$meta = Get-PunkRuntimeMetadataSummary $archfolder $f.Name $arch
$lhs = "$($f.Name)".PadRight(35, ' ')
if ($f.Name -eq $activename) {
write-host "* $lhs (active) $meta"
@ -2616,13 +2890,15 @@ function psmain {
}
}
}
default {
$actions = @("fetch", "list", "use", "run")
write-host "Available actions: $actions"
write-host "received"
foreach ($boundparam in $PSBoundParameters.opts) {
write-host $boundparam
'help' {
Show-PunkRuntimeHelp
}
default {
#no action given (unknown actions were already rejected in the
#process block): show the short usage and point at 'help'
Show-PunkRuntimeUsage
write-host ""
write-host "'punk-runtime.cmd help' gives options, env vars and examples."
}
}

22
goals/G-103-runtime-kit-family.md

@ -372,6 +372,28 @@ punk family runtime and reported 9.0.5 / piperepl machinery present /
tcl_library=//zipfs:/app/tcl_library. Project 0.17.7 (patch bump + changelog:
punk-runtime is shipped product surface).
### 2026-07-22 increment: punk-runtime cross-platform surface + help (user-directed; G-105 groundwork)
User-approved argument surface for future cross-builds (design discussion
2026-07-22): fetch/list/use accept `-platform <p>` (punkbin platform-DIR names,
never zig triples; resolution -platform arg > PUNK_RUNTIME_PLATFORM env > local
default; shape-only lowercase validation - the server is the truth). Foreign
fetch requires an explicit runtime name (no foreign defaults); `use -platform`
manages that folder's active.toml/materialization (the marker travels with the
folder at deploy time - the provisioning story; exec bits restored on the
receiving side); `list` gains a !TARGET-MISMATCH integrity flag when a
runtime's metadata target disagrees with its folder; `run` is local-only
(rejects a leading -platform, ignores the env override, later args pass to the
runtime untouched). Plus a `help` action (full operator reference) and a real
usage block on no-args. Bash FreeBSD platform dir aligned to punkbin's actual
freebsd-x86_64 (was freebsd-amd64 - a G-105 naming-alignment item found during
the design pass). Parity bug caught in verification: powershell -notmatch is
case-insensitive - validation uses -cnotmatch (URL paths are case-sensitive).
Verified on both payloads directly AND through the rewrapped polyglot
(noargs/help/list/foreign-use-materialize/mismatch-flag/foreign-fetch-refusal/
run-guard/env-override incl run's immunity to it); roundtrip pin PASS; layout
copy + .ps1 twin refreshed; project 0.17.9.
Remaining for acceptance:
- exercise the new mapvfs entries with an actual kit wrap (punk9_beta /

10
goals/G-105-buildsuite-cross-target.md

@ -63,3 +63,13 @@ dimension), G-102 (achieved 2026-07-21 - driver shape settled; target becomes a
is fully characterized (confirmed flaw, both direct-kit and modpod-.tm binary
loads - G-103/G-066 Notes); the linux expectation stays no-accumulation
(unlink-while-mapped) but is UNVERIFIED until a runtime exists.
- 2026-07-22: punk-runtime grew the cross-platform staging surface this goal
will consume (user-approved; details in G-103 Progress 2026-07-22):
fetch/list/use -platform <punkbin platform-dir name> with local-platform
default (PUNK_RUNTIME_PLATFORM env override), foreign fetch name-required,
list !TARGET-MISMATCH integrity flag from the G-103 metadata target field,
run local-only. Platform-dir naming alignment progress: bash payload's
FreeBSD dir aligned to punkbin's actual freebsd-x86_64 (was freebsd-amd64).
Still open for this goal's alignment item: the zig-triple <-> platform-dir
mapping itself, openbsd-amd64 (payload) vs the x86_64 convention, and a
windows-arm default for the ps1 payload once punkbin carries such a folder.

2
punkproject.toml

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

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

@ -1299,55 +1299,57 @@ arch=$(uname -m) #machine/architecture
plat=$(uname -s) #platform/system
#even though most of the platform prongs are very similar,
#we keep the code separate so it can be tweaked easily for unexpected differences
#each prong sets archdir (local folder) and, where a runtime is published for the
#platform, rt_default (default runtime name). archtail (server folder) is derived
#from archdir below.
#each prong sets local_platform (the punkbin/bin-runtime platform-DIR name) and,
#where a runtime is published for the platform, rt_default (default runtime name).
if [[ "$plat" = "Linux"* ]]; then
if [[ "$arch" = "x86_64"* ]]; then
archdir="${scriptdir}/runtime/linux-x86_64"
local_platform="linux-x86_64"
rt_default="tclkit-902-Linux64-intel-dyn"
runtime_available=1
elif [[ "$arch" = "arm"* ]]; then
archdir="${scriptdir}/runtime/linux-arm"
local_platform="linux-arm"
rt_default="tclkit-902-Linux64-arm-dyn"
runtime_available=1
else
archdir="${scriptdir}/runtime/linux-$arch"
local_platform="linux-$arch"
fi
os="linux"
elif [[ "$plat" = "Darwin"* ]]; then
os="macosx"
#assumed to be Mach-O 'universal binaries' for both x86-64 and arm? - REVIEW
archdir="${scriptdir}/runtime/macosx"
local_platform="macosx"
rt_default="tclkit-902-Darwin64-dyn"
runtime_available=1
elif [[ "$plat" = "FreeBSD"* ]]; then
archdir="${scriptdir}/runtime/freebsd-amd64"
#aligned 2026-07-22 to the punkbin repo's actual folder name (freebsd-x86_64;
#this payload previously said freebsd-amd64 - the G-105 platform-dir naming
#alignment item)
local_platform="freebsd-x86_64"
os="freebsd"
elif [[ "$plat" == "DragonFly"* ]]; then
archdir="${scriptdir}/runtime/dragonflybsd-$arch"
local_platform="dragonflybsd-$arch"
os="dragonflybsd"
elif [[ "$plat" == "NetBSD"* ]]; then
archdir="${scriptdir}/runtime/netbsd-$arch"
local_platform="netbsd-$arch"
os="netbsd"
elif [[ "$plat" == "OpenBSD"* ]]; then
archdir="${scriptdir}/runtime/openbsd-amd64"
local_platform="openbsd-amd64"
os="openbsd"
elif [[ "$plat" == "MINGW32"* ]]; then
#REVIEW
os="win32"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
elif [[ "$plat" == "MINGW64"* ]]; then
#REVIEW
os="win32"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
elif [[ "$plat" == "CYGWIN_NT"* ]]; then
os="win32"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
elif [[ "$plat" == "MSYS_NT"* ]]; then
@ -1360,14 +1362,61 @@ elif [[ "$plat" == "MSYS_NT"* ]]; then
#"c:/windows/system32/" is quite likely in the path ahead of msys,git etc.
#This breaks calls to various unix utils such as sed etc (wsl related?)
export PATH="$shellfolder${PATH:+:${PATH}}"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
else
archdir="${scriptdir}/runtime/other"
local_platform="other"
os="other"
fi
archtail="${archdir##*/}" #server folder name e.g linux-x86_64
#-- platform resolution (G-105 cross-build staging) ---------------------------
#The prongs above detect the LOCAL platform. fetch/list/use accept
#'-platform <p>' to aim at another punkbin platform-dir (cross-build staging /
#provisioning); resolution: -platform arg > PUNK_RUNTIME_PLATFORM env > local.
#Values are punkbin platform-dir names (e.g win32-x86_64, linux-x86_64, macosx)
#- NOT zig triples (the buildsuite maps triples to platform dirs at build time).
#Validation is shape-only: the server's sha1sums/404 is the truth for what
#exists. 'run' is LOCAL ONLY (foreign binaries are not runnable here) - only a
#LEADING -platform is rejected there; later args belong to the launched runtime.
action="${1:-}"
[[ $# -gt 0 ]] && shift
platform_opt=""
case "$action" in
fetch|list|use)
newargs=()
while [[ $# -gt 0 ]]; do
if [[ "$1" == "-platform" ]]; then
shift
if [[ $# -eq 0 ]]; then
echo "option -platform requires a value (a punkbin platform-dir name, e.g linux-x86_64)"
exit 1
fi
platform_opt="$1"
else
newargs+=("$1")
fi
shift
done
set -- ${newargs[@]+"${newargs[@]}"}
;;
run)
if [[ "${1:-}" == "-platform" ]]; then
echo "'run' launches the LOCAL platform's active runtime - it takes no -platform option"
echo "(foreign-platform folders are cross-build staging; deploy them to their platform to run)"
exit 1
fi
;;
esac
platform="${platform_opt:-${PUNK_RUNTIME_PLATFORM:-$local_platform}}"
if ! [[ "$platform" =~ ^[a-z0-9][a-z0-9_-]*$ ]]; then
echo "invalid platform name '$platform' (expected a punkbin platform-dir name such as win32-x86_64, linux-x86_64, macosx)"
exit 1
fi
is_local=0
[[ "$platform" == "$local_platform" ]] && is_local=1
archdir="${scriptdir}/runtime/${platform}"
archtail="$platform" #server folder name e.g linux-x86_64
active_file="${archdir}/active.toml"
#sha1 of a file - tool varies by platform (sha1sum: linux/coreutils, shasum: macosx,
@ -1425,7 +1474,7 @@ rootname_of() {
#by the buildsuite kit-family-artifacts step / fetched from punkbin). Prints a
#short "[variant=... tcl=... rN ...]" summary for list output, "" when absent.
metadata_summary() {
local exename="$1" tomlfile parts variant tclpatch revision piperepl artname
local exename="$1" tomlfile parts variant tclpatch revision piperepl artname target
tomlfile="$archdir/$(rootname_of "$exename").toml"
[[ -f "$tomlfile" ]] || return 0
variant=$(sed -n 's/^[[:space:]]*variant[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" | head -n 1)
@ -1433,6 +1482,7 @@ metadata_summary() {
revision=$(sed -n 's/^[[:space:]]*revision[[:space:]]*=[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$tomlfile" | head -n 1)
piperepl=$(sed -n 's/^[[:space:]]*piperepl[[:space:]]*=[[:space:]]*\(true\|false\).*/\1/p' "$tomlfile" | head -n 1)
artname=$(sed -n 's/^[[:space:]]*name[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" | head -n 1)
target=$(sed -n 's/^[[:space:]]*target[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" | head -n 1)
parts=""
[[ -n "$variant" ]] && parts="$parts variant=$variant"
[[ -n "$tclpatch" ]] && parts="$parts tcl=$tclpatch"
@ -1441,8 +1491,70 @@ metadata_summary() {
elif [[ "$piperepl" == "false" ]]; then parts="$parts piperepl=off"; fi
#a materialized working copy records which immutable artifact it came from
[[ -n "$artname" && "$artname" != "$exename" ]] && parts="$parts from=$artname"
#integrity flag: a runtime filed under a platform folder its metadata says it
#was not built for (cross-platform fetch/staging misfiling)
[[ -n "$target" && "$target" != "$archtail" ]] && parts="$parts !TARGET-MISMATCH:$target"
[[ -n "$parts" ]] && printf '[%s]' "${parts# }"
}
#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 " fetch ?<name>? ?-platform <p>? download+verify a runtime from punkbin"
echo " list ?-remote? ?-platform <p>? installed (or server) runtimes + metadata"
echo " use <name> ?-platform <p>? select active / materialize -r<N> artifact"
echo " run ?args...? launch the active local-platform runtime"
echo " help full help (options, env vars, examples)"
}
show_help() {
echo "punk-runtime - manage the plain Tcl runtimes under bin/runtime/<platform>/"
echo ""
show_usage
echo ""
echo "Actions:"
echo " fetch ?<name>? ?-platform <p>?"
echo " Download a runtime from the punkbin artifact server into"
echo " bin/runtime/<p>/ with sha1 verification against the server's"
echo " sha1sums.txt. -r<N>-named family artifacts also fetch their"
echo " <rootname>.toml metadata record. Omitting <name> fetches the"
echo " local platform's default runtime; a FOREIGN platform fetch"
echo " requires an explicit <name>."
echo " list ?-remote? ?-platform <p>?"
echo " List installed runtimes with artifact-metadata summaries"
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 " 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"
echo " MATERIALIZED into its WORKING name (name minus -r<N> - what"
echo " mapvfs and projects reference), metadata toml copied alongside."
echo " run ?args...?"
echo " Launch the ACTIVE runtime of the LOCAL platform, passing args."
echo " Resolution: PUNK_ACTIVE_RUNTIME env > active.toml > sole"
echo " installed candidate. Takes no -platform (foreign binaries are"
echo " not runnable here)."
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"
echo " order: -platform argument > PUNK_RUNTIME_PLATFORM env var."
echo " Foreign-platform folders serve cross-build staging and provisioning:"
echo " active.toml travels with the folder when it is deployed to its real"
echo " platform (unix exec bits are restored at deploy time - e.g rsync/tar/"
echo " chmod on the receiving side)."
echo ""
echo "Env: PUNKBIN_URL (artifact server base url), PUNK_RUNTIME_PLATFORM,"
echo " PUNK_ACTIVE_RUNTIME (run-time selection override)"
echo ""
echo "Examples:"
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"
echo " $0 fetch tclsh9.0.5-punk-r1 -platform linux-x86_64"
echo " $0 use tclsh9.0.5-punk-r1 -platform linux-x86_64"
echo " $0 run myscript.tcl arg1 arg2"
}
#G-103 artifact-tier names carry -r<N> before the (optional) .exe suffix; prints
#the WORKING name (artifact minus -r<N>) when the name is artifact-tier, else ""
working_name_of() {
@ -1451,13 +1563,20 @@ working_name_of() {
if [[ "$w" != "$1" ]]; then printf '%s' "$w"; fi
}
case "$1" in
case "$action" in
"fetch")
runtime="$rt_default"
if [[ -n "$2" ]]; then
runtime="$2"
if [[ -n "${1:-}" ]]; then
runtime="$1"
elif [[ "$is_local" -ne 1 ]]; then
#fetch-name defaults only make sense for the platform we are standing
#on - a foreign-platform fetch (cross-build staging) names its runtime
echo "No default runtime for foreign platform '$platform' - name it explicitly:"
echo " $0 fetch <runtimename> -platform $platform"
echo " (see available names: $0 list -remote -platform $platform)"
exit 1
fi
if [[ ( "$runtime_available" -eq 1 || -n "$2" ) && "$archtail" != "other" && -n "$runtime" ]]; then
if [[ ( "$runtime_available" -eq 1 || -n "${1:-}" ) && "$archtail" != "other" && -n "$runtime" ]]; then
url="${url_kitbase}/${archtail}/${runtime}"
output="${archdir}/${runtime}"
sha1url="${url_kitbase}/${archtail}/sha1sums.txt"
@ -1547,7 +1666,7 @@ case "$1" in
fi
;;
"list")
if [[ "$2" == "-remote" ]]; then
if [[ "${1:-}" == "-remote" ]]; then
#compare local runtimes with those listed on the artifact server
#(functional parity with the powershell payload's 'list -remote')
sha1url="${url_kitbase}/${archtail}/sha1sums.txt"
@ -1620,9 +1739,12 @@ case "$1" in
fi
;;
"use")
if [[ -z "$2" ]]; then
echo "Usage: $0 use <runtimename>"
echo "Installed candidates:"
#with -platform: manage THAT platform folder's selection/materialization
#(cross-build staging - active.toml travels with the folder when deployed;
#'run' on this machine only ever consults the local platform)
if [[ -z "${1:-}" ]]; then
echo "Usage: $0 use <runtimename> ?-platform <p>?"
echo "Installed candidates ($platform):"
for f in $(list_candidates); do
echo " $f"
done
@ -1632,14 +1754,14 @@ case "$1" in
fi
exit 1
fi
case "$2" in
case "$1" in
*_BUILDCOPY|*.txt|*.toml|*.tm|*.tmp)
echo "'$2' is not a selectable runtime"
echo "'$1' is not a selectable runtime"
exit 1
;;
esac
if [[ ! -f "$archdir/$2" ]]; then
echo "No runtime named '$2' found in $archdir"
if [[ ! -f "$archdir/$1" ]]; then
echo "No runtime named '$1' found in $archdir"
echo "Installed candidates:"
for f in $(list_candidates); do
echo " $f"
@ -1650,26 +1772,35 @@ case "$1" in
#artifact into its WORKING name (name minus -r<N> - what mapvfs and
#projects reference), copies its metadata toml alongside, and selects
#the working name. Republishing artifacts never churns consumers.
working=$(working_name_of "$2")
#(chmod is a no-op when staging unix runtimes from windows filesystems -
#exec bits are restored at deploy time, e.g rsync/tar/chmod on the guest.)
working=$(working_name_of "$1")
if [[ -n "$working" ]]; then
cp -f "$archdir/$2" "$archdir/$working"
cp -f "$archdir/$1" "$archdir/$working"
chmod +x "$archdir/$working"
srctoml="$archdir/$(rootname_of "$2").toml"
srctoml="$archdir/$(rootname_of "$1").toml"
desttoml="$archdir/$(rootname_of "$working").toml"
if [[ -f "$srctoml" ]]; then
cp -f "$srctoml" "$desttoml"
echo "materialized $working from artifact $2 (metadata toml copied alongside)"
echo "materialized $working from artifact $1 (metadata toml copied alongside)"
else
echo "materialized $working from artifact $2 (no metadata toml found beside the artifact)"
echo "materialized $working from artifact $1 (no metadata toml found beside the artifact)"
fi
set_active "$working"
else
set_active "$2"
set_active "$1"
fi
;;
"run")
#resolution order: PUNK_ACTIVE_RUNTIME env override, active.toml, single
#installed candidate - otherwise error with candidates (no last-in-list guessing)
#installed candidate - otherwise error with candidates (no last-in-list guessing).
#LOCAL platform only: the -platform arg is rejected in the scan above, and a
#PUNK_RUNTIME_PLATFORM env override is likewise ignored here (foreign
#binaries are not runnable; the env override serves list/fetch/use).
if [[ "$is_local" -ne 1 ]]; then
archdir="${scriptdir}/runtime/${local_platform}"
active_file="${archdir}/active.toml"
fi
activeruntime=""
if [[ -n "$PUNK_ACTIVE_RUNTIME" ]]; then
activeruntime="$PUNK_ACTIVE_RUNTIME"
@ -1706,13 +1837,22 @@ case "$1" in
fi
activeruntime_fullpath="$archdir/$activeruntime"
#echo "using $activeruntime_fullpath"
shift
#echo "args: $@"
#(the action was already shifted off during the option scan - "$@" is
#exactly the runtime's argument list)
$activeruntime_fullpath "$@"
;;
"help")
show_help
;;
"")
#no action: short usage + pointer at the fuller help
show_usage
echo ""
echo "'$0 help' gives options, env vars and examples."
;;
*)
echo "Usage: $0 {fetch|list|use|run}"
echo "received $@"
echo "unknown action '$action'"
show_usage
exit 1
;;
esac
@ -2085,6 +2225,91 @@ function Get-PunkRuntimeCandidates {
}
return @(get-childItem -Path $archfolder -File | Where-object Name -Notlike '*_BUILDCOPY*' | Where-object {-not ($(".txt",".toml",".tm",".tmp",".log") -contains $_.Extension) } | Sort-Object Name)
}
#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 " fetch ?<name>? ?-platform <p>? download+verify a runtime from punkbin"
write-host " list ?-remote? ?-platform <p>? installed (or server) runtimes + metadata"
write-host " use <name> ?-platform <p>? select active / materialize -r<N> artifact"
write-host " run ?args...? launch the active local-platform runtime"
write-host " help full help (options, env vars, examples)"
}
function Show-PunkRuntimeHelp {
write-host "punk-runtime - manage the plain Tcl runtimes under bin/runtime/<platform>/"
write-host ""
Show-PunkRuntimeUsage
write-host ""
write-host "Actions:"
write-host " fetch ?<name>? ?-platform <p>?"
write-host " Download a runtime from the punkbin artifact server into"
write-host " bin/runtime/<p>/ with sha1 verification against the server's"
write-host " sha1sums.txt. -r<N>-named family artifacts also fetch their"
write-host " <rootname>.toml metadata record. Omitting <name> fetches the"
write-host " local platform's default runtime; a FOREIGN platform fetch"
write-host " requires an explicit <name>."
write-host " list ?-remote? ?-platform <p>?"
write-host " List installed runtimes with artifact-metadata summaries"
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 " 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"
write-host " MATERIALIZED into its WORKING name (name minus -r<N> - what"
write-host " mapvfs and projects reference), metadata toml copied alongside."
write-host " run ?args...?"
write-host " Launch the ACTIVE runtime of the LOCAL platform, passing args."
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 ""
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"
write-host " order: -platform argument > PUNK_RUNTIME_PLATFORM env var."
write-host " Foreign-platform folders serve cross-build staging and provisioning:"
write-host " active.toml travels with the folder when it is deployed to its real"
write-host " platform (unix exec bits are restored at deploy time - e.g rsync/tar/"
write-host " chmod on the receiving side)."
write-host ""
write-host "Env: PUNKBIN_URL (artifact server base url), PUNK_RUNTIME_PLATFORM,"
write-host " PUNK_ACTIVE_RUNTIME (run-time selection override)"
write-host ""
write-host "Examples:"
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"
write-host " punk-runtime.cmd fetch tclsh9.0.5-punk-r1 -platform linux-x86_64"
write-host " punk-runtime.cmd use tclsh9.0.5-punk-r1 -platform linux-x86_64"
write-host " punk-runtime.cmd run myscript.tcl arg1 arg2"
}
#platform (target) resolution for fetch/list/use: -platform arg > PUNK_RUNTIME_PLATFORM
#env > the local default. Values are punkbin/bin-runtime platform-DIR names (e.g
#win32-x86_64, linux-x86_64, macosx) - NOT zig triples (the buildsuite maps triples to
#platform dirs at build time; punk-runtime speaks only the punkbin tier). Validation is
#deliberately shape-only: the server's sha1sums/404 is the truth for what exists.
#This payload runs on windows - the local default stays win32-x86_64 (a windows-arm
#default becomes a question when punkbin carries such a folder).
$script:PunkLocalPlatform = "win32-x86_64"
function Resolve-PunkRuntimePlatform {
param([string] $requested)
$plat = $script:PunkLocalPlatform
if ($requested) {
$plat = $requested
} elseif ($env:PUNK_RUNTIME_PLATFORM) {
$plat = $env:PUNK_RUNTIME_PLATFORM
}
#-cnotmatch: platform-dir names are lowercase and the artifact-server URL path
#is case-sensitive (default -notmatch is case-insensitive and would pass typos
#like Win32-X86_64 through to a server 404); bash payload parity (=~ is
#case-sensitive there)
if ($plat -cnotmatch '^[a-z0-9][a-z0-9_-]*$') {
write-host "invalid platform name '$plat' (expected a punkbin platform-dir name such as win32-x86_64, linux-x86_64, macosx)"
exit 1
}
return $plat
}
#name minus a .exe suffix only - dotted tcl patchlevels (tclsh9.0.5-punk) make
#generic last-dot extension stripping wrong for extensionless unix names
function Get-PunkRuntimeRootName {
@ -2098,7 +2323,7 @@ function Get-PunkRuntimeRootName {
#by the buildsuite kit-family-artifacts step / fetched from punkbin). Returns a
#short "[variant=... tcl=... rN ...]" summary for list output, "" when absent.
function Get-PunkRuntimeMetadataSummary {
param([string] $archfolder, [string] $exename)
param([string] $archfolder, [string] $exename, [string] $expectedplatform = "")
$tomlfile = Join-Path -Path $archfolder -ChildPath ((Get-PunkRuntimeRootName $exename) + ".toml")
if (-not (Test-Path -Path $tomlfile -PathType Leaf)) {
return ""
@ -2124,6 +2349,11 @@ function Get-PunkRuntimeMetadataSummary {
}
#a materialized working copy records which immutable artifact it came from
if ($fields.ContainsKey('name') -and $fields['name'] -ne $exename) { $parts += "from=$($fields['name'])" }
#integrity flag: a runtime filed under a platform folder its metadata says it
#was not built for (cross-platform fetch/staging misfiling)
if ($expectedplatform -ne "" -and $fields.ContainsKey('target') -and $fields['target'] -ne $expectedplatform) {
$parts += "!TARGET-MISMATCH:$($fields['target'])"
}
if ($parts.Count -eq 0) {
return ""
}
@ -2147,8 +2377,19 @@ function psmain {
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'remote', [switch], $attributeCollection
)
#-platform (G-105 cross-build staging): punkbin platform-dir name to list for
$platformAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "listruntime"
Mandatory = $false
}
$platformAttributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$platformAttributeCollection.Add($platformAttribute)
$dynParam2 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'platform', [string], $platformAttributeCollection
)
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('remote', $dynParam1)
$paramDictionary.Add('platform', $dynParam2)
return $paramDictionary
} elseif ($action -eq 'fetch' -or $action -eq 'use') {
#GetDynamicParamDictionary ParameterDefinitions
@ -2164,8 +2405,21 @@ function psmain {
'runtime', [string], $attributeCollection
)
#-platform (G-105 cross-build staging): punkbin platform-dir name to fetch
#into / select within (default: the local platform)
$platformAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "fetchruntime"
Mandatory = $false
}
$platformAttributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$platformAttributeCollection.Add($platformAttribute)
$dynParam2 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'platform', [string], $platformAttributeCollection
)
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('runtime', $dynParam1)
$paramDictionary.Add('platform', $dynParam2)
return $paramDictionary
} elseif ($action -eq 'run') {
#GetDynamicParamDictionary ParameterDefinitions
@ -2210,7 +2464,7 @@ function psmain {
'action' {
write-host "got action " $PSBoundParameters.action
Set-Variable -Name $_ -Value $PSBoundParameters."$_"
$known_actions = @("fetch", "list", "use", "run")
$known_actions = @("fetch", "list", "use", "run", "help")
if (-not($known_actions -contains $action)) {
write-host "action '$action' not understood. Known_actions: $known_actions"
exit 1
@ -2242,16 +2496,25 @@ function psmain {
}
switch ($action) {
'fetch' {
$arch = "win32-x86_64"
$arch = Resolve-PunkRuntimePlatform $PSBoundParameters["platform"]
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$archurl = "$artifacturl/$arch"
$sha1url = "$archurl/sha1sums.txt"
$runtime = "tclsh902z.exe"
foreach ($boundparam in $PSBoundParameters.Keys) {
write-host "fetchopt: $boundparam $($PSBoundParameters[$boundparam])"
}
$runtime = ""
if ( $PSBoundParameters["runtime"].Length ) {
$runtime = $PSBoundParameters["runtime"]
} elseif ($arch -eq $script:PunkLocalPlatform) {
$runtime = "tclsh902z.exe"
} else {
#fetch-name defaults only make sense for the platform we are standing
#on - a foreign-platform fetch (cross-build staging) names its runtime
write-host "No default runtime for foreign platform '$arch' - name it explicitly:"
write-host " punk-runtime.cmd fetch <runtimename> -platform $arch"
write-host " (see available names: punk-runtime.cmd list -remote -platform $arch)"
exit 1
}
$fileurl = "$archurl/$runtime"
@ -2363,8 +2626,11 @@ function psmain {
}
}
'use' {
#select the active runtime for subsequent 'run' calls
$arch = "win32-x86_64"
#select the active runtime for subsequent 'run' calls. With -platform:
#manage THAT platform folder's selection/materialization (cross-build
#staging - the active.toml travels with the folder when deployed; 'run'
#on this machine only ever consults the local platform).
$arch = Resolve-PunkRuntimePlatform $PSBoundParameters["platform"]
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$candidates = Get-PunkRuntimeCandidates $archfolder
$rtname = ""
@ -2372,8 +2638,8 @@ function psmain {
$rtname = $PSBoundParameters["runtime"]
}
if ($rtname -eq "") {
write-host "Usage: punk-runtime.cmd use <runtimename>"
write-host "Installed candidates:"
write-host "Usage: punk-runtime.cmd use <runtimename> ?-platform <p>?"
write-host "Installed candidates ($arch):"
foreach ($f in $candidates) {
write-host " $($f.Name)"
}
@ -2417,8 +2683,16 @@ function psmain {
'run' {
#launch the active runtime, passing arguments.
#resolution order: PUNK_ACTIVE_RUNTIME env override, active.toml, single
#installed candidate - otherwise error with candidates (no last-in-list guessing)
$arch = "win32-x86_64"
#installed candidate - otherwise error with candidates (no last-in-list guessing).
#LOCAL PLATFORM ONLY - a foreign platform's binaries are not runnable here.
#Only a LEADING -platform is rejected: everything after 'run' belongs to
#the runtime, so a later arg spelled -platform must pass through untouched.
if ($PSBoundParameters.opts.Length -gt 0 -and $PSBoundParameters.opts[0] -eq '-platform') {
write-host "'run' launches the LOCAL platform's active runtime - it takes no -platform option"
write-host "(foreign-platform folders are cross-build staging; deploy them to their platform to run)"
exit 1
}
$arch = $script:PunkLocalPlatform
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
if (-not(Test-Path -Path $archfolder -PathType Container)) {
write-host "No runtimes seem to be installed for $arch`nPlease use 'punk-runtime.cmd fetch' to install"
@ -2494,8 +2768,8 @@ function psmain {
}
}
'list' {
#todo - option to list for other os-arch
$arch = 'win32-x86_64'
#-platform lists another platform's folder/server dir (cross-build staging)
$arch = Resolve-PunkRuntimePlatform $PSBoundParameters["platform"]
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt"
$archurl = "$artifacturl/$arch"
@ -2595,7 +2869,7 @@ function psmain {
write-host "$(${dircontents}.count) runtime(s) in $archfolder"
Write-host "-----------------------------------------------------------------------"
foreach ($f in $dircontents) {
$meta = Get-PunkRuntimeMetadataSummary $archfolder $f.Name
$meta = Get-PunkRuntimeMetadataSummary $archfolder $f.Name $arch
$lhs = "$($f.Name)".PadRight(35, ' ')
if ($f.Name -eq $activename) {
write-host "* $lhs (active) $meta"
@ -2616,13 +2890,15 @@ function psmain {
}
}
}
default {
$actions = @("fetch", "list", "use", "run")
write-host "Available actions: $actions"
write-host "received"
foreach ($boundparam in $PSBoundParameters.opts) {
write-host $boundparam
'help' {
Show-PunkRuntimeHelp
}
default {
#no action given (unknown actions were already rejected in the
#process block): show the short usage and point at 'help'
Show-PunkRuntimeUsage
write-host ""
write-host "'punk-runtime.cmd help' gives options, env vars and examples."
}
}

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

@ -19,55 +19,57 @@ arch=$(uname -m) #machine/architecture
plat=$(uname -s) #platform/system
#even though most of the platform prongs are very similar,
#we keep the code separate so it can be tweaked easily for unexpected differences
#each prong sets archdir (local folder) and, where a runtime is published for the
#platform, rt_default (default runtime name). archtail (server folder) is derived
#from archdir below.
#each prong sets local_platform (the punkbin/bin-runtime platform-DIR name) and,
#where a runtime is published for the platform, rt_default (default runtime name).
if [[ "$plat" = "Linux"* ]]; then
if [[ "$arch" = "x86_64"* ]]; then
archdir="${scriptdir}/runtime/linux-x86_64"
local_platform="linux-x86_64"
rt_default="tclkit-902-Linux64-intel-dyn"
runtime_available=1
elif [[ "$arch" = "arm"* ]]; then
archdir="${scriptdir}/runtime/linux-arm"
local_platform="linux-arm"
rt_default="tclkit-902-Linux64-arm-dyn"
runtime_available=1
else
archdir="${scriptdir}/runtime/linux-$arch"
local_platform="linux-$arch"
fi
os="linux"
elif [[ "$plat" = "Darwin"* ]]; then
os="macosx"
#assumed to be Mach-O 'universal binaries' for both x86-64 and arm? - REVIEW
archdir="${scriptdir}/runtime/macosx"
local_platform="macosx"
rt_default="tclkit-902-Darwin64-dyn"
runtime_available=1
elif [[ "$plat" = "FreeBSD"* ]]; then
archdir="${scriptdir}/runtime/freebsd-amd64"
#aligned 2026-07-22 to the punkbin repo's actual folder name (freebsd-x86_64;
#this payload previously said freebsd-amd64 - the G-105 platform-dir naming
#alignment item)
local_platform="freebsd-x86_64"
os="freebsd"
elif [[ "$plat" == "DragonFly"* ]]; then
archdir="${scriptdir}/runtime/dragonflybsd-$arch"
local_platform="dragonflybsd-$arch"
os="dragonflybsd"
elif [[ "$plat" == "NetBSD"* ]]; then
archdir="${scriptdir}/runtime/netbsd-$arch"
local_platform="netbsd-$arch"
os="netbsd"
elif [[ "$plat" == "OpenBSD"* ]]; then
archdir="${scriptdir}/runtime/openbsd-amd64"
local_platform="openbsd-amd64"
os="openbsd"
elif [[ "$plat" == "MINGW32"* ]]; then
#REVIEW
os="win32"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
elif [[ "$plat" == "MINGW64"* ]]; then
#REVIEW
os="win32"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
elif [[ "$plat" == "CYGWIN_NT"* ]]; then
os="win32"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
elif [[ "$plat" == "MSYS_NT"* ]]; then
@ -80,14 +82,61 @@ elif [[ "$plat" == "MSYS_NT"* ]]; then
#"c:/windows/system32/" is quite likely in the path ahead of msys,git etc.
#This breaks calls to various unix utils such as sed etc (wsl related?)
export PATH="$shellfolder${PATH:+:${PATH}}"
archdir="${scriptdir}/runtime/win32-x86_64"
local_platform="win32-x86_64"
rt_default="tclsh902z.exe"
runtime_available=1
else
archdir="${scriptdir}/runtime/other"
local_platform="other"
os="other"
fi
archtail="${archdir##*/}" #server folder name e.g linux-x86_64
#-- platform resolution (G-105 cross-build staging) ---------------------------
#The prongs above detect the LOCAL platform. fetch/list/use accept
#'-platform <p>' to aim at another punkbin platform-dir (cross-build staging /
#provisioning); resolution: -platform arg > PUNK_RUNTIME_PLATFORM env > local.
#Values are punkbin platform-dir names (e.g win32-x86_64, linux-x86_64, macosx)
#- NOT zig triples (the buildsuite maps triples to platform dirs at build time).
#Validation is shape-only: the server's sha1sums/404 is the truth for what
#exists. 'run' is LOCAL ONLY (foreign binaries are not runnable here) - only a
#LEADING -platform is rejected there; later args belong to the launched runtime.
action="${1:-}"
[[ $# -gt 0 ]] && shift
platform_opt=""
case "$action" in
fetch|list|use)
newargs=()
while [[ $# -gt 0 ]]; do
if [[ "$1" == "-platform" ]]; then
shift
if [[ $# -eq 0 ]]; then
echo "option -platform requires a value (a punkbin platform-dir name, e.g linux-x86_64)"
exit 1
fi
platform_opt="$1"
else
newargs+=("$1")
fi
shift
done
set -- ${newargs[@]+"${newargs[@]}"}
;;
run)
if [[ "${1:-}" == "-platform" ]]; then
echo "'run' launches the LOCAL platform's active runtime - it takes no -platform option"
echo "(foreign-platform folders are cross-build staging; deploy them to their platform to run)"
exit 1
fi
;;
esac
platform="${platform_opt:-${PUNK_RUNTIME_PLATFORM:-$local_platform}}"
if ! [[ "$platform" =~ ^[a-z0-9][a-z0-9_-]*$ ]]; then
echo "invalid platform name '$platform' (expected a punkbin platform-dir name such as win32-x86_64, linux-x86_64, macosx)"
exit 1
fi
is_local=0
[[ "$platform" == "$local_platform" ]] && is_local=1
archdir="${scriptdir}/runtime/${platform}"
archtail="$platform" #server folder name e.g linux-x86_64
active_file="${archdir}/active.toml"
#sha1 of a file - tool varies by platform (sha1sum: linux/coreutils, shasum: macosx,
@ -145,7 +194,7 @@ rootname_of() {
#by the buildsuite kit-family-artifacts step / fetched from punkbin). Prints a
#short "[variant=... tcl=... rN ...]" summary for list output, "" when absent.
metadata_summary() {
local exename="$1" tomlfile parts variant tclpatch revision piperepl artname
local exename="$1" tomlfile parts variant tclpatch revision piperepl artname target
tomlfile="$archdir/$(rootname_of "$exename").toml"
[[ -f "$tomlfile" ]] || return 0
variant=$(sed -n 's/^[[:space:]]*variant[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" | head -n 1)
@ -153,6 +202,7 @@ metadata_summary() {
revision=$(sed -n 's/^[[:space:]]*revision[[:space:]]*=[[:space:]]*\([0-9][0-9]*\).*/\1/p' "$tomlfile" | head -n 1)
piperepl=$(sed -n 's/^[[:space:]]*piperepl[[:space:]]*=[[:space:]]*\(true\|false\).*/\1/p' "$tomlfile" | head -n 1)
artname=$(sed -n 's/^[[:space:]]*name[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" | head -n 1)
target=$(sed -n 's/^[[:space:]]*target[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" | head -n 1)
parts=""
[[ -n "$variant" ]] && parts="$parts variant=$variant"
[[ -n "$tclpatch" ]] && parts="$parts tcl=$tclpatch"
@ -161,8 +211,70 @@ metadata_summary() {
elif [[ "$piperepl" == "false" ]]; then parts="$parts piperepl=off"; fi
#a materialized working copy records which immutable artifact it came from
[[ -n "$artname" && "$artname" != "$exename" ]] && parts="$parts from=$artname"
#integrity flag: a runtime filed under a platform folder its metadata says it
#was not built for (cross-platform fetch/staging misfiling)
[[ -n "$target" && "$target" != "$archtail" ]] && parts="$parts !TARGET-MISMATCH:$target"
[[ -n "$parts" ]] && printf '[%s]' "${parts# }"
}
#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 " fetch ?<name>? ?-platform <p>? download+verify a runtime from punkbin"
echo " list ?-remote? ?-platform <p>? installed (or server) runtimes + metadata"
echo " use <name> ?-platform <p>? select active / materialize -r<N> artifact"
echo " run ?args...? launch the active local-platform runtime"
echo " help full help (options, env vars, examples)"
}
show_help() {
echo "punk-runtime - manage the plain Tcl runtimes under bin/runtime/<platform>/"
echo ""
show_usage
echo ""
echo "Actions:"
echo " fetch ?<name>? ?-platform <p>?"
echo " Download a runtime from the punkbin artifact server into"
echo " bin/runtime/<p>/ with sha1 verification against the server's"
echo " sha1sums.txt. -r<N>-named family artifacts also fetch their"
echo " <rootname>.toml metadata record. Omitting <name> fetches the"
echo " local platform's default runtime; a FOREIGN platform fetch"
echo " requires an explicit <name>."
echo " list ?-remote? ?-platform <p>?"
echo " List installed runtimes with artifact-metadata summaries"
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 " 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"
echo " MATERIALIZED into its WORKING name (name minus -r<N> - what"
echo " mapvfs and projects reference), metadata toml copied alongside."
echo " run ?args...?"
echo " Launch the ACTIVE runtime of the LOCAL platform, passing args."
echo " Resolution: PUNK_ACTIVE_RUNTIME env > active.toml > sole"
echo " installed candidate. Takes no -platform (foreign binaries are"
echo " not runnable here)."
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"
echo " order: -platform argument > PUNK_RUNTIME_PLATFORM env var."
echo " Foreign-platform folders serve cross-build staging and provisioning:"
echo " active.toml travels with the folder when it is deployed to its real"
echo " platform (unix exec bits are restored at deploy time - e.g rsync/tar/"
echo " chmod on the receiving side)."
echo ""
echo "Env: PUNKBIN_URL (artifact server base url), PUNK_RUNTIME_PLATFORM,"
echo " PUNK_ACTIVE_RUNTIME (run-time selection override)"
echo ""
echo "Examples:"
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"
echo " $0 fetch tclsh9.0.5-punk-r1 -platform linux-x86_64"
echo " $0 use tclsh9.0.5-punk-r1 -platform linux-x86_64"
echo " $0 run myscript.tcl arg1 arg2"
}
#G-103 artifact-tier names carry -r<N> before the (optional) .exe suffix; prints
#the WORKING name (artifact minus -r<N>) when the name is artifact-tier, else ""
working_name_of() {
@ -171,13 +283,20 @@ working_name_of() {
if [[ "$w" != "$1" ]]; then printf '%s' "$w"; fi
}
case "$1" in
case "$action" in
"fetch")
runtime="$rt_default"
if [[ -n "$2" ]]; then
runtime="$2"
if [[ -n "${1:-}" ]]; then
runtime="$1"
elif [[ "$is_local" -ne 1 ]]; then
#fetch-name defaults only make sense for the platform we are standing
#on - a foreign-platform fetch (cross-build staging) names its runtime
echo "No default runtime for foreign platform '$platform' - name it explicitly:"
echo " $0 fetch <runtimename> -platform $platform"
echo " (see available names: $0 list -remote -platform $platform)"
exit 1
fi
if [[ ( "$runtime_available" -eq 1 || -n "$2" ) && "$archtail" != "other" && -n "$runtime" ]]; then
if [[ ( "$runtime_available" -eq 1 || -n "${1:-}" ) && "$archtail" != "other" && -n "$runtime" ]]; then
url="${url_kitbase}/${archtail}/${runtime}"
output="${archdir}/${runtime}"
sha1url="${url_kitbase}/${archtail}/sha1sums.txt"
@ -267,7 +386,7 @@ case "$1" in
fi
;;
"list")
if [[ "$2" == "-remote" ]]; then
if [[ "${1:-}" == "-remote" ]]; then
#compare local runtimes with those listed on the artifact server
#(functional parity with the powershell payload's 'list -remote')
sha1url="${url_kitbase}/${archtail}/sha1sums.txt"
@ -340,9 +459,12 @@ case "$1" in
fi
;;
"use")
if [[ -z "$2" ]]; then
echo "Usage: $0 use <runtimename>"
echo "Installed candidates:"
#with -platform: manage THAT platform folder's selection/materialization
#(cross-build staging - active.toml travels with the folder when deployed;
#'run' on this machine only ever consults the local platform)
if [[ -z "${1:-}" ]]; then
echo "Usage: $0 use <runtimename> ?-platform <p>?"
echo "Installed candidates ($platform):"
for f in $(list_candidates); do
echo " $f"
done
@ -352,14 +474,14 @@ case "$1" in
fi
exit 1
fi
case "$2" in
case "$1" in
*_BUILDCOPY|*.txt|*.toml|*.tm|*.tmp)
echo "'$2' is not a selectable runtime"
echo "'$1' is not a selectable runtime"
exit 1
;;
esac
if [[ ! -f "$archdir/$2" ]]; then
echo "No runtime named '$2' found in $archdir"
if [[ ! -f "$archdir/$1" ]]; then
echo "No runtime named '$1' found in $archdir"
echo "Installed candidates:"
for f in $(list_candidates); do
echo " $f"
@ -370,26 +492,35 @@ case "$1" in
#artifact into its WORKING name (name minus -r<N> - what mapvfs and
#projects reference), copies its metadata toml alongside, and selects
#the working name. Republishing artifacts never churns consumers.
working=$(working_name_of "$2")
#(chmod is a no-op when staging unix runtimes from windows filesystems -
#exec bits are restored at deploy time, e.g rsync/tar/chmod on the guest.)
working=$(working_name_of "$1")
if [[ -n "$working" ]]; then
cp -f "$archdir/$2" "$archdir/$working"
cp -f "$archdir/$1" "$archdir/$working"
chmod +x "$archdir/$working"
srctoml="$archdir/$(rootname_of "$2").toml"
srctoml="$archdir/$(rootname_of "$1").toml"
desttoml="$archdir/$(rootname_of "$working").toml"
if [[ -f "$srctoml" ]]; then
cp -f "$srctoml" "$desttoml"
echo "materialized $working from artifact $2 (metadata toml copied alongside)"
echo "materialized $working from artifact $1 (metadata toml copied alongside)"
else
echo "materialized $working from artifact $2 (no metadata toml found beside the artifact)"
echo "materialized $working from artifact $1 (no metadata toml found beside the artifact)"
fi
set_active "$working"
else
set_active "$2"
set_active "$1"
fi
;;
"run")
#resolution order: PUNK_ACTIVE_RUNTIME env override, active.toml, single
#installed candidate - otherwise error with candidates (no last-in-list guessing)
#installed candidate - otherwise error with candidates (no last-in-list guessing).
#LOCAL platform only: the -platform arg is rejected in the scan above, and a
#PUNK_RUNTIME_PLATFORM env override is likewise ignored here (foreign
#binaries are not runnable; the env override serves list/fetch/use).
if [[ "$is_local" -ne 1 ]]; then
archdir="${scriptdir}/runtime/${local_platform}"
active_file="${archdir}/active.toml"
fi
activeruntime=""
if [[ -n "$PUNK_ACTIVE_RUNTIME" ]]; then
activeruntime="$PUNK_ACTIVE_RUNTIME"
@ -426,13 +557,22 @@ case "$1" in
fi
activeruntime_fullpath="$archdir/$activeruntime"
#echo "using $activeruntime_fullpath"
shift
#echo "args: $@"
#(the action was already shifted off during the option scan - "$@" is
#exactly the runtime's argument list)
$activeruntime_fullpath "$@"
;;
"help")
show_help
;;
"")
#no action: short usage + pointer at the fuller help
show_usage
echo ""
echo "'$0 help' gives options, env vars and examples."
;;
*)
echo "Usage: $0 {fetch|list|use|run}"
echo "received $@"
echo "unknown action '$action'"
show_usage
exit 1
;;
esac

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

@ -70,6 +70,91 @@ function Get-PunkRuntimeCandidates {
}
return @(get-childItem -Path $archfolder -File | Where-object Name -Notlike '*_BUILDCOPY*' | Where-object {-not ($(".txt",".toml",".tm",".tmp",".log") -contains $_.Extension) } | Sort-Object Name)
}
#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 " fetch ?<name>? ?-platform <p>? download+verify a runtime from punkbin"
write-host " list ?-remote? ?-platform <p>? installed (or server) runtimes + metadata"
write-host " use <name> ?-platform <p>? select active / materialize -r<N> artifact"
write-host " run ?args...? launch the active local-platform runtime"
write-host " help full help (options, env vars, examples)"
}
function Show-PunkRuntimeHelp {
write-host "punk-runtime - manage the plain Tcl runtimes under bin/runtime/<platform>/"
write-host ""
Show-PunkRuntimeUsage
write-host ""
write-host "Actions:"
write-host " fetch ?<name>? ?-platform <p>?"
write-host " Download a runtime from the punkbin artifact server into"
write-host " bin/runtime/<p>/ with sha1 verification against the server's"
write-host " sha1sums.txt. -r<N>-named family artifacts also fetch their"
write-host " <rootname>.toml metadata record. Omitting <name> fetches the"
write-host " local platform's default runtime; a FOREIGN platform fetch"
write-host " requires an explicit <name>."
write-host " list ?-remote? ?-platform <p>?"
write-host " List installed runtimes with artifact-metadata summaries"
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 " 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"
write-host " MATERIALIZED into its WORKING name (name minus -r<N> - what"
write-host " mapvfs and projects reference), metadata toml copied alongside."
write-host " run ?args...?"
write-host " Launch the ACTIVE runtime of the LOCAL platform, passing args."
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 ""
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"
write-host " order: -platform argument > PUNK_RUNTIME_PLATFORM env var."
write-host " Foreign-platform folders serve cross-build staging and provisioning:"
write-host " active.toml travels with the folder when it is deployed to its real"
write-host " platform (unix exec bits are restored at deploy time - e.g rsync/tar/"
write-host " chmod on the receiving side)."
write-host ""
write-host "Env: PUNKBIN_URL (artifact server base url), PUNK_RUNTIME_PLATFORM,"
write-host " PUNK_ACTIVE_RUNTIME (run-time selection override)"
write-host ""
write-host "Examples:"
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"
write-host " punk-runtime.cmd fetch tclsh9.0.5-punk-r1 -platform linux-x86_64"
write-host " punk-runtime.cmd use tclsh9.0.5-punk-r1 -platform linux-x86_64"
write-host " punk-runtime.cmd run myscript.tcl arg1 arg2"
}
#platform (target) resolution for fetch/list/use: -platform arg > PUNK_RUNTIME_PLATFORM
#env > the local default. Values are punkbin/bin-runtime platform-DIR names (e.g
#win32-x86_64, linux-x86_64, macosx) - NOT zig triples (the buildsuite maps triples to
#platform dirs at build time; punk-runtime speaks only the punkbin tier). Validation is
#deliberately shape-only: the server's sha1sums/404 is the truth for what exists.
#This payload runs on windows - the local default stays win32-x86_64 (a windows-arm
#default becomes a question when punkbin carries such a folder).
$script:PunkLocalPlatform = "win32-x86_64"
function Resolve-PunkRuntimePlatform {
param([string] $requested)
$plat = $script:PunkLocalPlatform
if ($requested) {
$plat = $requested
} elseif ($env:PUNK_RUNTIME_PLATFORM) {
$plat = $env:PUNK_RUNTIME_PLATFORM
}
#-cnotmatch: platform-dir names are lowercase and the artifact-server URL path
#is case-sensitive (default -notmatch is case-insensitive and would pass typos
#like Win32-X86_64 through to a server 404); bash payload parity (=~ is
#case-sensitive there)
if ($plat -cnotmatch '^[a-z0-9][a-z0-9_-]*$') {
write-host "invalid platform name '$plat' (expected a punkbin platform-dir name such as win32-x86_64, linux-x86_64, macosx)"
exit 1
}
return $plat
}
#name minus a .exe suffix only - dotted tcl patchlevels (tclsh9.0.5-punk) make
#generic last-dot extension stripping wrong for extensionless unix names
function Get-PunkRuntimeRootName {
@ -83,7 +168,7 @@ function Get-PunkRuntimeRootName {
#by the buildsuite kit-family-artifacts step / fetched from punkbin). Returns a
#short "[variant=... tcl=... rN ...]" summary for list output, "" when absent.
function Get-PunkRuntimeMetadataSummary {
param([string] $archfolder, [string] $exename)
param([string] $archfolder, [string] $exename, [string] $expectedplatform = "")
$tomlfile = Join-Path -Path $archfolder -ChildPath ((Get-PunkRuntimeRootName $exename) + ".toml")
if (-not (Test-Path -Path $tomlfile -PathType Leaf)) {
return ""
@ -109,6 +194,11 @@ function Get-PunkRuntimeMetadataSummary {
}
#a materialized working copy records which immutable artifact it came from
if ($fields.ContainsKey('name') -and $fields['name'] -ne $exename) { $parts += "from=$($fields['name'])" }
#integrity flag: a runtime filed under a platform folder its metadata says it
#was not built for (cross-platform fetch/staging misfiling)
if ($expectedplatform -ne "" -and $fields.ContainsKey('target') -and $fields['target'] -ne $expectedplatform) {
$parts += "!TARGET-MISMATCH:$($fields['target'])"
}
if ($parts.Count -eq 0) {
return ""
}
@ -132,8 +222,19 @@ function psmain {
$dynParam1 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'remote', [switch], $attributeCollection
)
#-platform (G-105 cross-build staging): punkbin platform-dir name to list for
$platformAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "listruntime"
Mandatory = $false
}
$platformAttributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$platformAttributeCollection.Add($platformAttribute)
$dynParam2 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'platform', [string], $platformAttributeCollection
)
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('remote', $dynParam1)
$paramDictionary.Add('platform', $dynParam2)
return $paramDictionary
} elseif ($action -eq 'fetch' -or $action -eq 'use') {
#GetDynamicParamDictionary ParameterDefinitions
@ -149,8 +250,21 @@ function psmain {
'runtime', [string], $attributeCollection
)
#-platform (G-105 cross-build staging): punkbin platform-dir name to fetch
#into / select within (default: the local platform)
$platformAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "fetchruntime"
Mandatory = $false
}
$platformAttributeCollection = [System.Collections.ObjectModel.Collection[System.Attribute]]::new()
$platformAttributeCollection.Add($platformAttribute)
$dynParam2 = [System.Management.Automation.RuntimeDefinedParameter]::new(
'platform', [string], $platformAttributeCollection
)
$paramDictionary = [System.Management.Automation.RuntimeDefinedParameterDictionary]::new()
$paramDictionary.Add('runtime', $dynParam1)
$paramDictionary.Add('platform', $dynParam2)
return $paramDictionary
} elseif ($action -eq 'run') {
#GetDynamicParamDictionary ParameterDefinitions
@ -195,7 +309,7 @@ function psmain {
'action' {
write-host "got action " $PSBoundParameters.action
Set-Variable -Name $_ -Value $PSBoundParameters."$_"
$known_actions = @("fetch", "list", "use", "run")
$known_actions = @("fetch", "list", "use", "run", "help")
if (-not($known_actions -contains $action)) {
write-host "action '$action' not understood. Known_actions: $known_actions"
exit 1
@ -227,16 +341,25 @@ function psmain {
}
switch ($action) {
'fetch' {
$arch = "win32-x86_64"
$arch = Resolve-PunkRuntimePlatform $PSBoundParameters["platform"]
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$archurl = "$artifacturl/$arch"
$sha1url = "$archurl/sha1sums.txt"
$runtime = "tclsh902z.exe"
foreach ($boundparam in $PSBoundParameters.Keys) {
write-host "fetchopt: $boundparam $($PSBoundParameters[$boundparam])"
}
$runtime = ""
if ( $PSBoundParameters["runtime"].Length ) {
$runtime = $PSBoundParameters["runtime"]
} elseif ($arch -eq $script:PunkLocalPlatform) {
$runtime = "tclsh902z.exe"
} else {
#fetch-name defaults only make sense for the platform we are standing
#on - a foreign-platform fetch (cross-build staging) names its runtime
write-host "No default runtime for foreign platform '$arch' - name it explicitly:"
write-host " punk-runtime.cmd fetch <runtimename> -platform $arch"
write-host " (see available names: punk-runtime.cmd list -remote -platform $arch)"
exit 1
}
$fileurl = "$archurl/$runtime"
@ -348,8 +471,11 @@ function psmain {
}
}
'use' {
#select the active runtime for subsequent 'run' calls
$arch = "win32-x86_64"
#select the active runtime for subsequent 'run' calls. With -platform:
#manage THAT platform folder's selection/materialization (cross-build
#staging - the active.toml travels with the folder when deployed; 'run'
#on this machine only ever consults the local platform).
$arch = Resolve-PunkRuntimePlatform $PSBoundParameters["platform"]
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$candidates = Get-PunkRuntimeCandidates $archfolder
$rtname = ""
@ -357,8 +483,8 @@ function psmain {
$rtname = $PSBoundParameters["runtime"]
}
if ($rtname -eq "") {
write-host "Usage: punk-runtime.cmd use <runtimename>"
write-host "Installed candidates:"
write-host "Usage: punk-runtime.cmd use <runtimename> ?-platform <p>?"
write-host "Installed candidates ($arch):"
foreach ($f in $candidates) {
write-host " $($f.Name)"
}
@ -402,8 +528,16 @@ function psmain {
'run' {
#launch the active runtime, passing arguments.
#resolution order: PUNK_ACTIVE_RUNTIME env override, active.toml, single
#installed candidate - otherwise error with candidates (no last-in-list guessing)
$arch = "win32-x86_64"
#installed candidate - otherwise error with candidates (no last-in-list guessing).
#LOCAL PLATFORM ONLY - a foreign platform's binaries are not runnable here.
#Only a LEADING -platform is rejected: everything after 'run' belongs to
#the runtime, so a later arg spelled -platform must pass through untouched.
if ($PSBoundParameters.opts.Length -gt 0 -and $PSBoundParameters.opts[0] -eq '-platform') {
write-host "'run' launches the LOCAL platform's active runtime - it takes no -platform option"
write-host "(foreign-platform folders are cross-build staging; deploy them to their platform to run)"
exit 1
}
$arch = $script:PunkLocalPlatform
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
if (-not(Test-Path -Path $archfolder -PathType Container)) {
write-host "No runtimes seem to be installed for $arch`nPlease use 'punk-runtime.cmd fetch' to install"
@ -479,8 +613,8 @@ function psmain {
}
}
'list' {
#todo - option to list for other os-arch
$arch = 'win32-x86_64'
#-platform lists another platform's folder/server dir (cross-build staging)
$arch = Resolve-PunkRuntimePlatform $PSBoundParameters["platform"]
$archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
$sha1local = join-path -Path $archfolder -ChildPath "sha1sums.txt"
$archurl = "$artifacturl/$arch"
@ -580,7 +714,7 @@ function psmain {
write-host "$(${dircontents}.count) runtime(s) in $archfolder"
Write-host "-----------------------------------------------------------------------"
foreach ($f in $dircontents) {
$meta = Get-PunkRuntimeMetadataSummary $archfolder $f.Name
$meta = Get-PunkRuntimeMetadataSummary $archfolder $f.Name $arch
$lhs = "$($f.Name)".PadRight(35, ' ')
if ($f.Name -eq $activename) {
write-host "* $lhs (active) $meta"
@ -601,13 +735,15 @@ function psmain {
}
}
}
default {
$actions = @("fetch", "list", "use", "run")
write-host "Available actions: $actions"
write-host "received"
foreach ($boundparam in $PSBoundParameters.opts) {
write-host $boundparam
'help' {
Show-PunkRuntimeHelp
}
default {
#no action given (unknown actions were already rejected in the
#process block): show the short usage and point at 'help'
Show-PunkRuntimeUsage
write-host ""
write-host "'punk-runtime.cmd help' gives options, env vars and examples."
}
}

Loading…
Cancel
Save