Browse Source

make.tcl-generated outputs: layout sync copies of the tool subcommand

Thin-layout sync (part of the bootsupport run): the project-layout
make.tcl copies (vendor/punk/basic, vendor/punk/project-0.1, and the
punk::mix::templates modpod source tree) pick up the G-126 'tool'
subcommand from d76a7907 via the punkcheck-managed sync step. No hand
edits.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 4 days ago
parent
commit
25b3dcc667
  1. 411
      src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl
  2. 411
      src/project_layouts/vendor/punk/basic/src/make.tcl
  3. 411
      src/project_layouts/vendor/punk/project-0.1/src/make.tcl

411
src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl vendored

@ -187,7 +187,7 @@ namespace eval ::punkboot {
variable foldername [file tail $scriptfolder] variable foldername [file tail $scriptfolder]
variable pkg_requirements [list]; variable pkg_missing [list];variable pkg_loaded [list] variable pkg_requirements [list]; variable pkg_missing [list];variable pkg_loaded [list]
variable help_flags [list -help --help /? -h] variable help_flags [list -help --help /? -h]
variable known_commands [list bakehouse packages modules libs bake bakelist vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow buildsuite project vfs] variable known_commands [list bakehouse packages modules libs bake bakelist vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow buildsuite tool project vfs]
} }
@ -2152,6 +2152,11 @@ proc ::punkboot::punkboot_gethelp {args} {
append h " $scriptname buildsuite list|info|build ?<suitename>? ?driver-args ...?" \n append h " $scriptname buildsuite list|info|build ?<suitename>? ?driver-args ...?" \n
append h " - list the defined buildsuites under src/buildsuites (zig runtime factory), show a suite's configured" \n append h " - list the defined buildsuites under src/buildsuites (zig runtime factory), show a suite's configured" \n
append h " detail (sources/zig pin/products from its sources.config), or run its driver forwarding the args" \n \n append h " detail (sources/zig pin/products from its sources.config), or run its driver forwarding the args" \n \n
append h " $scriptname tool list|info|build|test ?<toolname> ...? ?-test 0|1?" \n
append h " - vendored first-party build tools under src/tools (zig source; G-126): list/detail them, run their" \n
append h " test suites, or build (test-gated) and install to <projectdir>/bin" \n
append h " - zig is OPTIONAL: packages/bake never require this step; without a suitable toolchain the state is" \n
append h " reported and build/test exit nonzero with fetch guidance (bin/punk-getzig.cmd)" \n \n
append h " $scriptname help ?subcommand?" \n append h " $scriptname help ?subcommand?" \n
append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname <subcommand> -help)" \n \n append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname <subcommand> -help)" \n \n
append h " Deprecated aliases (transition window):" \n append h " Deprecated aliases (transition window):" \n
@ -2402,6 +2407,14 @@ KEY / NOTES
with binary dependencies, and version-preference outcomes are visible only to with binary dependencies, and version-preference outcomes are visible only to
the smoke probe - and only for declared packages. 'make.tcl check' reports both. the smoke probe - and only for declared packages. 'make.tcl check' reports both.
OUT-OF-BAND SUBSYSTEMS (not part of the packages/bake data flow above)
'make.tcl tool' builds the vendored first-party zig tools under src/tools
(G-126; punkzip first) into <projectdir>/bin, gated on each tree's own
'zig build test' exit code. zig is OPTIONAL: packages/bake never require it.
'make.tcl buildsuite' is the analogous arm's-length factory for whole Tcl
runtimes built from EXTERNAL sources under src/buildsuites (fetch + test-gate
contract per suite; products land in the bin/runtime store tiers).
MAINTENANCE (agents take note) MAINTENANCE (agents take note)
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
This text is embedded in make.tcl (::punkboot::workflow_text). When the build This text is embedded in make.tcl (::punkboot::workflow_text). When the build
@ -2514,6 +2527,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
shell "Run the punk shell using bootsupport libraries" shell "Run the punk shell using bootsupport libraries"
help "Show usage for make.tcl or one of its subcommands" help "Show usage for make.tcl or one of its subcommands"
buildsuite "List, describe or run the defined buildsuites under src/buildsuites (zig runtime factory)" buildsuite "List, describe or run the defined buildsuites under src/buildsuites (zig runtime factory)"
tool "List, test or build the vendored tools under src/tools (zig) and install them to <projectdir>/bin"
project "DEPRECATED alias for bakehouse (one-line notice, then runs bakehouse)" project "DEPRECATED alias for bakehouse (one-line notice, then runs bakehouse)"
vfs "DEPRECATED alias for bake (one-line notice, then runs bake)" vfs "DEPRECATED alias for bake (one-line notice, then runs bake)"
} }
@ -2683,6 +2697,45 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
(copy-and-tweak workflow) appears here automatically with no (copy-and-tweak workflow) appears here automatically with no
make.tcl edits. The contract is documented in make.tcl edits. The contract is documented in
src/buildsuites/README.md." src/buildsuites/README.md."
tool
"
Surface for the vendored first-party build tools under src/tools
(G-126: zig source vendored in full; boundary and editing policy in
src/tools/AGENTS.md, per-tree origin/licence records in
<tool>/PROVENANCE.md). Discovery is convention-based: a directory
under src/tools carrying build.zig is a tool; its installed
artifact is <projectdir>/bin/<name> with the host executable
suffix.
Actions:
tool list
Discover the tools with version (build.zig.zon), declared zig
floor, installed-binary state (current|stale|absent) and the
vendored upstream commit; report the resolved toolchain.
tool info <name> ...
Per-tool detail: paths, provenance records, toolchain
resolution.
tool build ?<name> ...? ?-test 0|1?
Resolve a zig satisfying the tool's declared floor, run the
'zig build test' gate (default on; the gate is the EXIT CODE -
expected warnings on stderr do not fail it), build ReleaseSafe
and install to <projectdir>/bin. Nothing is installed when the
gate or the build fails. With no name, all tools are
processed.
tool test ?<name> ...?
Run each tool's 'zig build test' only.
Toolchain resolution: PUNK_ZIG=<path-to-zig-or-its-folder>
overrides; otherwise <projectdir>/bin/tools/zig* is scanned and
the LOWEST release satisfying the floor wins (deterministic as
newer toolchains appear beside the pinned one; dev builds count
only when their base version exceeds the floor). zig is OPTIONAL
for punkshell builds: packages/bake never require this step -
without a suitable toolchain, list reports the state and
build/test exit nonzero with fetch guidance
(bin/punk-getzig.cmd). Build caches (.zig-cache/zig-out) are
deliberately left in place between runs for rebuild speed (both
git- and fossil-ignored)."
project project
" "
DEPRECATED alias for 'bakehouse' (G-112 stage-true rename) - prints a DEPRECATED alias for 'bakehouse' (G-112 stage-true rename) - prints a
@ -2855,6 +2908,15 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
arg -type any -optional 1 -multiple 1 -help\ arg -type any -optional 1 -multiple 1 -help\
"Action (list|info|build), suite name, and - for build - driver "Action (list|info|build), suite name, and - for build - driver
arguments forwarded to the suite's suite.tcl untouched."} arguments forwarded to the suite's suite.tcl untouched."}
punk::args::define\
"@id -id (script)::punkboot::tool"\
"@normalize"\
"@cmd -name [list "make.tcl tool"] -summary [list [dict get $SUMMARIES tool]] -help [list [dict get $HELPTEXTS tool]]"\
{@form -synopsis "make.tcl tool list|info|build|test ?<toolname> ...? ?-test 0|1?"}\
{@values -min 0 -max -1
arg -type any -optional 1 -multiple 1 -help\
"Action (list|info|build|test), tool name(s), and - for build -
the -test 0|1 gate flag. Parsed by the handler."}
punk::args::define\ punk::args::define\
"@id -id (script)::punkboot::help"\ "@id -id (script)::punkboot::help"\
"@normalize"\ "@normalize"\
@ -2871,6 +2933,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
"promotion gates" {bootsupport vfscommonupdate} "promotion gates" {bootsupport vfscommonupdate}
"source maintenance" {vendorupdate} "source maintenance" {vendorupdate}
"buildsuites" {buildsuite} "buildsuites" {buildsuite}
"vendored tools" {tool}
"informational" {info check bakelist projectversion workflow help} "informational" {info check bakelist projectversion workflow help}
"interactive" {shell} "interactive" {shell}
"deprecated aliases" {project vfs} "deprecated aliases" {project vfs}
@ -2963,6 +3026,10 @@ if {$::punkboot::punkargs_ok} {
#args (arbitrary suite flags) are forwarded untouched (G-104) #args (arbitrary suite flags) are forwarded untouched (G-104)
set ::punkboot::command buildsuite set ::punkboot::command buildsuite
set ::punkboot::bs_args $subargs set ::punkboot::bs_args $subargs
} elseif {$subcommand eq "tool"} {
#declared passthrough: the handler parses action/names/-test itself (G-126)
set ::punkboot::command tool
set ::punkboot::tool_args $subargs
} else { } else {
if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::$subcommand} argd]} { if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::$subcommand} argd]} {
puts stderr $argd puts stderr $argd
@ -2993,6 +3060,12 @@ if {$::punkboot::punkargs_ok} {
set commands_found [list buildsuite] set commands_found [list buildsuite]
set argsleft [list] set argsleft [list]
set ::punkboot::bs_args [lrange $scriptargs 1 end] set ::punkboot::bs_args [lrange $scriptargs 1 end]
} elseif {[lindex $scriptargs 0] eq "tool"} {
#declared passthrough (as in the punk::args path) - the handler parses
#action/names/-test itself (G-126)
set commands_found [list tool]
set argsleft [list]
set ::punkboot::tool_args [lrange $scriptargs 1 end]
} }
while {[llength $argsleft]} { while {[llength $argsleft]} {
set a [lindex $argsleft 0] set a [lindex $argsleft 0]
@ -3116,7 +3189,8 @@ set forcekill $::punkboot::opt_forcekill
# - patch bump -> warn and proceed (non-breaking) # - patch bump -> warn and proceed (non-breaking)
# 'check' is exempt in all cases the warning is shown at the end of its output instead. # 'check' is exempt in all cases the warning is shown at the end of its output instead.
# 'projectversion', 'workflow' and 'bakelist' are informational/read-only and are likewise exempt. # 'projectversion', 'workflow' and 'bakelist' are informational/read-only and are likewise exempt.
if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ni {check projectversion workflow bakelist buildsuite}} { # 'buildsuite' and 'tool' are arm's-length subsystems that do not consume bootsupport modules.
if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ni {check projectversion workflow bakelist buildsuite tool}} {
set _stale $::punkboot::stale_bootsupport set _stale $::punkboot::stale_bootsupport
set _have_major 0 set _have_major 0
set _have_minor 0 set _have_minor 0
@ -4242,6 +4316,339 @@ if {$::punkboot::command eq "buildsuite"} {
} }
} }
if {$::punkboot::command eq "tool"} {
#G-126: vendored first-party build tools under src/tools (zig source vendored in
#full - boundary and editing policy in src/tools/AGENTS.md; per-tree origin,
#re-vendor procedure and licence records in <tool>/PROVENANCE.md). Discovery is
#convention-based: a directory under src/tools carrying build.zig is a tool, its
#name is the directory name, its build artifact is <tooldir>/zig-out/bin/<name>
#and its installed copy is <projectdir>/bin/<name> (host executable suffix).
#zig stays OPTIONAL for punkshell builds: nothing in packages/bake depends on
#this step; explicit build/test without a suitable toolchain exits nonzero with
#fetch guidance. Build caches (.zig-cache/zig-out) are deliberately left in
#place between builds for rebuild speed (both git- and fossil-ignored).
set tool_root [file join $sourcefolder tools]
if {![info exists ::punkboot::tool_args]} {set ::punkboot::tool_args [list]}
set targs $::punkboot::tool_args
set tool_action [lindex $targs 0]
if {$tool_action eq ""} {set tool_action list}
#args after the action: tool names plus an optional '-test 0|1' flag (build)
set tool_dotest 1
set tool_names [list]
set _i 1
while {$_i < [llength $targs]} {
set a [lindex $targs $_i]
if {$a eq "-test"} {
incr _i
set v [lindex $targs $_i]
if {![string is boolean -strict $v]} {
puts stderr "make.tcl tool: -test requires a boolean value (got '$v')"
exit 2
}
set tool_dotest [expr {bool($v)}]
} else {
lappend tool_names $a
}
incr _i
}
unset -nocomplain _i a v
proc ::punkboot::tool_dirs {tool_root} {
set dirs [list]
foreach dir [lsort [glob -nocomplain -dir $tool_root -type d *]] {
if {![file exists [file join $dir build.zig]]} {continue} ;#not a tool
lappend dirs $dir
}
return $dirs
}
#tolerant build.zig.zon reader: tool version + declared minimum zig version
proc ::punkboot::tool_zoninfo {tooldir} {
set m [dict create version "" zigfloor ""]
if {![catch {
set f [open [file join $tooldir build.zig.zon] r]
set data [read $f]
close $f
}]} {
if {[regexp {\.version\s*=\s*"([^"]+)"} $data -> _v]} {dict set m version $_v}
if {[regexp {\.minimum_zig_version\s*=\s*"([^"]+)"} $data -> _fl]} {dict set m zigfloor $_fl}
}
return $m
}
#tolerant PROVENANCE.md reader: vendored upstream commit + upstream location
proc ::punkboot::tool_provenance {tooldir} {
set m [dict create commit "" upstream ""]
if {![catch {
set f [open [file join $tooldir PROVENANCE.md] r]
set data [read $f]
close $f
}]} {
if {[regexp {Vendored state: commit\s+`?([0-9a-fA-F]{7,40})} $data -> _c]} {dict set m commit $_c}
if {[regexp {Upstream repository:\s+`?([^`\n]+)} $data -> _u]} {dict set m upstream [string trim $_u]}
}
return $m
}
proc ::punkboot::tool_newest_src_mtime {dir} {
set newest 0
foreach f [glob -nocomplain -dir $dir -type f *] {
if {[file mtime $f] > $newest} {set newest [file mtime $f]}
}
foreach d [glob -nocomplain -dir $dir -type d *] {
if {[file tail $d] in {zig-out .zig-cache zig-cache}} {continue}
set sub [::punkboot::tool_newest_src_mtime $d]
if {$sub > $newest} {set newest $sub}
}
return $newest
}
proc ::punkboot::tool_zig_version {zigexe} {
if {[catch {exec $zigexe version 2>@1} v]} {return ""}
return [string trim [lindex [split $v \n] 0]]
}
#a dev build's base version must EXCEED the floor (e.g 0.16.0-dev < 0.16.0)
proc ::punkboot::tool_zig_satisfies {ver floor} {
if {$floor eq ""} {return 1}
set base $ver ; set isdev 0
if {[regexp {^([0-9][0-9.]*)[-+]} $ver -> b]} {set base $b ; set isdev 1}
if {[catch {package vcompare $base $floor} cmp]} {return 0}
if {$cmp > 0} {return 1}
if {$cmp == 0 && !$isdev} {return 1}
return 0
}
#resolve a zig for the given floor: PUNK_ZIG env override (path to the zig
#executable or its folder), else scan <projectdir>/bin/tools/zig* preferring
#releases over dev builds and the LOWEST satisfying version - a deterministic
#choice that stays stable as newer toolchains get unpacked beside the pinned one
proc ::punkboot::tool_resolve_zig {projectroot floor} {
if {[info exists ::env(PUNK_ZIG)] && $::env(PUNK_ZIG) ne ""} {
set cand $::env(PUNK_ZIG)
if {[file isdirectory $cand]} {
foreach n {zig.exe zig} {
if {[file exists [file join $cand $n]]} {set cand [file join $cand $n] ; break}
}
}
set v [::punkboot::tool_zig_version $cand]
if {$v eq ""} {
return [dict create note "PUNK_ZIG='$::env(PUNK_ZIG)' did not answer 'zig version'"]
}
if {![::punkboot::tool_zig_satisfies $v $floor]} {
return [dict create note "PUNK_ZIG zig is $v which does not satisfy this tool's floor (>= $floor)"]
}
return [dict create zig $cand version $v via PUNK_ZIG]
}
set best "" ; set bestv "" ; set bestbase "" ; set bestdev 1
foreach dir [lsort [glob -nocomplain -dir [file join $projectroot bin tools] -type d zig*]] {
set p ""
foreach n {zig.exe zig} {
if {[file exists [file join $dir $n]]} {set p [file join $dir $n] ; break}
}
if {$p eq ""} {continue}
set v [::punkboot::tool_zig_version $p]
if {$v eq "" || ![::punkboot::tool_zig_satisfies $v $floor]} {continue}
set base $v ; set isdev 0
if {[regexp {^([0-9][0-9.]*)[-+]} $v -> b]} {set base $b ; set isdev 1}
set take 0
if {$best eq ""} {
set take 1
} elseif {$bestdev && !$isdev} {
set take 1
} elseif {$bestdev == $isdev && [package vcompare $base $bestbase] < 0} {
set take 1
}
if {$take} {set best $p ; set bestv $v ; set bestbase $base ; set bestdev $isdev}
}
if {$best eq ""} {
set want [expr {$floor eq "" ? "any version" : ">= $floor"}]
return [dict create note "no suitable zig toolchain ($want) under [file join $projectroot bin tools] - 'bin/punk-getzig.cmd <version>' fetches one; PUNK_ZIG=<path-to-zig> overrides"]
}
return [dict create zig $best version $bestv via scan]
}
proc ::punkboot::tool_installed_exe {projectroot name} {
set suffix [punkboot::lib::platform_exe_suffix $::punkboot::target_platform]
return [file join $projectroot bin ${name}$suffix]
}
proc ::punkboot::tool_install_state {projectroot tooldir} {
set exe [::punkboot::tool_installed_exe $projectroot [file tail $tooldir]]
if {![file exists $exe]} {return absent}
if {[file mtime $exe] >= [::punkboot::tool_newest_src_mtime $tooldir]} {return current}
return stale
}
#run 'zig <argl>' with cwd at the tool tree (the tree's CLI tests resolve
#fixtures and zig-out relative to the build root). The gate is the EXIT CODE:
#stderr legitimately carries expected warnings (punkzip's zip suite negative
#tests print EOCD warnings while passing). Returns the child's exit status.
proc ::punkboot::tool_zig_run {zig tooldir argl} {
set saved [pwd]
cd $tooldir
set rc 0
if {[catch {exec $zig {*}$argl >@stdout 2>@stderr} _e _o]} {
set ecode [dict get $_o -errorcode]
if {[lindex $ecode 0] eq "CHILDSTATUS"} {
set rc [lindex $ecode 2]
} else {
puts stderr "tool: failed to run '$zig $argl' in $tooldir: $_e"
set rc 1
}
}
cd $saved
return $rc
}
set alldirs [::punkboot::tool_dirs $tool_root]
set byname [dict create]
foreach d $alldirs {dict set byname [file tail $d] $d}
if {[llength $tool_names]} {
set selected [list]
foreach n $tool_names {
if {![dict exists $byname $n]} {
puts stderr "tool '$n' not found under $tool_root - configured tools: [dict keys $byname]"
exit 2
}
lappend selected [dict get $byname $n]
}
} else {
set selected $alldirs
}
if {![llength $alldirs] && $tool_action ne "list"} {
puts stderr "no vendored tools found under $tool_root (a tool = a directory carrying build.zig)"
exit 2
}
switch -- $tool_action {
list {
if {![llength $alldirs]} {
puts stdout "no vendored tools found under $tool_root (a tool = a directory carrying build.zig)"
exit 0
}
puts stdout "vendored tools under $tool_root (boundary: src/tools/AGENTS.md; per-tree PROVENANCE.md):"
puts stdout [format " %-10s %-9s %-10s %-8s %s" name version zig-floor bin vendored-commit]
set maxfloor ""
foreach dir $alldirs {
set name [file tail $dir]
set zon [::punkboot::tool_zoninfo $dir]
set prov [::punkboot::tool_provenance $dir]
set floor [dict get $zon zigfloor]
if {$floor ne "" && ($maxfloor eq "" || [package vcompare $floor $maxfloor] > 0)} {
set maxfloor $floor
}
set commit [dict get $prov commit]
set commit [expr {$commit eq "" ? "-" : [string range $commit 0 11]}]
set floorshow [expr {$floor eq "" ? "-" : ">=$floor"}]
puts stdout [format " %-10s %-9s %-10s %-8s %s" $name [dict get $zon version] $floorshow [::punkboot::tool_install_state $projectroot $dir] $commit]
}
set zres [::punkboot::tool_resolve_zig $projectroot $maxfloor]
if {[dict exists $zres zig]} {
puts stdout "toolchain: zig [dict get $zres version] via [dict get $zres via] ([dict get $zres zig])"
} else {
puts stdout "toolchain: [dict get $zres note]"
}
puts stdout ""
puts stdout " - 'make.tcl tool info <name>' shows a tool's detail"
puts stdout " - 'make.tcl tool build ?<name> ...? ?-test 0|1?' builds (test-gated) and installs to bin/"
puts stdout " - zig is OPTIONAL for punkshell builds: packages/bake never require this step"
exit 0
}
info {
if {![llength $tool_names]} {
puts stderr "usage: make.tcl tool info <toolname> ('make.tcl tool list' shows the names)"
exit 2
}
foreach dir $selected {
set name [file tail $dir]
set zon [::punkboot::tool_zoninfo $dir]
set prov [::punkboot::tool_provenance $dir]
set floor [dict get $zon zigfloor]
puts stdout "tool: $name"
puts stdout " path: $dir"
puts stdout " version: [dict get $zon version] (build.zig.zon)"
puts stdout " zig floor: [expr {$floor eq "" ? "(none declared)" : ">= $floor"}]"
puts stdout " upstream: [expr {[dict get $prov upstream] eq "" ? "(no PROVENANCE.md record)" : [dict get $prov upstream]}]"
puts stdout " vendored commit: [expr {[dict get $prov commit] eq "" ? "(no PROVENANCE.md record)" : [dict get $prov commit]}]"
puts stdout " provenance: [file join $dir PROVENANCE.md]"
set exe [::punkboot::tool_installed_exe $projectroot $name]
puts stdout " installed: $exe ([::punkboot::tool_install_state $projectroot $dir])"
set zres [::punkboot::tool_resolve_zig $projectroot $floor]
if {[dict exists $zres zig]} {
puts stdout " toolchain: zig [dict get $zres version] via [dict get $zres via] ([dict get $zres zig])"
} else {
puts stdout " toolchain: [dict get $zres note]"
}
}
exit 0
}
build {
foreach dir $selected {
set name [file tail $dir]
set floor [dict get [::punkboot::tool_zoninfo $dir] zigfloor]
set zres [::punkboot::tool_resolve_zig $projectroot $floor]
if {![dict exists $zres zig]} {
puts stderr "tool build $name: [dict get $zres note]"
exit 1
}
set zig [dict get $zres zig]
puts stdout "tool build $name: zig [dict get $zres version] via [dict get $zres via] ($zig)"
flush stdout
if {$tool_dotest} {
puts stdout "tool build $name: test gate ('zig build test') ..."
flush stdout
set rc [::punkboot::tool_zig_run $zig $dir [list build test]]
if {$rc != 0} {
puts stderr "tool build $name: test gate FAILED (exit $rc) - nothing installed"
exit 1
}
puts stdout "tool build $name: test gate passed"
} else {
puts stdout "tool build $name: test gate SKIPPED (-test 0)"
}
puts stdout "tool build $name: building (ReleaseSafe) ..."
flush stdout
set rc [::punkboot::tool_zig_run $zig $dir [list build -Doptimize=ReleaseSafe]]
if {$rc != 0} {
puts stderr "tool build $name: build FAILED (exit $rc) - nothing installed"
exit 1
}
set suffix [punkboot::lib::platform_exe_suffix $::punkboot::target_platform]
set built [file join $dir zig-out bin ${name}$suffix]
if {![file exists $built]} {
puts stderr "tool build $name: build reported success but $built is missing"
exit 1
}
set exe [::punkboot::tool_installed_exe $projectroot $name]
if {[catch {file copy -force $built $exe} cperr]} {
puts stderr "tool build $name: could not install $exe ($cperr) - is a copy currently running?"
exit 1
}
puts stdout "tool build $name: installed $exe ([file size $exe] bytes)"
}
exit 0
}
test {
foreach dir $selected {
set name [file tail $dir]
set floor [dict get [::punkboot::tool_zoninfo $dir] zigfloor]
set zres [::punkboot::tool_resolve_zig $projectroot $floor]
if {![dict exists $zres zig]} {
puts stderr "tool test $name: [dict get $zres note]"
exit 1
}
set zig [dict get $zres zig]
puts stdout "tool test $name: zig [dict get $zres version] via [dict get $zres via] - running 'zig build test' ..."
flush stdout
set rc [::punkboot::tool_zig_run $zig $dir [list build test]]
if {$rc != 0} {
puts stderr "tool test $name: FAILED (exit $rc)"
exit 1
}
puts stdout "tool test $name: passed"
}
exit 0
}
default {
puts stderr "unknown tool action '$tool_action' - expected list|info|build|test"
puts stderr "usage: make.tcl tool list|info|build|test ?<toolname> ...? ?-test 0|1?"
exit 2
}
}
}
if {$::punkboot::command eq "shell"} { if {$::punkboot::command eq "shell"} {
#G-113: the ansistrip transform serves make.tcl's own output only - the repl's #G-113: the ansistrip transform serves make.tcl's own output only - the repl's
#colour behaviour is the shell's own concern (colour on/off + NO_COLOR there). #colour behaviour is the shell's own concern (colour on/off + NO_COLOR there).

411
src/project_layouts/vendor/punk/basic/src/make.tcl vendored

@ -187,7 +187,7 @@ namespace eval ::punkboot {
variable foldername [file tail $scriptfolder] variable foldername [file tail $scriptfolder]
variable pkg_requirements [list]; variable pkg_missing [list];variable pkg_loaded [list] variable pkg_requirements [list]; variable pkg_missing [list];variable pkg_loaded [list]
variable help_flags [list -help --help /? -h] variable help_flags [list -help --help /? -h]
variable known_commands [list bakehouse packages modules libs bake bakelist vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow buildsuite project vfs] variable known_commands [list bakehouse packages modules libs bake bakelist vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow buildsuite tool project vfs]
} }
@ -2152,6 +2152,11 @@ proc ::punkboot::punkboot_gethelp {args} {
append h " $scriptname buildsuite list|info|build ?<suitename>? ?driver-args ...?" \n append h " $scriptname buildsuite list|info|build ?<suitename>? ?driver-args ...?" \n
append h " - list the defined buildsuites under src/buildsuites (zig runtime factory), show a suite's configured" \n append h " - list the defined buildsuites under src/buildsuites (zig runtime factory), show a suite's configured" \n
append h " detail (sources/zig pin/products from its sources.config), or run its driver forwarding the args" \n \n append h " detail (sources/zig pin/products from its sources.config), or run its driver forwarding the args" \n \n
append h " $scriptname tool list|info|build|test ?<toolname> ...? ?-test 0|1?" \n
append h " - vendored first-party build tools under src/tools (zig source; G-126): list/detail them, run their" \n
append h " test suites, or build (test-gated) and install to <projectdir>/bin" \n
append h " - zig is OPTIONAL: packages/bake never require this step; without a suitable toolchain the state is" \n
append h " reported and build/test exit nonzero with fetch guidance (bin/punk-getzig.cmd)" \n \n
append h " $scriptname help ?subcommand?" \n append h " $scriptname help ?subcommand?" \n
append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname <subcommand> -help)" \n \n append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname <subcommand> -help)" \n \n
append h " Deprecated aliases (transition window):" \n append h " Deprecated aliases (transition window):" \n
@ -2402,6 +2407,14 @@ KEY / NOTES
with binary dependencies, and version-preference outcomes are visible only to with binary dependencies, and version-preference outcomes are visible only to
the smoke probe - and only for declared packages. 'make.tcl check' reports both. the smoke probe - and only for declared packages. 'make.tcl check' reports both.
OUT-OF-BAND SUBSYSTEMS (not part of the packages/bake data flow above)
'make.tcl tool' builds the vendored first-party zig tools under src/tools
(G-126; punkzip first) into <projectdir>/bin, gated on each tree's own
'zig build test' exit code. zig is OPTIONAL: packages/bake never require it.
'make.tcl buildsuite' is the analogous arm's-length factory for whole Tcl
runtimes built from EXTERNAL sources under src/buildsuites (fetch + test-gate
contract per suite; products land in the bin/runtime store tiers).
MAINTENANCE (agents take note) MAINTENANCE (agents take note)
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
This text is embedded in make.tcl (::punkboot::workflow_text). When the build This text is embedded in make.tcl (::punkboot::workflow_text). When the build
@ -2514,6 +2527,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
shell "Run the punk shell using bootsupport libraries" shell "Run the punk shell using bootsupport libraries"
help "Show usage for make.tcl or one of its subcommands" help "Show usage for make.tcl or one of its subcommands"
buildsuite "List, describe or run the defined buildsuites under src/buildsuites (zig runtime factory)" buildsuite "List, describe or run the defined buildsuites under src/buildsuites (zig runtime factory)"
tool "List, test or build the vendored tools under src/tools (zig) and install them to <projectdir>/bin"
project "DEPRECATED alias for bakehouse (one-line notice, then runs bakehouse)" project "DEPRECATED alias for bakehouse (one-line notice, then runs bakehouse)"
vfs "DEPRECATED alias for bake (one-line notice, then runs bake)" vfs "DEPRECATED alias for bake (one-line notice, then runs bake)"
} }
@ -2683,6 +2697,45 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
(copy-and-tweak workflow) appears here automatically with no (copy-and-tweak workflow) appears here automatically with no
make.tcl edits. The contract is documented in make.tcl edits. The contract is documented in
src/buildsuites/README.md." src/buildsuites/README.md."
tool
"
Surface for the vendored first-party build tools under src/tools
(G-126: zig source vendored in full; boundary and editing policy in
src/tools/AGENTS.md, per-tree origin/licence records in
<tool>/PROVENANCE.md). Discovery is convention-based: a directory
under src/tools carrying build.zig is a tool; its installed
artifact is <projectdir>/bin/<name> with the host executable
suffix.
Actions:
tool list
Discover the tools with version (build.zig.zon), declared zig
floor, installed-binary state (current|stale|absent) and the
vendored upstream commit; report the resolved toolchain.
tool info <name> ...
Per-tool detail: paths, provenance records, toolchain
resolution.
tool build ?<name> ...? ?-test 0|1?
Resolve a zig satisfying the tool's declared floor, run the
'zig build test' gate (default on; the gate is the EXIT CODE -
expected warnings on stderr do not fail it), build ReleaseSafe
and install to <projectdir>/bin. Nothing is installed when the
gate or the build fails. With no name, all tools are
processed.
tool test ?<name> ...?
Run each tool's 'zig build test' only.
Toolchain resolution: PUNK_ZIG=<path-to-zig-or-its-folder>
overrides; otherwise <projectdir>/bin/tools/zig* is scanned and
the LOWEST release satisfying the floor wins (deterministic as
newer toolchains appear beside the pinned one; dev builds count
only when their base version exceeds the floor). zig is OPTIONAL
for punkshell builds: packages/bake never require this step -
without a suitable toolchain, list reports the state and
build/test exit nonzero with fetch guidance
(bin/punk-getzig.cmd). Build caches (.zig-cache/zig-out) are
deliberately left in place between runs for rebuild speed (both
git- and fossil-ignored)."
project project
" "
DEPRECATED alias for 'bakehouse' (G-112 stage-true rename) - prints a DEPRECATED alias for 'bakehouse' (G-112 stage-true rename) - prints a
@ -2855,6 +2908,15 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
arg -type any -optional 1 -multiple 1 -help\ arg -type any -optional 1 -multiple 1 -help\
"Action (list|info|build), suite name, and - for build - driver "Action (list|info|build), suite name, and - for build - driver
arguments forwarded to the suite's suite.tcl untouched."} arguments forwarded to the suite's suite.tcl untouched."}
punk::args::define\
"@id -id (script)::punkboot::tool"\
"@normalize"\
"@cmd -name [list "make.tcl tool"] -summary [list [dict get $SUMMARIES tool]] -help [list [dict get $HELPTEXTS tool]]"\
{@form -synopsis "make.tcl tool list|info|build|test ?<toolname> ...? ?-test 0|1?"}\
{@values -min 0 -max -1
arg -type any -optional 1 -multiple 1 -help\
"Action (list|info|build|test), tool name(s), and - for build -
the -test 0|1 gate flag. Parsed by the handler."}
punk::args::define\ punk::args::define\
"@id -id (script)::punkboot::help"\ "@id -id (script)::punkboot::help"\
"@normalize"\ "@normalize"\
@ -2871,6 +2933,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
"promotion gates" {bootsupport vfscommonupdate} "promotion gates" {bootsupport vfscommonupdate}
"source maintenance" {vendorupdate} "source maintenance" {vendorupdate}
"buildsuites" {buildsuite} "buildsuites" {buildsuite}
"vendored tools" {tool}
"informational" {info check bakelist projectversion workflow help} "informational" {info check bakelist projectversion workflow help}
"interactive" {shell} "interactive" {shell}
"deprecated aliases" {project vfs} "deprecated aliases" {project vfs}
@ -2963,6 +3026,10 @@ if {$::punkboot::punkargs_ok} {
#args (arbitrary suite flags) are forwarded untouched (G-104) #args (arbitrary suite flags) are forwarded untouched (G-104)
set ::punkboot::command buildsuite set ::punkboot::command buildsuite
set ::punkboot::bs_args $subargs set ::punkboot::bs_args $subargs
} elseif {$subcommand eq "tool"} {
#declared passthrough: the handler parses action/names/-test itself (G-126)
set ::punkboot::command tool
set ::punkboot::tool_args $subargs
} else { } else {
if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::$subcommand} argd]} { if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::$subcommand} argd]} {
puts stderr $argd puts stderr $argd
@ -2993,6 +3060,12 @@ if {$::punkboot::punkargs_ok} {
set commands_found [list buildsuite] set commands_found [list buildsuite]
set argsleft [list] set argsleft [list]
set ::punkboot::bs_args [lrange $scriptargs 1 end] set ::punkboot::bs_args [lrange $scriptargs 1 end]
} elseif {[lindex $scriptargs 0] eq "tool"} {
#declared passthrough (as in the punk::args path) - the handler parses
#action/names/-test itself (G-126)
set commands_found [list tool]
set argsleft [list]
set ::punkboot::tool_args [lrange $scriptargs 1 end]
} }
while {[llength $argsleft]} { while {[llength $argsleft]} {
set a [lindex $argsleft 0] set a [lindex $argsleft 0]
@ -3116,7 +3189,8 @@ set forcekill $::punkboot::opt_forcekill
# - patch bump -> warn and proceed (non-breaking) # - patch bump -> warn and proceed (non-breaking)
# 'check' is exempt in all cases the warning is shown at the end of its output instead. # 'check' is exempt in all cases the warning is shown at the end of its output instead.
# 'projectversion', 'workflow' and 'bakelist' are informational/read-only and are likewise exempt. # 'projectversion', 'workflow' and 'bakelist' are informational/read-only and are likewise exempt.
if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ni {check projectversion workflow bakelist buildsuite}} { # 'buildsuite' and 'tool' are arm's-length subsystems that do not consume bootsupport modules.
if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ni {check projectversion workflow bakelist buildsuite tool}} {
set _stale $::punkboot::stale_bootsupport set _stale $::punkboot::stale_bootsupport
set _have_major 0 set _have_major 0
set _have_minor 0 set _have_minor 0
@ -4242,6 +4316,339 @@ if {$::punkboot::command eq "buildsuite"} {
} }
} }
if {$::punkboot::command eq "tool"} {
#G-126: vendored first-party build tools under src/tools (zig source vendored in
#full - boundary and editing policy in src/tools/AGENTS.md; per-tree origin,
#re-vendor procedure and licence records in <tool>/PROVENANCE.md). Discovery is
#convention-based: a directory under src/tools carrying build.zig is a tool, its
#name is the directory name, its build artifact is <tooldir>/zig-out/bin/<name>
#and its installed copy is <projectdir>/bin/<name> (host executable suffix).
#zig stays OPTIONAL for punkshell builds: nothing in packages/bake depends on
#this step; explicit build/test without a suitable toolchain exits nonzero with
#fetch guidance. Build caches (.zig-cache/zig-out) are deliberately left in
#place between builds for rebuild speed (both git- and fossil-ignored).
set tool_root [file join $sourcefolder tools]
if {![info exists ::punkboot::tool_args]} {set ::punkboot::tool_args [list]}
set targs $::punkboot::tool_args
set tool_action [lindex $targs 0]
if {$tool_action eq ""} {set tool_action list}
#args after the action: tool names plus an optional '-test 0|1' flag (build)
set tool_dotest 1
set tool_names [list]
set _i 1
while {$_i < [llength $targs]} {
set a [lindex $targs $_i]
if {$a eq "-test"} {
incr _i
set v [lindex $targs $_i]
if {![string is boolean -strict $v]} {
puts stderr "make.tcl tool: -test requires a boolean value (got '$v')"
exit 2
}
set tool_dotest [expr {bool($v)}]
} else {
lappend tool_names $a
}
incr _i
}
unset -nocomplain _i a v
proc ::punkboot::tool_dirs {tool_root} {
set dirs [list]
foreach dir [lsort [glob -nocomplain -dir $tool_root -type d *]] {
if {![file exists [file join $dir build.zig]]} {continue} ;#not a tool
lappend dirs $dir
}
return $dirs
}
#tolerant build.zig.zon reader: tool version + declared minimum zig version
proc ::punkboot::tool_zoninfo {tooldir} {
set m [dict create version "" zigfloor ""]
if {![catch {
set f [open [file join $tooldir build.zig.zon] r]
set data [read $f]
close $f
}]} {
if {[regexp {\.version\s*=\s*"([^"]+)"} $data -> _v]} {dict set m version $_v}
if {[regexp {\.minimum_zig_version\s*=\s*"([^"]+)"} $data -> _fl]} {dict set m zigfloor $_fl}
}
return $m
}
#tolerant PROVENANCE.md reader: vendored upstream commit + upstream location
proc ::punkboot::tool_provenance {tooldir} {
set m [dict create commit "" upstream ""]
if {![catch {
set f [open [file join $tooldir PROVENANCE.md] r]
set data [read $f]
close $f
}]} {
if {[regexp {Vendored state: commit\s+`?([0-9a-fA-F]{7,40})} $data -> _c]} {dict set m commit $_c}
if {[regexp {Upstream repository:\s+`?([^`\n]+)} $data -> _u]} {dict set m upstream [string trim $_u]}
}
return $m
}
proc ::punkboot::tool_newest_src_mtime {dir} {
set newest 0
foreach f [glob -nocomplain -dir $dir -type f *] {
if {[file mtime $f] > $newest} {set newest [file mtime $f]}
}
foreach d [glob -nocomplain -dir $dir -type d *] {
if {[file tail $d] in {zig-out .zig-cache zig-cache}} {continue}
set sub [::punkboot::tool_newest_src_mtime $d]
if {$sub > $newest} {set newest $sub}
}
return $newest
}
proc ::punkboot::tool_zig_version {zigexe} {
if {[catch {exec $zigexe version 2>@1} v]} {return ""}
return [string trim [lindex [split $v \n] 0]]
}
#a dev build's base version must EXCEED the floor (e.g 0.16.0-dev < 0.16.0)
proc ::punkboot::tool_zig_satisfies {ver floor} {
if {$floor eq ""} {return 1}
set base $ver ; set isdev 0
if {[regexp {^([0-9][0-9.]*)[-+]} $ver -> b]} {set base $b ; set isdev 1}
if {[catch {package vcompare $base $floor} cmp]} {return 0}
if {$cmp > 0} {return 1}
if {$cmp == 0 && !$isdev} {return 1}
return 0
}
#resolve a zig for the given floor: PUNK_ZIG env override (path to the zig
#executable or its folder), else scan <projectdir>/bin/tools/zig* preferring
#releases over dev builds and the LOWEST satisfying version - a deterministic
#choice that stays stable as newer toolchains get unpacked beside the pinned one
proc ::punkboot::tool_resolve_zig {projectroot floor} {
if {[info exists ::env(PUNK_ZIG)] && $::env(PUNK_ZIG) ne ""} {
set cand $::env(PUNK_ZIG)
if {[file isdirectory $cand]} {
foreach n {zig.exe zig} {
if {[file exists [file join $cand $n]]} {set cand [file join $cand $n] ; break}
}
}
set v [::punkboot::tool_zig_version $cand]
if {$v eq ""} {
return [dict create note "PUNK_ZIG='$::env(PUNK_ZIG)' did not answer 'zig version'"]
}
if {![::punkboot::tool_zig_satisfies $v $floor]} {
return [dict create note "PUNK_ZIG zig is $v which does not satisfy this tool's floor (>= $floor)"]
}
return [dict create zig $cand version $v via PUNK_ZIG]
}
set best "" ; set bestv "" ; set bestbase "" ; set bestdev 1
foreach dir [lsort [glob -nocomplain -dir [file join $projectroot bin tools] -type d zig*]] {
set p ""
foreach n {zig.exe zig} {
if {[file exists [file join $dir $n]]} {set p [file join $dir $n] ; break}
}
if {$p eq ""} {continue}
set v [::punkboot::tool_zig_version $p]
if {$v eq "" || ![::punkboot::tool_zig_satisfies $v $floor]} {continue}
set base $v ; set isdev 0
if {[regexp {^([0-9][0-9.]*)[-+]} $v -> b]} {set base $b ; set isdev 1}
set take 0
if {$best eq ""} {
set take 1
} elseif {$bestdev && !$isdev} {
set take 1
} elseif {$bestdev == $isdev && [package vcompare $base $bestbase] < 0} {
set take 1
}
if {$take} {set best $p ; set bestv $v ; set bestbase $base ; set bestdev $isdev}
}
if {$best eq ""} {
set want [expr {$floor eq "" ? "any version" : ">= $floor"}]
return [dict create note "no suitable zig toolchain ($want) under [file join $projectroot bin tools] - 'bin/punk-getzig.cmd <version>' fetches one; PUNK_ZIG=<path-to-zig> overrides"]
}
return [dict create zig $best version $bestv via scan]
}
proc ::punkboot::tool_installed_exe {projectroot name} {
set suffix [punkboot::lib::platform_exe_suffix $::punkboot::target_platform]
return [file join $projectroot bin ${name}$suffix]
}
proc ::punkboot::tool_install_state {projectroot tooldir} {
set exe [::punkboot::tool_installed_exe $projectroot [file tail $tooldir]]
if {![file exists $exe]} {return absent}
if {[file mtime $exe] >= [::punkboot::tool_newest_src_mtime $tooldir]} {return current}
return stale
}
#run 'zig <argl>' with cwd at the tool tree (the tree's CLI tests resolve
#fixtures and zig-out relative to the build root). The gate is the EXIT CODE:
#stderr legitimately carries expected warnings (punkzip's zip suite negative
#tests print EOCD warnings while passing). Returns the child's exit status.
proc ::punkboot::tool_zig_run {zig tooldir argl} {
set saved [pwd]
cd $tooldir
set rc 0
if {[catch {exec $zig {*}$argl >@stdout 2>@stderr} _e _o]} {
set ecode [dict get $_o -errorcode]
if {[lindex $ecode 0] eq "CHILDSTATUS"} {
set rc [lindex $ecode 2]
} else {
puts stderr "tool: failed to run '$zig $argl' in $tooldir: $_e"
set rc 1
}
}
cd $saved
return $rc
}
set alldirs [::punkboot::tool_dirs $tool_root]
set byname [dict create]
foreach d $alldirs {dict set byname [file tail $d] $d}
if {[llength $tool_names]} {
set selected [list]
foreach n $tool_names {
if {![dict exists $byname $n]} {
puts stderr "tool '$n' not found under $tool_root - configured tools: [dict keys $byname]"
exit 2
}
lappend selected [dict get $byname $n]
}
} else {
set selected $alldirs
}
if {![llength $alldirs] && $tool_action ne "list"} {
puts stderr "no vendored tools found under $tool_root (a tool = a directory carrying build.zig)"
exit 2
}
switch -- $tool_action {
list {
if {![llength $alldirs]} {
puts stdout "no vendored tools found under $tool_root (a tool = a directory carrying build.zig)"
exit 0
}
puts stdout "vendored tools under $tool_root (boundary: src/tools/AGENTS.md; per-tree PROVENANCE.md):"
puts stdout [format " %-10s %-9s %-10s %-8s %s" name version zig-floor bin vendored-commit]
set maxfloor ""
foreach dir $alldirs {
set name [file tail $dir]
set zon [::punkboot::tool_zoninfo $dir]
set prov [::punkboot::tool_provenance $dir]
set floor [dict get $zon zigfloor]
if {$floor ne "" && ($maxfloor eq "" || [package vcompare $floor $maxfloor] > 0)} {
set maxfloor $floor
}
set commit [dict get $prov commit]
set commit [expr {$commit eq "" ? "-" : [string range $commit 0 11]}]
set floorshow [expr {$floor eq "" ? "-" : ">=$floor"}]
puts stdout [format " %-10s %-9s %-10s %-8s %s" $name [dict get $zon version] $floorshow [::punkboot::tool_install_state $projectroot $dir] $commit]
}
set zres [::punkboot::tool_resolve_zig $projectroot $maxfloor]
if {[dict exists $zres zig]} {
puts stdout "toolchain: zig [dict get $zres version] via [dict get $zres via] ([dict get $zres zig])"
} else {
puts stdout "toolchain: [dict get $zres note]"
}
puts stdout ""
puts stdout " - 'make.tcl tool info <name>' shows a tool's detail"
puts stdout " - 'make.tcl tool build ?<name> ...? ?-test 0|1?' builds (test-gated) and installs to bin/"
puts stdout " - zig is OPTIONAL for punkshell builds: packages/bake never require this step"
exit 0
}
info {
if {![llength $tool_names]} {
puts stderr "usage: make.tcl tool info <toolname> ('make.tcl tool list' shows the names)"
exit 2
}
foreach dir $selected {
set name [file tail $dir]
set zon [::punkboot::tool_zoninfo $dir]
set prov [::punkboot::tool_provenance $dir]
set floor [dict get $zon zigfloor]
puts stdout "tool: $name"
puts stdout " path: $dir"
puts stdout " version: [dict get $zon version] (build.zig.zon)"
puts stdout " zig floor: [expr {$floor eq "" ? "(none declared)" : ">= $floor"}]"
puts stdout " upstream: [expr {[dict get $prov upstream] eq "" ? "(no PROVENANCE.md record)" : [dict get $prov upstream]}]"
puts stdout " vendored commit: [expr {[dict get $prov commit] eq "" ? "(no PROVENANCE.md record)" : [dict get $prov commit]}]"
puts stdout " provenance: [file join $dir PROVENANCE.md]"
set exe [::punkboot::tool_installed_exe $projectroot $name]
puts stdout " installed: $exe ([::punkboot::tool_install_state $projectroot $dir])"
set zres [::punkboot::tool_resolve_zig $projectroot $floor]
if {[dict exists $zres zig]} {
puts stdout " toolchain: zig [dict get $zres version] via [dict get $zres via] ([dict get $zres zig])"
} else {
puts stdout " toolchain: [dict get $zres note]"
}
}
exit 0
}
build {
foreach dir $selected {
set name [file tail $dir]
set floor [dict get [::punkboot::tool_zoninfo $dir] zigfloor]
set zres [::punkboot::tool_resolve_zig $projectroot $floor]
if {![dict exists $zres zig]} {
puts stderr "tool build $name: [dict get $zres note]"
exit 1
}
set zig [dict get $zres zig]
puts stdout "tool build $name: zig [dict get $zres version] via [dict get $zres via] ($zig)"
flush stdout
if {$tool_dotest} {
puts stdout "tool build $name: test gate ('zig build test') ..."
flush stdout
set rc [::punkboot::tool_zig_run $zig $dir [list build test]]
if {$rc != 0} {
puts stderr "tool build $name: test gate FAILED (exit $rc) - nothing installed"
exit 1
}
puts stdout "tool build $name: test gate passed"
} else {
puts stdout "tool build $name: test gate SKIPPED (-test 0)"
}
puts stdout "tool build $name: building (ReleaseSafe) ..."
flush stdout
set rc [::punkboot::tool_zig_run $zig $dir [list build -Doptimize=ReleaseSafe]]
if {$rc != 0} {
puts stderr "tool build $name: build FAILED (exit $rc) - nothing installed"
exit 1
}
set suffix [punkboot::lib::platform_exe_suffix $::punkboot::target_platform]
set built [file join $dir zig-out bin ${name}$suffix]
if {![file exists $built]} {
puts stderr "tool build $name: build reported success but $built is missing"
exit 1
}
set exe [::punkboot::tool_installed_exe $projectroot $name]
if {[catch {file copy -force $built $exe} cperr]} {
puts stderr "tool build $name: could not install $exe ($cperr) - is a copy currently running?"
exit 1
}
puts stdout "tool build $name: installed $exe ([file size $exe] bytes)"
}
exit 0
}
test {
foreach dir $selected {
set name [file tail $dir]
set floor [dict get [::punkboot::tool_zoninfo $dir] zigfloor]
set zres [::punkboot::tool_resolve_zig $projectroot $floor]
if {![dict exists $zres zig]} {
puts stderr "tool test $name: [dict get $zres note]"
exit 1
}
set zig [dict get $zres zig]
puts stdout "tool test $name: zig [dict get $zres version] via [dict get $zres via] - running 'zig build test' ..."
flush stdout
set rc [::punkboot::tool_zig_run $zig $dir [list build test]]
if {$rc != 0} {
puts stderr "tool test $name: FAILED (exit $rc)"
exit 1
}
puts stdout "tool test $name: passed"
}
exit 0
}
default {
puts stderr "unknown tool action '$tool_action' - expected list|info|build|test"
puts stderr "usage: make.tcl tool list|info|build|test ?<toolname> ...? ?-test 0|1?"
exit 2
}
}
}
if {$::punkboot::command eq "shell"} { if {$::punkboot::command eq "shell"} {
#G-113: the ansistrip transform serves make.tcl's own output only - the repl's #G-113: the ansistrip transform serves make.tcl's own output only - the repl's
#colour behaviour is the shell's own concern (colour on/off + NO_COLOR there). #colour behaviour is the shell's own concern (colour on/off + NO_COLOR there).

411
src/project_layouts/vendor/punk/project-0.1/src/make.tcl vendored

@ -187,7 +187,7 @@ namespace eval ::punkboot {
variable foldername [file tail $scriptfolder] variable foldername [file tail $scriptfolder]
variable pkg_requirements [list]; variable pkg_missing [list];variable pkg_loaded [list] variable pkg_requirements [list]; variable pkg_missing [list];variable pkg_loaded [list]
variable help_flags [list -help --help /? -h] variable help_flags [list -help --help /? -h]
variable known_commands [list bakehouse packages modules libs bake bakelist vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow buildsuite project vfs] variable known_commands [list bakehouse packages modules libs bake bakelist vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow buildsuite tool project vfs]
} }
@ -2152,6 +2152,11 @@ proc ::punkboot::punkboot_gethelp {args} {
append h " $scriptname buildsuite list|info|build ?<suitename>? ?driver-args ...?" \n append h " $scriptname buildsuite list|info|build ?<suitename>? ?driver-args ...?" \n
append h " - list the defined buildsuites under src/buildsuites (zig runtime factory), show a suite's configured" \n append h " - list the defined buildsuites under src/buildsuites (zig runtime factory), show a suite's configured" \n
append h " detail (sources/zig pin/products from its sources.config), or run its driver forwarding the args" \n \n append h " detail (sources/zig pin/products from its sources.config), or run its driver forwarding the args" \n \n
append h " $scriptname tool list|info|build|test ?<toolname> ...? ?-test 0|1?" \n
append h " - vendored first-party build tools under src/tools (zig source; G-126): list/detail them, run their" \n
append h " test suites, or build (test-gated) and install to <projectdir>/bin" \n
append h " - zig is OPTIONAL: packages/bake never require this step; without a suitable toolchain the state is" \n
append h " reported and build/test exit nonzero with fetch guidance (bin/punk-getzig.cmd)" \n \n
append h " $scriptname help ?subcommand?" \n append h " $scriptname help ?subcommand?" \n
append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname <subcommand> -help)" \n \n append h " - show usage for $scriptname or one of its subcommands (equivalent: $scriptname <subcommand> -help)" \n \n
append h " Deprecated aliases (transition window):" \n append h " Deprecated aliases (transition window):" \n
@ -2402,6 +2407,14 @@ KEY / NOTES
with binary dependencies, and version-preference outcomes are visible only to with binary dependencies, and version-preference outcomes are visible only to
the smoke probe - and only for declared packages. 'make.tcl check' reports both. the smoke probe - and only for declared packages. 'make.tcl check' reports both.
OUT-OF-BAND SUBSYSTEMS (not part of the packages/bake data flow above)
'make.tcl tool' builds the vendored first-party zig tools under src/tools
(G-126; punkzip first) into <projectdir>/bin, gated on each tree's own
'zig build test' exit code. zig is OPTIONAL: packages/bake never require it.
'make.tcl buildsuite' is the analogous arm's-length factory for whole Tcl
runtimes built from EXTERNAL sources under src/buildsuites (fetch + test-gate
contract per suite; products land in the bin/runtime store tiers).
MAINTENANCE (agents take note) MAINTENANCE (agents take note)
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
This text is embedded in make.tcl (::punkboot::workflow_text). When the build This text is embedded in make.tcl (::punkboot::workflow_text). When the build
@ -2514,6 +2527,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
shell "Run the punk shell using bootsupport libraries" shell "Run the punk shell using bootsupport libraries"
help "Show usage for make.tcl or one of its subcommands" help "Show usage for make.tcl or one of its subcommands"
buildsuite "List, describe or run the defined buildsuites under src/buildsuites (zig runtime factory)" buildsuite "List, describe or run the defined buildsuites under src/buildsuites (zig runtime factory)"
tool "List, test or build the vendored tools under src/tools (zig) and install them to <projectdir>/bin"
project "DEPRECATED alias for bakehouse (one-line notice, then runs bakehouse)" project "DEPRECATED alias for bakehouse (one-line notice, then runs bakehouse)"
vfs "DEPRECATED alias for bake (one-line notice, then runs bake)" vfs "DEPRECATED alias for bake (one-line notice, then runs bake)"
} }
@ -2683,6 +2697,45 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
(copy-and-tweak workflow) appears here automatically with no (copy-and-tweak workflow) appears here automatically with no
make.tcl edits. The contract is documented in make.tcl edits. The contract is documented in
src/buildsuites/README.md." src/buildsuites/README.md."
tool
"
Surface for the vendored first-party build tools under src/tools
(G-126: zig source vendored in full; boundary and editing policy in
src/tools/AGENTS.md, per-tree origin/licence records in
<tool>/PROVENANCE.md). Discovery is convention-based: a directory
under src/tools carrying build.zig is a tool; its installed
artifact is <projectdir>/bin/<name> with the host executable
suffix.
Actions:
tool list
Discover the tools with version (build.zig.zon), declared zig
floor, installed-binary state (current|stale|absent) and the
vendored upstream commit; report the resolved toolchain.
tool info <name> ...
Per-tool detail: paths, provenance records, toolchain
resolution.
tool build ?<name> ...? ?-test 0|1?
Resolve a zig satisfying the tool's declared floor, run the
'zig build test' gate (default on; the gate is the EXIT CODE -
expected warnings on stderr do not fail it), build ReleaseSafe
and install to <projectdir>/bin. Nothing is installed when the
gate or the build fails. With no name, all tools are
processed.
tool test ?<name> ...?
Run each tool's 'zig build test' only.
Toolchain resolution: PUNK_ZIG=<path-to-zig-or-its-folder>
overrides; otherwise <projectdir>/bin/tools/zig* is scanned and
the LOWEST release satisfying the floor wins (deterministic as
newer toolchains appear beside the pinned one; dev builds count
only when their base version exceeds the floor). zig is OPTIONAL
for punkshell builds: packages/bake never require this step -
without a suitable toolchain, list reports the state and
build/test exit nonzero with fetch guidance
(bin/punk-getzig.cmd). Build caches (.zig-cache/zig-out) are
deliberately left in place between runs for rebuild speed (both
git- and fossil-ignored)."
project project
" "
DEPRECATED alias for 'bakehouse' (G-112 stage-true rename) - prints a DEPRECATED alias for 'bakehouse' (G-112 stage-true rename) - prints a
@ -2855,6 +2908,15 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
arg -type any -optional 1 -multiple 1 -help\ arg -type any -optional 1 -multiple 1 -help\
"Action (list|info|build), suite name, and - for build - driver "Action (list|info|build), suite name, and - for build - driver
arguments forwarded to the suite's suite.tcl untouched."} arguments forwarded to the suite's suite.tcl untouched."}
punk::args::define\
"@id -id (script)::punkboot::tool"\
"@normalize"\
"@cmd -name [list "make.tcl tool"] -summary [list [dict get $SUMMARIES tool]] -help [list [dict get $HELPTEXTS tool]]"\
{@form -synopsis "make.tcl tool list|info|build|test ?<toolname> ...? ?-test 0|1?"}\
{@values -min 0 -max -1
arg -type any -optional 1 -multiple 1 -help\
"Action (list|info|build|test), tool name(s), and - for build -
the -test 0|1 gate flag. Parsed by the handler."}
punk::args::define\ punk::args::define\
"@id -id (script)::punkboot::help"\ "@id -id (script)::punkboot::help"\
"@normalize"\ "@normalize"\
@ -2871,6 +2933,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
"promotion gates" {bootsupport vfscommonupdate} "promotion gates" {bootsupport vfscommonupdate}
"source maintenance" {vendorupdate} "source maintenance" {vendorupdate}
"buildsuites" {buildsuite} "buildsuites" {buildsuite}
"vendored tools" {tool}
"informational" {info check bakelist projectversion workflow help} "informational" {info check bakelist projectversion workflow help}
"interactive" {shell} "interactive" {shell}
"deprecated aliases" {project vfs} "deprecated aliases" {project vfs}
@ -2963,6 +3026,10 @@ if {$::punkboot::punkargs_ok} {
#args (arbitrary suite flags) are forwarded untouched (G-104) #args (arbitrary suite flags) are forwarded untouched (G-104)
set ::punkboot::command buildsuite set ::punkboot::command buildsuite
set ::punkboot::bs_args $subargs set ::punkboot::bs_args $subargs
} elseif {$subcommand eq "tool"} {
#declared passthrough: the handler parses action/names/-test itself (G-126)
set ::punkboot::command tool
set ::punkboot::tool_args $subargs
} else { } else {
if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::$subcommand} argd]} { if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::$subcommand} argd]} {
puts stderr $argd puts stderr $argd
@ -2993,6 +3060,12 @@ if {$::punkboot::punkargs_ok} {
set commands_found [list buildsuite] set commands_found [list buildsuite]
set argsleft [list] set argsleft [list]
set ::punkboot::bs_args [lrange $scriptargs 1 end] set ::punkboot::bs_args [lrange $scriptargs 1 end]
} elseif {[lindex $scriptargs 0] eq "tool"} {
#declared passthrough (as in the punk::args path) - the handler parses
#action/names/-test itself (G-126)
set commands_found [list tool]
set argsleft [list]
set ::punkboot::tool_args [lrange $scriptargs 1 end]
} }
while {[llength $argsleft]} { while {[llength $argsleft]} {
set a [lindex $argsleft 0] set a [lindex $argsleft 0]
@ -3116,7 +3189,8 @@ set forcekill $::punkboot::opt_forcekill
# - patch bump -> warn and proceed (non-breaking) # - patch bump -> warn and proceed (non-breaking)
# 'check' is exempt in all cases the warning is shown at the end of its output instead. # 'check' is exempt in all cases the warning is shown at the end of its output instead.
# 'projectversion', 'workflow' and 'bakelist' are informational/read-only and are likewise exempt. # 'projectversion', 'workflow' and 'bakelist' are informational/read-only and are likewise exempt.
if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ni {check projectversion workflow bakelist buildsuite}} { # 'buildsuite' and 'tool' are arm's-length subsystems that do not consume bootsupport modules.
if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ni {check projectversion workflow bakelist buildsuite tool}} {
set _stale $::punkboot::stale_bootsupport set _stale $::punkboot::stale_bootsupport
set _have_major 0 set _have_major 0
set _have_minor 0 set _have_minor 0
@ -4242,6 +4316,339 @@ if {$::punkboot::command eq "buildsuite"} {
} }
} }
if {$::punkboot::command eq "tool"} {
#G-126: vendored first-party build tools under src/tools (zig source vendored in
#full - boundary and editing policy in src/tools/AGENTS.md; per-tree origin,
#re-vendor procedure and licence records in <tool>/PROVENANCE.md). Discovery is
#convention-based: a directory under src/tools carrying build.zig is a tool, its
#name is the directory name, its build artifact is <tooldir>/zig-out/bin/<name>
#and its installed copy is <projectdir>/bin/<name> (host executable suffix).
#zig stays OPTIONAL for punkshell builds: nothing in packages/bake depends on
#this step; explicit build/test without a suitable toolchain exits nonzero with
#fetch guidance. Build caches (.zig-cache/zig-out) are deliberately left in
#place between builds for rebuild speed (both git- and fossil-ignored).
set tool_root [file join $sourcefolder tools]
if {![info exists ::punkboot::tool_args]} {set ::punkboot::tool_args [list]}
set targs $::punkboot::tool_args
set tool_action [lindex $targs 0]
if {$tool_action eq ""} {set tool_action list}
#args after the action: tool names plus an optional '-test 0|1' flag (build)
set tool_dotest 1
set tool_names [list]
set _i 1
while {$_i < [llength $targs]} {
set a [lindex $targs $_i]
if {$a eq "-test"} {
incr _i
set v [lindex $targs $_i]
if {![string is boolean -strict $v]} {
puts stderr "make.tcl tool: -test requires a boolean value (got '$v')"
exit 2
}
set tool_dotest [expr {bool($v)}]
} else {
lappend tool_names $a
}
incr _i
}
unset -nocomplain _i a v
proc ::punkboot::tool_dirs {tool_root} {
set dirs [list]
foreach dir [lsort [glob -nocomplain -dir $tool_root -type d *]] {
if {![file exists [file join $dir build.zig]]} {continue} ;#not a tool
lappend dirs $dir
}
return $dirs
}
#tolerant build.zig.zon reader: tool version + declared minimum zig version
proc ::punkboot::tool_zoninfo {tooldir} {
set m [dict create version "" zigfloor ""]
if {![catch {
set f [open [file join $tooldir build.zig.zon] r]
set data [read $f]
close $f
}]} {
if {[regexp {\.version\s*=\s*"([^"]+)"} $data -> _v]} {dict set m version $_v}
if {[regexp {\.minimum_zig_version\s*=\s*"([^"]+)"} $data -> _fl]} {dict set m zigfloor $_fl}
}
return $m
}
#tolerant PROVENANCE.md reader: vendored upstream commit + upstream location
proc ::punkboot::tool_provenance {tooldir} {
set m [dict create commit "" upstream ""]
if {![catch {
set f [open [file join $tooldir PROVENANCE.md] r]
set data [read $f]
close $f
}]} {
if {[regexp {Vendored state: commit\s+`?([0-9a-fA-F]{7,40})} $data -> _c]} {dict set m commit $_c}
if {[regexp {Upstream repository:\s+`?([^`\n]+)} $data -> _u]} {dict set m upstream [string trim $_u]}
}
return $m
}
proc ::punkboot::tool_newest_src_mtime {dir} {
set newest 0
foreach f [glob -nocomplain -dir $dir -type f *] {
if {[file mtime $f] > $newest} {set newest [file mtime $f]}
}
foreach d [glob -nocomplain -dir $dir -type d *] {
if {[file tail $d] in {zig-out .zig-cache zig-cache}} {continue}
set sub [::punkboot::tool_newest_src_mtime $d]
if {$sub > $newest} {set newest $sub}
}
return $newest
}
proc ::punkboot::tool_zig_version {zigexe} {
if {[catch {exec $zigexe version 2>@1} v]} {return ""}
return [string trim [lindex [split $v \n] 0]]
}
#a dev build's base version must EXCEED the floor (e.g 0.16.0-dev < 0.16.0)
proc ::punkboot::tool_zig_satisfies {ver floor} {
if {$floor eq ""} {return 1}
set base $ver ; set isdev 0
if {[regexp {^([0-9][0-9.]*)[-+]} $ver -> b]} {set base $b ; set isdev 1}
if {[catch {package vcompare $base $floor} cmp]} {return 0}
if {$cmp > 0} {return 1}
if {$cmp == 0 && !$isdev} {return 1}
return 0
}
#resolve a zig for the given floor: PUNK_ZIG env override (path to the zig
#executable or its folder), else scan <projectdir>/bin/tools/zig* preferring
#releases over dev builds and the LOWEST satisfying version - a deterministic
#choice that stays stable as newer toolchains get unpacked beside the pinned one
proc ::punkboot::tool_resolve_zig {projectroot floor} {
if {[info exists ::env(PUNK_ZIG)] && $::env(PUNK_ZIG) ne ""} {
set cand $::env(PUNK_ZIG)
if {[file isdirectory $cand]} {
foreach n {zig.exe zig} {
if {[file exists [file join $cand $n]]} {set cand [file join $cand $n] ; break}
}
}
set v [::punkboot::tool_zig_version $cand]
if {$v eq ""} {
return [dict create note "PUNK_ZIG='$::env(PUNK_ZIG)' did not answer 'zig version'"]
}
if {![::punkboot::tool_zig_satisfies $v $floor]} {
return [dict create note "PUNK_ZIG zig is $v which does not satisfy this tool's floor (>= $floor)"]
}
return [dict create zig $cand version $v via PUNK_ZIG]
}
set best "" ; set bestv "" ; set bestbase "" ; set bestdev 1
foreach dir [lsort [glob -nocomplain -dir [file join $projectroot bin tools] -type d zig*]] {
set p ""
foreach n {zig.exe zig} {
if {[file exists [file join $dir $n]]} {set p [file join $dir $n] ; break}
}
if {$p eq ""} {continue}
set v [::punkboot::tool_zig_version $p]
if {$v eq "" || ![::punkboot::tool_zig_satisfies $v $floor]} {continue}
set base $v ; set isdev 0
if {[regexp {^([0-9][0-9.]*)[-+]} $v -> b]} {set base $b ; set isdev 1}
set take 0
if {$best eq ""} {
set take 1
} elseif {$bestdev && !$isdev} {
set take 1
} elseif {$bestdev == $isdev && [package vcompare $base $bestbase] < 0} {
set take 1
}
if {$take} {set best $p ; set bestv $v ; set bestbase $base ; set bestdev $isdev}
}
if {$best eq ""} {
set want [expr {$floor eq "" ? "any version" : ">= $floor"}]
return [dict create note "no suitable zig toolchain ($want) under [file join $projectroot bin tools] - 'bin/punk-getzig.cmd <version>' fetches one; PUNK_ZIG=<path-to-zig> overrides"]
}
return [dict create zig $best version $bestv via scan]
}
proc ::punkboot::tool_installed_exe {projectroot name} {
set suffix [punkboot::lib::platform_exe_suffix $::punkboot::target_platform]
return [file join $projectroot bin ${name}$suffix]
}
proc ::punkboot::tool_install_state {projectroot tooldir} {
set exe [::punkboot::tool_installed_exe $projectroot [file tail $tooldir]]
if {![file exists $exe]} {return absent}
if {[file mtime $exe] >= [::punkboot::tool_newest_src_mtime $tooldir]} {return current}
return stale
}
#run 'zig <argl>' with cwd at the tool tree (the tree's CLI tests resolve
#fixtures and zig-out relative to the build root). The gate is the EXIT CODE:
#stderr legitimately carries expected warnings (punkzip's zip suite negative
#tests print EOCD warnings while passing). Returns the child's exit status.
proc ::punkboot::tool_zig_run {zig tooldir argl} {
set saved [pwd]
cd $tooldir
set rc 0
if {[catch {exec $zig {*}$argl >@stdout 2>@stderr} _e _o]} {
set ecode [dict get $_o -errorcode]
if {[lindex $ecode 0] eq "CHILDSTATUS"} {
set rc [lindex $ecode 2]
} else {
puts stderr "tool: failed to run '$zig $argl' in $tooldir: $_e"
set rc 1
}
}
cd $saved
return $rc
}
set alldirs [::punkboot::tool_dirs $tool_root]
set byname [dict create]
foreach d $alldirs {dict set byname [file tail $d] $d}
if {[llength $tool_names]} {
set selected [list]
foreach n $tool_names {
if {![dict exists $byname $n]} {
puts stderr "tool '$n' not found under $tool_root - configured tools: [dict keys $byname]"
exit 2
}
lappend selected [dict get $byname $n]
}
} else {
set selected $alldirs
}
if {![llength $alldirs] && $tool_action ne "list"} {
puts stderr "no vendored tools found under $tool_root (a tool = a directory carrying build.zig)"
exit 2
}
switch -- $tool_action {
list {
if {![llength $alldirs]} {
puts stdout "no vendored tools found under $tool_root (a tool = a directory carrying build.zig)"
exit 0
}
puts stdout "vendored tools under $tool_root (boundary: src/tools/AGENTS.md; per-tree PROVENANCE.md):"
puts stdout [format " %-10s %-9s %-10s %-8s %s" name version zig-floor bin vendored-commit]
set maxfloor ""
foreach dir $alldirs {
set name [file tail $dir]
set zon [::punkboot::tool_zoninfo $dir]
set prov [::punkboot::tool_provenance $dir]
set floor [dict get $zon zigfloor]
if {$floor ne "" && ($maxfloor eq "" || [package vcompare $floor $maxfloor] > 0)} {
set maxfloor $floor
}
set commit [dict get $prov commit]
set commit [expr {$commit eq "" ? "-" : [string range $commit 0 11]}]
set floorshow [expr {$floor eq "" ? "-" : ">=$floor"}]
puts stdout [format " %-10s %-9s %-10s %-8s %s" $name [dict get $zon version] $floorshow [::punkboot::tool_install_state $projectroot $dir] $commit]
}
set zres [::punkboot::tool_resolve_zig $projectroot $maxfloor]
if {[dict exists $zres zig]} {
puts stdout "toolchain: zig [dict get $zres version] via [dict get $zres via] ([dict get $zres zig])"
} else {
puts stdout "toolchain: [dict get $zres note]"
}
puts stdout ""
puts stdout " - 'make.tcl tool info <name>' shows a tool's detail"
puts stdout " - 'make.tcl tool build ?<name> ...? ?-test 0|1?' builds (test-gated) and installs to bin/"
puts stdout " - zig is OPTIONAL for punkshell builds: packages/bake never require this step"
exit 0
}
info {
if {![llength $tool_names]} {
puts stderr "usage: make.tcl tool info <toolname> ('make.tcl tool list' shows the names)"
exit 2
}
foreach dir $selected {
set name [file tail $dir]
set zon [::punkboot::tool_zoninfo $dir]
set prov [::punkboot::tool_provenance $dir]
set floor [dict get $zon zigfloor]
puts stdout "tool: $name"
puts stdout " path: $dir"
puts stdout " version: [dict get $zon version] (build.zig.zon)"
puts stdout " zig floor: [expr {$floor eq "" ? "(none declared)" : ">= $floor"}]"
puts stdout " upstream: [expr {[dict get $prov upstream] eq "" ? "(no PROVENANCE.md record)" : [dict get $prov upstream]}]"
puts stdout " vendored commit: [expr {[dict get $prov commit] eq "" ? "(no PROVENANCE.md record)" : [dict get $prov commit]}]"
puts stdout " provenance: [file join $dir PROVENANCE.md]"
set exe [::punkboot::tool_installed_exe $projectroot $name]
puts stdout " installed: $exe ([::punkboot::tool_install_state $projectroot $dir])"
set zres [::punkboot::tool_resolve_zig $projectroot $floor]
if {[dict exists $zres zig]} {
puts stdout " toolchain: zig [dict get $zres version] via [dict get $zres via] ([dict get $zres zig])"
} else {
puts stdout " toolchain: [dict get $zres note]"
}
}
exit 0
}
build {
foreach dir $selected {
set name [file tail $dir]
set floor [dict get [::punkboot::tool_zoninfo $dir] zigfloor]
set zres [::punkboot::tool_resolve_zig $projectroot $floor]
if {![dict exists $zres zig]} {
puts stderr "tool build $name: [dict get $zres note]"
exit 1
}
set zig [dict get $zres zig]
puts stdout "tool build $name: zig [dict get $zres version] via [dict get $zres via] ($zig)"
flush stdout
if {$tool_dotest} {
puts stdout "tool build $name: test gate ('zig build test') ..."
flush stdout
set rc [::punkboot::tool_zig_run $zig $dir [list build test]]
if {$rc != 0} {
puts stderr "tool build $name: test gate FAILED (exit $rc) - nothing installed"
exit 1
}
puts stdout "tool build $name: test gate passed"
} else {
puts stdout "tool build $name: test gate SKIPPED (-test 0)"
}
puts stdout "tool build $name: building (ReleaseSafe) ..."
flush stdout
set rc [::punkboot::tool_zig_run $zig $dir [list build -Doptimize=ReleaseSafe]]
if {$rc != 0} {
puts stderr "tool build $name: build FAILED (exit $rc) - nothing installed"
exit 1
}
set suffix [punkboot::lib::platform_exe_suffix $::punkboot::target_platform]
set built [file join $dir zig-out bin ${name}$suffix]
if {![file exists $built]} {
puts stderr "tool build $name: build reported success but $built is missing"
exit 1
}
set exe [::punkboot::tool_installed_exe $projectroot $name]
if {[catch {file copy -force $built $exe} cperr]} {
puts stderr "tool build $name: could not install $exe ($cperr) - is a copy currently running?"
exit 1
}
puts stdout "tool build $name: installed $exe ([file size $exe] bytes)"
}
exit 0
}
test {
foreach dir $selected {
set name [file tail $dir]
set floor [dict get [::punkboot::tool_zoninfo $dir] zigfloor]
set zres [::punkboot::tool_resolve_zig $projectroot $floor]
if {![dict exists $zres zig]} {
puts stderr "tool test $name: [dict get $zres note]"
exit 1
}
set zig [dict get $zres zig]
puts stdout "tool test $name: zig [dict get $zres version] via [dict get $zres via] - running 'zig build test' ..."
flush stdout
set rc [::punkboot::tool_zig_run $zig $dir [list build test]]
if {$rc != 0} {
puts stderr "tool test $name: FAILED (exit $rc)"
exit 1
}
puts stdout "tool test $name: passed"
}
exit 0
}
default {
puts stderr "unknown tool action '$tool_action' - expected list|info|build|test"
puts stderr "usage: make.tcl tool list|info|build|test ?<toolname> ...? ?-test 0|1?"
exit 2
}
}
}
if {$::punkboot::command eq "shell"} { if {$::punkboot::command eq "shell"} {
#G-113: the ansistrip transform serves make.tcl's own output only - the repl's #G-113: the ansistrip transform serves make.tcl's own output only - the repl's
#colour behaviour is the shell's own concern (colour on/off + NO_COLOR there). #colour behaviour is the shell's own concern (colour on/off + NO_COLOR there).

Loading…
Cancel
Save