diff --git a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd
index 963a5420..e2429a73 100644
--- a/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd
+++ b/src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/bin/punk-runtime.cmd
@@ -1292,64 +1292,73 @@ scriptroot="${basename%.*}" #e.g "punk-runtime"
#artifact server base url - overridable for mirrors/testing
url_kitbase="${PUNKBIN_URL:-https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master}"
-runtime_available=0
#$OSTYPE varies in capitalization across for example zsh and bash
#uname probably a more consistent bet
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 CANONICAL punkshell platform-DIR name - see
+#punk::platform / 'help platforms': cpu tokens normalized amd64->x86_64,
+#aarch64->arm64). Per-platform default fetch runtimes are NOT baked here - they
+#are the server's curated defaults.txt (a punkbin release decision).
+narch="$arch"
+case "$narch" in
+ amd64) narch="x86_64";;
+ aarch64|arm64) narch="arm64";;
+esac
if [[ "$plat" = "Linux"* ]]; then
if [[ "$arch" = "x86_64"* ]]; then
- archdir="${scriptdir}/runtime/linux-x86_64"
- rt_default="tclkit-902-Linux64-intel-dyn"
- runtime_available=1
+ local_platform="linux-x86_64"
+ elif [[ "$narch" = "arm64" ]]; then
+ #canonical arm64 (aarch64). punkbin's existing arm kit predates the
+ #arm64 name and sits in linux-arm (the server's defaults.txt records
+ #per-platform recommendations).
+ local_platform="linux-arm64"
elif [[ "$arch" = "arm"* ]]; then
- archdir="${scriptdir}/runtime/linux-arm"
- rt_default="tclkit-902-Linux64-arm-dyn"
- runtime_available=1
+ #32-bit arm
+ local_platform="linux-arm"
else
- archdir="${scriptdir}/runtime/linux-$arch"
+ local_platform="linux-$narch"
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"
- rt_default="tclkit-902-Darwin64-dyn"
- runtime_available=1
+ #universal (multi-arch) binaries - the runtime tier keeps ONE macosx folder
+ #(per-arch macosx-x86_64/macosx-arm64 names serve the lib tree tier)
+ local_platform="macosx"
elif [[ "$plat" = "FreeBSD"* ]]; then
- archdir="${scriptdir}/runtime/freebsd-amd64"
+ #canonical names (2026-07-22): freebsd-x86_64 (punkbin's actual folder; this
+ #payload previously said freebsd-amd64) / freebsd-arm64
+ local_platform="freebsd-$narch"
os="freebsd"
elif [[ "$plat" == "DragonFly"* ]]; then
- archdir="${scriptdir}/runtime/dragonflybsd-$arch"
+ local_platform="dragonflybsd-$narch"
os="dragonflybsd"
elif [[ "$plat" == "NetBSD"* ]]; then
- archdir="${scriptdir}/runtime/netbsd-$arch"
+ local_platform="netbsd-$narch"
os="netbsd"
elif [[ "$plat" == "OpenBSD"* ]]; then
- archdir="${scriptdir}/runtime/openbsd-amd64"
+ local_platform="openbsd-$narch"
os="openbsd"
elif [[ "$plat" == "MINGW32"* ]]; then
- #REVIEW
+ #32-bit msys shell - a genuine 32-bit machine reports i*86; a 32-bit shell
+ #on a 64-bit OS is rare enough that the machine arch decides (REVIEW)
os="win32"
- archdir="${scriptdir}/runtime/win32-x86_64"
- rt_default="tclsh902z.exe"
- runtime_available=1
+ case "$arch" in
+ i*86) local_platform="win32-ix86";;
+ *) local_platform="win32-x86_64";;
+ esac
elif [[ "$plat" == "MINGW64"* ]]; then
#REVIEW
os="win32"
- archdir="${scriptdir}/runtime/win32-x86_64"
- rt_default="tclsh902z.exe"
- runtime_available=1
+ local_platform="win32-x86_64"
elif [[ "$plat" == "CYGWIN_NT"* ]]; then
os="win32"
- archdir="${scriptdir}/runtime/win32-x86_64"
- rt_default="tclsh902z.exe"
- runtime_available=1
+ case "$arch" in
+ i*86) local_platform="win32-ix86";;
+ *) local_platform="win32-x86_64";;
+ esac
elif [[ "$plat" == "MSYS_NT"* ]]; then
echo MSYS
os="win32"
@@ -1360,14 +1369,59 @@ 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"
- rt_default="tclsh902z.exe"
- runtime_available=1
+ local_platform="win32-x86_64"
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
' 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|platforms)
+ 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,
@@ -1398,20 +1452,170 @@ set_active() {
printf 'active = "%s"\n' "$1" > "$active_file"
echo "active runtime for $archtail set to: $1 (recorded in $active_file)"
}
-#installed runtime candidates - exclude build copies and non-runtime files
+#installed runtime candidates - exclude directories, build copies and
+#non-runtime files (ps1-payload parity: files only, same extension excludes)
list_candidates() {
+ local f
if [[ -d "$archdir" ]]; then
- ls -1 "$archdir" | grep -v '_BUILDCOPY$' | grep -v '\.txt$' | grep -v '\.toml$' | grep -v '\.tm$' | grep -v '\.tmp$'
+ for f in "$archdir"/*; do
+ [[ -f "$f" ]] || continue
+ f="${f##*/}"
+ case "$f" in
+ *_BUILDCOPY*|*.txt|*.toml|*.tm|*.tmp|*.log) continue;;
+ esac
+ printf '%s\n' "$f"
+ done
fi
}
+#name minus a .exe suffix only - dotted tcl patchlevels (tclsh9.0.5-punk) make
+#generic last-dot extension stripping wrong for extensionless unix names
+rootname_of() {
+ case "$1" in
+ *.exe|*.EXE) printf '%s' "${1%.???}";;
+ *) printf '%s' "$1";;
+ esac
+}
+#G-103 artifact metadata: a runtime may carry a .toml beside it (emitted
+#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 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)
+ tclpatch=$(sed -n 's/^[[:space:]]*tcl_patchlevel[[:space:]]*=[[:space:]]*"\(.*\)".*/\1/p' "$tomlfile" | head -n 1)
+ 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"
+ [[ -n "$revision" ]] && parts="$parts r$revision"
+ if [[ "$piperepl" == "true" ]]; then parts="$parts piperepl=on"
+ 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|platforms|help}"
+ echo " fetch ?? ?-platform ? download+verify a runtime from punkbin"
+ echo " list ?-remote? ?-platform
? installed (or server) runtimes + metadata"
+ echo " use ?-platform ? select active / materialize -r artifact"
+ echo " run ?args...? launch the active local-platform runtime"
+ echo " platforms ?-remote? local platform folders / platforms the server serves"
+ echo " help full help (options, env vars, examples)"
+}
+show_help() {
+ echo "punk-runtime - manage the plain Tcl runtimes under bin/runtime//"
+ echo ""
+ show_usage
+ echo ""
+ echo "Actions:"
+ echo " fetch ?? ?-platform ?"
+ echo " Download a runtime from the punkbin artifact server into"
+ echo " bin/runtime/
/ with sha1 verification against the server's"
+ echo " sha1sums.txt. -r-named family artifacts also fetch their"
+ echo " .toml metadata record. Omitting fetches the"
+ echo " platform's recommended default per the server's curated"
+ echo " defaults.txt (a punkbin release decision; works with -platform"
+ echo " too) - platforms without a recorded default need an explicit"
+ echo " ."
+ echo " list ?-remote? ?-platform ?"
+ 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 ?-platform ?"
+ echo " Select the runtime that 'run' launches (records active.toml in"
+ echo " the platform folder). An immutable -r ARTIFACT name is"
+ echo " MATERIALIZED into its WORKING name (name minus -r - 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 " platforms ?-remote?"
+ echo " List local platform folders under bin/runtime/. With -remote,"
+ echo " list the platforms the artifact server serves - read from the"
+ echo " server's platforms.txt discovery manifest (part of the punkbin"
+ echo " layout; third-party mirrors carry the same file), with local"
+ echo " presence marked. Servers without the manifest get an actionable"
+ echo " message (name platforms explicitly with -platform)."
+ echo ""
+ echo "Platforms: punkbin platform-dir names (e.g win32-x86_64, linux-x86_64,"
+ echo " macosx) - not zig triples. Default is the local platform; override"
+ 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 platforms -remote"
+ echo " $0 fetch tclsh9.0.5-punk-r1.exe"
+ echo " $0 use tclsh9.0.5-punk-r1.exe (materializes tclsh9.0.5-punk.exe)"
+ echo " $0 list -remote -platform linux-x86_64"
+ 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 before the (optional) .exe suffix; prints
+#the WORKING name (artifact minus -r) when the name is artifact-tier, else ""
+working_name_of() {
+ local w
+ w=$(printf '%s' "$1" | sed -E 's/^(.*)-r[0-9]+(\.[Ee][Xx][Ee])?$/\1\2/')
+ 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 [[ "$archtail" == "other" ]]; then
+ echo "Unrecognised local platform - name one explicitly with -platform"
+ echo "(canonical names: 'help platforms' in the punk shell)"
+ exit 1
+ fi
+ runtime="${1:-}"
+ if [[ -z "$runtime" ]]; then
+ #no name given: consult the server's curated defaults.txt - the punkbin
+ #release recommendation (updated there as part of each publication
+ #change-set; see punkbin AGENTS.md). Per-platform server data, so it
+ #works for any -platform, not just local.
+ defaultsurl="${url_kitbase}/defaults.txt"
+ defaultslocal="${scriptdir}/runtime/defaults.txt"
+ mkdir -p "${scriptdir}/runtime"
+ if ! curl -fsSL --output "$defaultslocal" "$defaultsurl"; then
+ if [[ -f "$defaultslocal" ]]; then
+ echo "WARNING: could not fetch $defaultsurl - using cached copy at $defaultslocal"
+ else
+ echo "Could not fetch $defaultsurl"
+ echo "No server default available - name a runtime explicitly:"
+ echo " $0 fetch ?-platform $archtail?"
+ echo " (see available names: $0 list -remote -platform $archtail)"
+ exit 1
+ fi
+ fi
+ runtime=$(awk -v p="$archtail" '$1==p {print $2; exit}' "$defaultslocal")
+ if [[ -z "$runtime" ]]; then
+ echo "No default recorded for platform '$archtail' in the server's defaults.txt - name a runtime explicitly:"
+ echo " $0 fetch ?-platform $archtail?"
+ echo " (see available names: $0 list -remote -platform $archtail)"
+ exit 1
+ fi
+ echo "using server default for $archtail: $runtime"
fi
- if [[ ( "$runtime_available" -eq 1 || -n "$2" ) && "$archtail" != "other" && -n "$runtime" ]]; then
+ if [[ -n "$runtime" ]]; then
url="${url_kitbase}/${archtail}/${runtime}"
output="${archdir}/${runtime}"
sha1url="${url_kitbase}/${archtail}/sha1sums.txt"
@@ -1480,17 +1684,25 @@ case "$1" in
exit 1
fi
fi
+ #G-103: family artifacts (-r names) carry a metadata toml alongside
+ #on the server - fetch it too; absence is fine (pre-family runtimes)
+ if [[ -n "$(working_name_of "$runtime")" ]]; then
+ tomlname="$(rootname_of "$runtime").toml"
+ if curl -fsSL --output "${archdir}/${tomlname}" "${url_kitbase}/${archtail}/${tomlname}"; then
+ echo "artifact metadata saved at ${archdir}/${tomlname}"
+ else
+ rm -f "${archdir}/${tomlname}"
+ echo "no artifact metadata toml on server for $runtime (ok for pre-family runtimes)"
+ fi
+ fi
#first fetch establishes the active runtime; later fetches never steal it
if [[ -z "$(get_active)" ]]; then
set_active "$runtime"
fi
- else
- echo "No default runtime currently published for $os ($archtail)"
- echo "If one exists on the server, name it explicitly: $0 fetch "
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"
@@ -1543,16 +1755,19 @@ case "$1" in
count=$(printf '%s\n' "$candidates" | grep -c . )
echo "$count runtime(s) in $archdir"
for f in $candidates; do
+ meta=$(metadata_summary "$f")
if [[ "$f" == "$active" ]]; then
- echo "* $f (active)"
+ printf '* %-35s (active) %s\n' "$f" "$meta"
else
- echo " $f"
+ printf ' %-35s %s\n' "$f" "$meta"
fi
done
if [[ -n "$active" && ! -f "$archdir/$active" ]]; then
echo "WARNING: active runtime '$active' (from $active_file) is not present - use '$0 use ' to reselect"
fi
echo "Use: '$0 list -remote' to compare local runtimes with those available on the artifact server"
+ echo "Use: '$0 use ' to select the runtime that 'run' launches"
+ echo "Use: '$0 use -name>' to materialize an immutable -r artifact into its working name and select it"
else
echo "No runtimes available in $archdir"
echo " Use '$0 fetch' to install."
@@ -1560,9 +1775,12 @@ case "$1" in
fi
;;
"use")
- if [[ -z "$2" ]]; then
- echo "Usage: $0 use "
- 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 ?-platform ?"
+ echo "Installed candidates ($platform):"
for f in $(list_candidates); do
echo " $f"
done
@@ -1572,25 +1790,53 @@ 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"
done
exit 1
fi
- set_active "$2"
+ #G-103 artifact-tier names (-r, immutable): 'use' MATERIALIZES the
+ #artifact into its WORKING name (name minus -r - what mapvfs and
+ #projects reference), copies its metadata toml alongside, and selects
+ #the working name. Republishing artifacts never churns consumers.
+ #(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/$1" "$archdir/$working"
+ chmod +x "$archdir/$working"
+ 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 $1 (metadata toml copied alongside)"
+ else
+ echo "materialized $working from artifact $1 (no metadata toml found beside the artifact)"
+ fi
+ set_active "$working"
+ else
+ 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"
@@ -1627,13 +1873,93 @@ 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 "$@"
;;
+ "platforms")
+ #enumerate platform folders: local (bin/runtime/*) and, with -remote, the
+ #server's platforms.txt discovery manifest (raw-file servers have no
+ #directory listing - the manifest is part of the punkbin layout contract;
+ #third-party mirrors carry the same file). -platform is ignored here
+ #(this action enumerates ALL platforms).
+ rtroot="${scriptdir}/runtime"
+ localdirs=""
+ if [[ -d "$rtroot" ]]; then
+ localdirs=$(ls -1 "$rtroot" 2>/dev/null | while read -r d; do [[ -d "$rtroot/$d" ]] && echo "$d"; done)
+ fi
+ if [[ "${1:-}" == "-remote" ]]; then
+ manifesturl="${url_kitbase}/platforms.txt"
+ manifestlocal="${rtroot}/platforms.txt"
+ mkdir -p "$rtroot"
+ if curl -fsSL --output "$manifestlocal" "$manifesturl"; then
+ echo "Fetched $manifesturl"
+ elif [[ -f "$manifestlocal" ]]; then
+ echo "WARNING: could not fetch $manifesturl - using cached copy at $manifestlocal"
+ else
+ echo "No platforms.txt available from $manifesturl"
+ echo "(pre-convention punkbin or third-party mirror without the discovery manifest)"
+ echo "Name platforms explicitly with -platform; canonical names: 'help platforms' in the punk shell"
+ exit 1
+ fi
+ echo "-----------------------------------------------------------------------"
+ echo "Platforms served by ${url_kitbase}"
+ echo "-----------------------------------------------------------------------"
+ remoteplatforms=""
+ while IFS= read -r line; do
+ line="${line#"${line%%[![:space:]]*}"}"
+ [[ -z "$line" || "${line:0:1}" == "#" ]] && continue
+ remoteplatforms="$remoteplatforms $line"
+ marks=""
+ [[ "$line" == "$local_platform" ]] && marks="local platform"
+ if printf '%s\n' $localdirs | grep -qx "$line"; then
+ [[ -n "$marks" ]] && marks="$marks, "
+ marks="${marks}local dir present"
+ fi
+ if [[ -n "$marks" ]]; then
+ printf ' %-25s (%s)\n' "$line" "$marks"
+ else
+ printf ' %-25s\n' "$line"
+ fi
+ done < "$manifestlocal"
+ for d in $localdirs; do
+ if ! printf '%s\n' $remoteplatforms | grep -qx "$d"; then
+ printf ' %-25s (local dir only - not served remotely)\n' "$d"
+ fi
+ done
+ echo "-----------------------------------------------------------------------"
+ echo "Use: '$0 list -remote -platform ' to see a platform's runtimes"
+ else
+ echo "-----------------------------------------------------------------------"
+ echo "Local platform folders under $rtroot"
+ echo "-----------------------------------------------------------------------"
+ if [[ -z "$localdirs" ]]; then
+ echo " (none - 'fetch' creates the local platform's folder)"
+ fi
+ for d in $localdirs; do
+ if [[ "$d" == "$local_platform" ]]; then
+ printf '* %-25s (local platform)\n' "$d"
+ else
+ printf ' %-25s\n' "$d"
+ fi
+ done
+ echo "-----------------------------------------------------------------------"
+ echo "Use: '$0 platforms -remote' to see platforms served by the artifact server"
+ echo "Canonical platform names: 'help platforms' in the punk shell"
+ fi
+ ;;
+ "help")
+ show_help
+ ;;
+ "")
+ #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
@@ -2004,7 +2330,158 @@ function Get-PunkRuntimeCandidates {
if (-not (Test-Path -Path $archfolder -PathType Container)) {
return @()
}
- return @(get-childItem -Path $archfolder -File | Where-object Name -Notlike '*_BUILDCOPY*' | Where-object {-not ($(".txt",".toml",".tm",".tmp") -contains $_.Extension) } | Sort-Object Name)
+ 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|platforms|help}"
+ write-host " fetch ?? ?-platform ? download+verify a runtime from punkbin"
+ write-host " list ?-remote? ?-platform
? installed (or server) runtimes + metadata"
+ write-host " use ?-platform ? select active / materialize -r artifact"
+ write-host " run ?args...? launch the active local-platform runtime"
+ write-host " platforms ?-remote? local platform folders / platforms the server serves"
+ write-host " help full help (options, env vars, examples)"
+}
+function Show-PunkRuntimeHelp {
+ write-host "punk-runtime - manage the plain Tcl runtimes under bin/runtime//"
+ write-host ""
+ Show-PunkRuntimeUsage
+ write-host ""
+ write-host "Actions:"
+ write-host " fetch ?? ?-platform ?"
+ write-host " Download a runtime from the punkbin artifact server into"
+ write-host " bin/runtime/
/ with sha1 verification against the server's"
+ write-host " sha1sums.txt. -r-named family artifacts also fetch their"
+ write-host " .toml metadata record. Omitting fetches the"
+ write-host " platform's recommended default per the server's curated"
+ write-host " defaults.txt (a punkbin release decision; works with -platform"
+ write-host " too) - platforms without a recorded default need an explicit"
+ write-host " ."
+ write-host " list ?-remote? ?-platform ?"
+ 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 ?-platform ?"
+ write-host " Select the runtime that 'run' launches (records active.toml in"
+ write-host " the platform folder). An immutable -r ARTIFACT name is"
+ write-host " MATERIALIZED into its WORKING name (name minus -r - 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 " platforms ?-remote?"
+ write-host " List local platform folders under bin/runtime/. With -remote,"
+ write-host " list the platforms the artifact server serves - read from the"
+ write-host " server's platforms.txt discovery manifest (part of the punkbin"
+ write-host " layout; third-party mirrors carry the same file), with local"
+ write-host " presence marked. Servers without the manifest get an actionable"
+ write-host " message (name platforms explicitly with -platform)."
+ write-host ""
+ write-host "Platforms: punkbin platform-dir names (e.g win32-x86_64, linux-x86_64,"
+ write-host " macosx) - not zig triples. Default is the local platform; override"
+ 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 platforms -remote"
+ write-host " punk-runtime.cmd fetch tclsh9.0.5-punk-r1.exe"
+ write-host " punk-runtime.cmd use tclsh9.0.5-punk-r1.exe (materializes tclsh9.0.5-punk.exe)"
+ write-host " punk-runtime.cmd list -remote -platform linux-x86_64"
+ 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 is win32-x86_64, or win32-ix86 on
+#a GENUINE 32-bit windows host (PROCESSOR_ARCHITECTURE x86 with no
+#PROCESSOR_ARCHITEW6432 - a 32-bit shell on a 64-bit OS keeps the x86_64 default:
+#the runtime store serves what the OS can run). A windows-arm default becomes a
+#question when punkbin carries such a folder.
+$script:PunkLocalPlatform = "win32-x86_64"
+if ($env:PROCESSOR_ARCHITECTURE -eq 'x86' -and -not $env:PROCESSOR_ARCHITEW6432) {
+ $script:PunkLocalPlatform = "win32-ix86"
+}
+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 {
+ param([string] $name)
+ if ($name -match '(?i)\.exe$') {
+ return $name.Substring(0, $name.Length - 4)
+ }
+ return $name
+}
+#G-103 artifact metadata: a runtime may carry a .toml beside it (emitted
+#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, [string] $expectedplatform = "")
+ $tomlfile = Join-Path -Path $archfolder -ChildPath ((Get-PunkRuntimeRootName $exename) + ".toml")
+ if (-not (Test-Path -Path $tomlfile -PathType Leaf)) {
+ return ""
+ }
+ $fields = @{}
+ foreach ($line in (Get-Content -Path $tomlfile)) {
+ $m = [regex]::Match($line, '^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*"(.*)"\s*$')
+ if ($m.Success) {
+ $fields[$m.Groups[1].Value] = $m.Groups[2].Value
+ continue
+ }
+ $m = [regex]::Match($line, '^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*([0-9]+|true|false)\s*$')
+ if ($m.Success) {
+ $fields[$m.Groups[1].Value] = $m.Groups[2].Value
+ }
+ }
+ $parts = @()
+ if ($fields.ContainsKey('variant')) { $parts += "variant=$($fields['variant'])" }
+ if ($fields.ContainsKey('tcl_patchlevel')) { $parts += "tcl=$($fields['tcl_patchlevel'])" }
+ if ($fields.ContainsKey('revision')) { $parts += "r$($fields['revision'])" }
+ if ($fields.ContainsKey('piperepl')) {
+ if ($fields['piperepl'] -eq 'true') { $parts += "piperepl=on" } else { $parts += "piperepl=off" }
+ }
+ #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 ""
+ }
+ return "[" + ($parts -join " ") + "]"
}
function psmain {
@@ -2014,7 +2491,9 @@ function psmain {
[Parameter(Mandatory=$false, Position = 0)][string] $action = ""
)
dynamicparam {
- if ($action -eq 'list') {
+ if ($action -eq 'list' -or $action -eq 'platforms') {
+ #shared dynamic params: -remote for both; -platform is meaningful to
+ #'list' and ignored by 'platforms' (which enumerates ALL platforms)
$parameterAttribute = [System.Management.Automation.ParameterAttribute]@{
ParameterSetName = "listruntime"
Mandatory = $false
@@ -2024,8 +2503,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
@@ -2041,8 +2531,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
@@ -2087,7 +2590,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", "platforms", "help")
if (-not($known_actions -contains $action)) {
write-host "action '$action' not understood. Known_actions: $known_actions"
exit 1
@@ -2119,16 +2622,56 @@ function psmain {
}
switch ($action) {
'fetch' {
- $arch = "win32-x86_64"
- $archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
+ $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"]
+ } else {
+ #no name given: consult the server's curated defaults.txt - the
+ #punkbin release recommendation (updated there as part of each
+ #publication change-set; see punkbin AGENTS.md). Per-platform
+ #server data, so it works for any -platform, not just local.
+ $defaultsurl = "$artifacturl/defaults.txt"
+ $defaultslocal = Join-Path -Path $rtfolder -ChildPath "defaults.txt"
+ if (-not (Test-Path -Path $rtfolder -PathType Container)) {
+ new-item -Path $rtfolder -ItemType Directory -force | out-null
+ }
+ try {
+ Invoke-WebRequest -Uri $defaultsurl -OutFile $defaultslocal -ErrorAction Stop
+ } catch {
+ if (Test-Path -Path $defaultslocal -PathType Leaf) {
+ Write-Host "WARNING: could not fetch ${defaultsurl}: $($_.Exception.Message)"
+ Write-Host "WARNING: using cached copy at $defaultslocal"
+ } else {
+ Write-Host "Could not fetch ${defaultsurl}: $($_.Exception.Message)"
+ Write-Host "No server default available - name a runtime explicitly:"
+ Write-Host " punk-runtime.cmd fetch ?-platform ${arch}?"
+ Write-Host " (see available names: punk-runtime.cmd list -remote -platform $arch)"
+ exit 1
+ }
+ }
+ foreach ($line in (Get-Content -Path $defaultslocal)) {
+ $line = $line.Trim()
+ if ($line -eq "" -or $line.StartsWith("#")) { continue }
+ $parts = -split $line
+ if ($parts.Count -ge 2 -and $parts[0] -eq $arch) {
+ $runtime = $parts[1]
+ break
+ }
+ }
+ if ($runtime -eq "") {
+ Write-Host "No default recorded for platform '$arch' in the server's defaults.txt - name a runtime explicitly:"
+ Write-Host " punk-runtime.cmd fetch ?-platform ${arch}?"
+ Write-Host " (see available names: punk-runtime.cmd list -remote -platform $arch)"
+ exit 1
+ }
+ Write-Host "using server default for ${arch}: $runtime"
}
$fileurl = "$archurl/$runtime"
@@ -2212,6 +2755,19 @@ function psmain {
Write-Host "Local copy of runtime at $output seems to match sha1 checksum of file on server."
Write-Host "No download required"
}
+ #G-103: family artifacts (-r names) carry a metadata toml alongside
+ #on the server - fetch it too; absence is fine (pre-family runtimes)
+ if ($runtime -match '^(.*)-r([0-9]+)(\.[Ee][Xx][Ee])?$') {
+ $tomlname = (Get-PunkRuntimeRootName $runtime) + ".toml"
+ $tomlurl = "$archurl/$tomlname"
+ $tomllocal = Join-Path -Path $archfolder -ChildPath $tomlname
+ try {
+ Invoke-WebRequest -Uri $tomlurl -OutFile $tomllocal -ErrorAction Stop
+ Write-Host "artifact metadata saved at $tomllocal"
+ } catch {
+ Write-Host "no artifact metadata toml on server for $runtime (ok for pre-family runtimes)"
+ }
+ }
#first fetch establishes the active runtime; later fetches never steal it
if ((Get-PunkActiveRuntime $archfolder) -eq "") {
Set-PunkActiveRuntime $archfolder $runtime
@@ -2227,8 +2783,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 = ""
@@ -2236,8 +2795,8 @@ function psmain {
$rtname = $PSBoundParameters["runtime"]
}
if ($rtname -eq "") {
- write-host "Usage: punk-runtime.cmd use "
- write-host "Installed candidates:"
+ write-host "Usage: punk-runtime.cmd use ?-platform ?"
+ write-host "Installed candidates ($arch):"
foreach ($f in $candidates) {
write-host " $($f.Name)"
}
@@ -2255,13 +2814,42 @@ function psmain {
}
exit 1
}
- Set-PunkActiveRuntime $archfolder $rtname
+ #G-103 artifact-tier names (-r, immutable): 'use' MATERIALIZES the
+ #artifact into its WORKING name (name minus -r - what mapvfs and
+ #projects reference), copies its metadata toml alongside, and selects
+ #the working name. Republishing artifacts never churns consumers.
+ $am = [regex]::Match($rtname, '^(.*)-r([0-9]+)(\.[Ee][Xx][Ee])?$')
+ if ($am.Success) {
+ $working = $am.Groups[1].Value + $am.Groups[3].Value
+ $srcexe = Join-Path -Path $archfolder -ChildPath $rtname
+ $destexe = Join-Path -Path $archfolder -ChildPath $working
+ Copy-Item -Path $srcexe -Destination $destexe -Force
+ $srctoml = Join-Path -Path $archfolder -ChildPath ((Get-PunkRuntimeRootName $rtname) + ".toml")
+ $desttoml = Join-Path -Path $archfolder -ChildPath ((Get-PunkRuntimeRootName $working) + ".toml")
+ if (Test-Path -Path $srctoml -PathType Leaf) {
+ Copy-Item -Path $srctoml -Destination $desttoml -Force
+ write-host "materialized $working from artifact $rtname (metadata toml copied alongside)"
+ } else {
+ write-host "materialized $working from artifact $rtname (no metadata toml found beside the artifact)"
+ }
+ Set-PunkActiveRuntime $archfolder $working
+ } else {
+ Set-PunkActiveRuntime $archfolder $rtname
+ }
}
'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"
@@ -2337,9 +2925,9 @@ function psmain {
}
}
'list' {
- #todo - option to list for other os-arch
- $arch = 'win32-x86_64'
- $archfolder = Join-Path -Path $rtfolder -ChildPath "$arch"
+ #-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"
$sha1url = "$archurl/sha1sums.txt"
@@ -2380,7 +2968,12 @@ function psmain {
$localdict = @{}
if (test-path -Path $archfolder -Type Container) {
- $dircontents = (get-childItem -Path $archfolder -File | Where-object Name -Notlike '*_BUILDCOPY.*' | Where-object {-not ($(".txt",".tm") -contains $_.Extension) })
+ #shared candidate filter (bash payload parity - its -remote loop
+ #already uses list_candidates): excludes directories, build
+ #copies and .txt/.toml/.tm/.tmp/.log support files, so
+ #active.toml / metadata tomls / stray logs never show as
+ #local runtimes in the comparison
+ $dircontents = Get-PunkRuntimeCandidates $archfolder
foreach ($f in $dircontents) {
$local_sha1 = Get-FileHash -Path $(${f}.FullName) -Algorithm SHA1
$localdict[$f.Name] = ${local_sha1}.Hash
@@ -2438,10 +3031,12 @@ function psmain {
write-host "$(${dircontents}.count) runtime(s) in $archfolder"
Write-host "-----------------------------------------------------------------------"
foreach ($f in $dircontents) {
+ $meta = Get-PunkRuntimeMetadataSummary $archfolder $f.Name $arch
+ $lhs = "$($f.Name)".PadRight(35, ' ')
if ($f.Name -eq $activename) {
- write-host "* $($f.Name) (active)"
+ write-host "* $lhs (active) $meta"
} else {
- write-host " $($f.Name)"
+ write-host " $lhs $meta"
}
}
Write-host "-----------------------------------------------------------------------"
@@ -2450,20 +3045,100 @@ function psmain {
}
Write-host "Use: 'list -remote' to compare local runtimes with those available on the artifact server"
Write-host "Use: 'use ' to select the runtime that 'run' launches"
+ Write-host "Use: 'use -name>' to materialize an immutable -r artifact into its working name and select it"
} else {
write-host "No runtimes seem to be installed for $arch in $archfolder`nPlease use 'punk-runtime.cmd fetch' to install."
write-host "Use 'punk-runtime.cmd list -remote' to see available runtimes for $arch"
}
}
}
- default {
- $actions = @("fetch", "list", "use", "run")
- write-host "Available actions: $actions"
- write-host "received"
- foreach ($boundparam in $PSBoundParameters.opts) {
- write-host $boundparam
+ 'platforms' {
+ #enumerate platform folders: local (bin/runtime/*) and, with
+ #-remote, the server's platforms.txt discovery manifest (raw-file
+ #servers have no directory listing - the manifest is part of the
+ #punkbin layout contract; third-party mirrors carry the same file)
+ $localdirs = @()
+ if (Test-Path -Path $rtfolder -PathType Container) {
+ $localdirs = @(Get-ChildItem -Path $rtfolder -Directory | Select-Object -ExpandProperty Name | Sort-Object)
+ }
+ if ( $PSBoundParameters.ContainsKey('remote') ) {
+ $manifesturl = "$artifacturl/platforms.txt"
+ $manifestlocal = Join-Path -Path $rtfolder -ChildPath "platforms.txt"
+ if (-not (Test-Path -Path $rtfolder -PathType Container)) {
+ new-item -Path $rtfolder -ItemType Directory -force | out-null
+ }
+ try {
+ Invoke-WebRequest -Uri $manifesturl -OutFile $manifestlocal -ErrorAction Stop
+ Write-Host "Fetched $manifesturl"
+ } catch {
+ if (Test-Path -Path $manifestlocal -PathType Leaf) {
+ Write-Host "WARNING: could not fetch ${manifesturl}: $($_.Exception.Message)"
+ Write-Host "WARNING: using cached copy at $manifestlocal"
+ } else {
+ Write-Host "No platforms.txt available from ${manifesturl}: $($_.Exception.Message)"
+ Write-Host "(pre-convention punkbin or third-party mirror without the discovery manifest)"
+ Write-Host "Name platforms explicitly with -platform; canonical names: 'help platforms' in the punk shell"
+ exit 1
+ }
+ }
+ $remoteplatforms = @()
+ foreach ($line in (Get-Content -Path $manifestlocal)) {
+ $line = $line.Trim()
+ if ($line -eq "" -or $line.StartsWith("#")) { continue }
+ $remoteplatforms += $line
+ }
+ Write-host "-----------------------------------------------------------------------"
+ Write-Host "Platforms served by $artifacturl"
+ Write-host "-----------------------------------------------------------------------"
+ foreach ($p in $remoteplatforms) {
+ $marks = @()
+ if ($p -eq $script:PunkLocalPlatform) { $marks += "local platform" }
+ if ($localdirs -contains $p) { $marks += "local dir present" }
+ $lhs = "$p".PadRight(25, ' ')
+ if ($marks.Count -gt 0) {
+ write-host " $lhs ($($marks -join ', '))"
+ } else {
+ write-host " $lhs"
+ }
+ }
+ foreach ($d in $localdirs) {
+ if (-not ($remoteplatforms -contains $d)) {
+ $lhs = "$d".PadRight(25, ' ')
+ write-host " $lhs (local dir only - not served remotely)"
+ }
+ }
+ Write-host "-----------------------------------------------------------------------"
+ Write-Host "Use: 'list -remote -platform ' to see a platform's runtimes"
+ } else {
+ Write-host "-----------------------------------------------------------------------"
+ Write-Host "Local platform folders under $rtfolder"
+ Write-host "-----------------------------------------------------------------------"
+ if ($localdirs.Count -eq 0) {
+ write-host " (none - 'fetch' creates the local platform's folder)"
+ }
+ foreach ($d in $localdirs) {
+ $lhs = "$d".PadRight(25, ' ')
+ if ($d -eq $script:PunkLocalPlatform) {
+ write-host "* $lhs (local platform)"
+ } else {
+ write-host " $lhs"
+ }
+ }
+ Write-host "-----------------------------------------------------------------------"
+ Write-Host "Use: 'platforms -remote' to see platforms served by the artifact server"
+ Write-Host "Canonical platform names: 'help platforms' in the punk shell"
}
}
+ 'help' {
+ Show-PunkRuntimeHelp
+ }
+ 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."
+ }
}
return $PSBoundParameters