Browse Source

G-104: make.tcl buildsuite list/info/build + sources.config self-description contract

buildsuite group added as a declared passthrough (punk::args + fallback paths):
list discovers suites (dirs carrying suite.tcl; _build excluded), info renders
the manifest-derived detail, build forwards driver args untouched streaming
output and exiting with the driver's status (punk-kit-hosted runs launch the
driver via the kit's script subcommand, selected by the G-058 marker).

Self-description = manifest option: sources.config gains description/product/
doc/zigpin records parsed by both suite.tcl (strict; pinned-zig default now
reads zigpin - one source of truth) and make.tcl (tolerant). suite_tcl90
seeded with its records. Copied trees appear automatically (verified with a
throwaway copy). Contract documented in new src/buildsuites/README.md +
AGENTS.md, indexed from src/AGENTS.md. CHANGELOG extended under 0.23.0.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 6 days ago
parent
commit
889d3cd1c7
  1. 10
      CHANGELOG.md
  2. 27
      goals/G-104-maketcl-buildsuite-surface.md
  3. 1
      src/AGENTS.md
  4. 42
      src/buildsuites/AGENTS.md
  5. 70
      src/buildsuites/README.md
  6. 16
      src/buildsuites/suite_tcl90/sources.config
  7. 92
      src/buildsuites/suite_tcl90/suite.tcl
  8. 209
      src/make.tcl

10
CHANGELOG.md

@ -16,6 +16,16 @@ Entries are newest-first; one bullet per notable change. See the root `AGENTS.md
the 8.6 arc completes). `vfslibs` survives as a standalone narrowing for declaration
iteration. Help/usage tables regrouped (build & bake / promotion gates / source
maintenance / deprecated aliases); `workflow` output teaches the two-persona model.
- make.tcl buildsuite surface (G-104): `buildsuite list` discovers the suites under
src/buildsuites (directories carrying a suite.tcl driver; _build excluded) with
one-line descriptions; `buildsuite info <name>` renders the suite's configured detail
(sources.config records, pinned zig + presence, products, doc pointers); `buildsuite
build <name> ?driver-args?` runs the suite driver forwarding args untouched, streaming
output and exiting with the driver's status. Suites are self-describing via new
sources.config records (description/product/doc/zigpin - same manifest the driver
parses; suite.tcl's pinned-zig default now reads the zigpin record), so copied
retargeted trees appear automatically. Contract documented in src/buildsuites/README.md
(new) + AGENTS.md (new). Works under plain tclsh and punk kit executables.
## [0.22.2] - 2026-07-25

27
goals/G-104-maketcl-buildsuite-surface.md

@ -32,6 +32,33 @@ Relationships: G-096 (achieved 2026-07-20 - suite.tcl driver + copy-and-tweak wo
G-102 (achieved 2026-07-21 - driver shape settled; the info/build contract holds), G-103 (achieved 2026-07-22 - see goals/archive/G-103-runtime-kit-family.md; family
products appear in info output), G-105 (target dimension forwarded when it exists).
## Progress
- 2026-07-25 surface landed (punkshell 0.23.0, written directly in the G-112
stage-true vocabulary): make.tcl gains the buildsuite group (list/info/build)
as a declared passthrough beside shell (driver args forwarded untouched in
both the punk::args and degraded-fallback dispatch paths). Self-description
contract settled on the MANIFEST option: sources.config gains
description/product/doc/zigpin records parsed by BOTH suite.tcl (strict; its
pinned-zig default now reads the zigpin record - single source of truth) and
make.tcl (tolerant - a malformed/absent manifest lists with the problem as
its description instead of breaking discovery). Discovery = directory scan
for a suite.tcl driver, _build excluded (samplesuite1 auto-excluded).
Contract documented in src/buildsuites/README.md (new) + AGENTS.md (new,
indexed from src/AGENTS.md); make.tcl help/plain-help document the group.
- Verified 2026-07-25: list shows suite_tcl90 with its sources.config-derived
description; info renders the sources table + zig pin (present) + products +
doc pointers; build forwards args and exits with the driver's status
(unknown-option run exit 1 streamed; unknown suite/action exit 2; list exit
0); works under native tclsh90 AND punk91-kit-hosted (script-mode launcher
selection via the G-058 static-capture marker); a throwaway COPY of
suite_tcl90 with an edited description appeared in list/info automatically
and was removed after the check. suite.tcl direct CLI re-verified
(usage-error path through the new config-load position).
- Remains for acceptance: a real driver run through the surface (satisfied
naturally when the G-099 suite_tcl86 arc drives builds via 'make.tcl
buildsuite build'); window doc sweep.
## Notes
- Activation freshness 2026-07-25: goals_xref.tcl score G-104 re-run at the

1
src/AGENTS.md

@ -116,5 +116,6 @@ Recovery after a wrong path guess:
- `vendorlib_tcl8/` — Tcl 8 specific vendor libraries
- `vendorlib_tcl9/` — Tcl 9 specific vendor libraries
- `runtime/` — Build runtimes and VFS config (see runtime/AGENTS.md)
- `buildsuites/` — Zig-built runtime factory: suites building Tcl runtimes from external sources with the pinned zig toolchain; surfaced via `make.tcl buildsuite list/info/build`; suite self-description contract in buildsuites/README.md (see buildsuites/AGENTS.md)
- `doc/` — Generated documentation (see doc/AGENTS.md)
- `testansi/` — Sample ANSI art files (do not modify)

42
src/buildsuites/AGENTS.md

@ -0,0 +1,42 @@
# src/buildsuites - Buildsuites (zig runtime factory)
## Purpose
Suites that build Tcl runtimes and binary companions from external upstream
sources using the pinned zig toolchain (zig-only build policy). Arm's-length
from the project build/bake stages: inputs are upstream checkouts/pins, not
this project's `src/` tree.
## Ownership
- Suite trees (`suite_tcl90/`, future `suite_tcl86/` etc) are agent-editable
under user-directed goal work (the G-096/G-099 arcs).
- `_build/` is a VCS-ignored build area - never commit from it; each suite
stages into `_build/<suitename>`.
## Local Contracts
- The suite self-description contract (what makes a directory a suite, the
`sources.config` record grammar incl. description/product/doc/zigpin, the
copy-and-tweak guarantee) is documented in `README.md` here - keep it and
the `make.tcl buildsuite` surface in step.
- `sources.config` is parsed, never executed - by both the suite driver and
`make.tcl buildsuite list/info`. Grammar changes must land in both parsers
(suite.tcl strict, make.tcl tolerant) plus `README.md`.
- Fossil clones live in the machine-level store (`PUNK_FOSSIL_STORE`, default
`~/.punkshell/fossils`) - outside `_build`-class deletable dirs.
- Suite drivers must keep working when invoked directly (`tclsh suite.tcl ...`)
AND via `make.tcl buildsuite build <name>` (which forwards args untouched).
## Verification
- `tclsh src/make.tcl buildsuite list` shows every suite with its description.
- `tclsh src/make.tcl buildsuite info <name>` renders the manifest-derived
detail for the touched suite.
- Suite pipelines verify per their own README/goal records (test gates vs
tracked expected_test_failures baselines).
## Child DOX Index
- `suite_tcl90/` - Tcl 9.0 suite (its README.md carries lineage/detail; no
child AGENTS.md yet)

70
src/buildsuites/README.md

@ -0,0 +1,70 @@
# src/buildsuites - zig-built runtime factory
Buildsuites build Tcl runtimes (and their binary companions) from external
sources with the pinned zig toolchain. This is an arm's-length subsystem: it
consumes upstream Tcl/Tk/extension sources, not this project's `src/` tree,
and its outputs are runtime executables and artifact families - distinct from
the project build/bake stages driven by the rest of `make.tcl`.
## Layout
- `suite_tcl90/` - the Tcl 9.0 suite (see its README for lineage and detail)
- `_build/` - VCS-ignored build area; each suite stages into `_build/<suitename>`
- other directories without a `suite.tcl` driver are not suites (e.g sample
material) and are ignored by discovery
## The make.tcl surface (G-104)
Run from the projectroot:
tclsh src/make.tcl buildsuite list
tclsh src/make.tcl buildsuite info <suitename>
tclsh src/make.tcl buildsuite build <suitename> ?driver-args ...?
`list` discovers the suites and their one-line descriptions. `info` shows a
suite's configured detail: description, source records (url/ref/pin), the
pinned zig and whether it is present, products, and doc pointers. `build`
runs the suite's driver (`suite.tcl build`) forwarding the given args
untouched (e.g `-tclbranch`, `-refresh`, `-steps`), streams its output, and
exits with the driver's status. The surface works under a plain tclsh and
under punk kit executables.
## Suite self-description contract
A directory under `src/buildsuites` IS a suite when it carries a `suite.tcl`
driver. Its `sources.config` is the suite's manifest - parsed as plain line
records, never executed - read by BOTH the driver and `make.tcl buildsuite
list/info`. Record grammar (whitespace-separated; `#` comments and blanks
ignored):
source <name> <kind> <url> <ref> <dir> source-pull declarations (fossil|git)
description <text...> one line - the suite's list/info one-liner
product <text...> repeatable - what a full build produces
doc <relpath> repeatable - suite-relative doc pointers
zigpin <relpath> projectroot-relative pinned zig executable
Because discovery is a directory scan and description/info are answered by the
suite's own manifest, a copied tree (the copy-and-tweak retargeting workflow -
copy `suite_tcl90/` to `src/buildsuites/<yourname>/`, edit `sources.config`)
appears in `list`/`info` automatically and stages into its own
`_build/<yourname>` - no `make.tcl` edits, ever. A new or forked suite
satisfies the contract by construction: keep `suite.tcl` + `sources.config`
and edit the description/product records to tell the truth about your suite.
The `zigpin` record is the single source of truth for the suite's pinned zig:
`suite.tcl` resolves its default zig from it (precedence: `-zig` option >
`PUNK_ZIG` env > the pin > `zig` on PATH) and `info` reports it with presence
state (`bin/punk-getzig.cmd` fetches pinned zig versions).
## Flows
Each suite offers two equivalent flows (G-102):
- FOSSIL DEV FLOW: `suite.tcl build|test|clean` - live checkouts per
`sources.config` refs (branches may float), staged from the hermetic clone
store (`PUNK_FOSSIL_STORE`, default `~/.punkshell/fossils`).
- NO-TCLSH FLOW: `zig build stage|bootstrap` from the suite directory -
content-hashed per-checkin pins from `build.zig.zon`.
Both delegate the pipeline (configure, compile, install, smoke, test gates)
to the suite's zig recipe steps.

16
src/buildsuites/suite_tcl90/sources.config

@ -41,6 +41,22 @@
# cloned directly from <url> and pinned to <ref>. critcl is fetched lazily -
# only when the tcllibc accelerators need building.
# -- suite self-description records (G-104) --------------------------------
# Consumed by 'make.tcl buildsuite list/info' AND by suite.tcl (same parser
# grammar both sides - the file stays the single manifest). Part of the
# copy-and-tweak surface: edit these for your copied suite so it lists and
# describes itself with no make.tcl edits.
# description <text...> one line - the list/info one-liner for this suite
# product <text...> repeatable - what a full build produces
# doc <relpath> repeatable - suite-relative doc pointers
# zigpin <relpath> projectroot-relative pinned zig executable
description Zig-built Tcl 9.0 windows runtime family: core + thread/tclvfs/Tk + tcllib/tcllibc, core-test gate, punk kit-family artifacts
product tclsh9.0.x runtime family (plain / punk / punk-bi) with attached prefix-mirror image - out/family plus punkbin-layout -r<N> artifacts with toml metadata
product installed lib tree: thread, tclvfs, Tk, tklib, tcllib (+ tcllibc critcl accelerators)
product core testsuite gate vs the tracked expected_test_failures baseline (parsed all.tcl totals)
doc README.md
zigpin bin/tools/zig-x86_64-windows-0.16.0/zig.exe
source tcl fossil https://core.tcl-lang.org/tcl core-9-0-branch tcl905
source tclthread fossil https://core.tcl-lang.org/thread trunk tclthread
# tclvfs forTcl9 branch (user 2026-07-22): trunk is the 1.4.2 era; forTcl9 carries

92
src/buildsuites/suite_tcl90/suite.tcl

@ -71,6 +71,62 @@ set suiteroot [file dirname [file normalize [info script]]]
set stage [file normalize [file join $suiteroot .. _build [file tail $suiteroot]]]
set builddir [file join $stage build]
#-- sources.config load ---------------------------------------------------
#Declared in sources.config (the copy-and-tweak surface for the LIVE-checkout dev
#flow - see its header; build.zig.zon is the equivalent PINNED surface for the
#no-tclsh flow). Parsed as line records - never executed.
#Extended record grammar (G-104 self-description contract - documented in
#src/buildsuites/README.md; 'make.tcl buildsuite list/info' reads the same
#records, so a copied suite self-describes with no make.tcl edits):
# source <name> <kind> <url> <ref> <dir> source-pull declarations (the original records)
# description <text...> one line - the suite's list/info one-liner
# product <text...> repeatable - what the suite produces
# doc <relpath> repeatable - suite-relative doc pointers
# zigpin <relpath> projectroot-relative pinned zig executable
proc load_sources_config {path} {
set config [dict create sources [dict create] description "" products [list] docs [list] zigpin ""]
set f [open $path r]; set data [read $f]; close $f
set ln 0
foreach line [split $data \n] {
incr ln
set line [string trim $line]
if {$line eq "" || [string index $line 0] eq "#"} {continue}
if {[catch {llength $line} len]} {
fail "sources.config line $ln: not a well-formed record: $line"
}
switch -- [lindex $line 0] {
source {
if {$len != 6} {
fail "sources.config line $ln: expected 'source <name> <kind> <url> <ref> <dir>' - got: $line"
}
lassign $line -> name kind url ref dir
if {$kind ni {fossil git}} {
fail "sources.config line $ln: unknown kind '$kind' (expected fossil|git)"
}
dict set config sources $name [dict create kind $kind url $url ref $ref dir $dir]
}
description {
dict set config description [join [lrange $line 1 end] " "]
}
product {
dict lappend config products [join [lrange $line 1 end] " "]
}
doc {
dict lappend config docs [lindex $line 1]
}
zigpin {
dict set config zigpin [lindex $line 1]
}
default {
fail "sources.config line $ln: unknown record type '[lindex $line 0]' (expected source|description|product|doc|zigpin)"
}
}
}
return $config
}
set suiteconfig [load_sources_config [file join $suiteroot sources.config]]
set sources [dict get $suiteconfig sources]
#-- options ---------------------------------------------------------------
set action [lindex $argv 0]
if {$action ni {build test clean}} {
@ -92,8 +148,14 @@ set opt(-seedfossils) [file normalize [file join $env(HOME) .fossils]]
#zig resolution: -zig option > PUNK_ZIG env > the suite's pinned toolchain under
#bin/tools (zig 0.16.0 official release - hosted on punkbin, minisign-verified;
#the recipe is 0.16-API and does NOT build under 0.14/0.15 - see README Lineage)
#> 'zig' on PATH.
set pinned_zig [file normalize [file join $suiteroot .. .. .. bin tools zig-x86_64-windows-0.16.0 zig.exe]]
#> 'zig' on PATH. The pinned path comes from the sources.config 'zigpin' record
#(projectroot-relative; single source of truth shared with 'make.tcl buildsuite
#info') with the historical suite_tcl90 path as fallback when the record is absent.
if {[dict get $suiteconfig zigpin] ne ""} {
set pinned_zig [file normalize [file join $suiteroot .. .. .. [dict get $suiteconfig zigpin]]]
} else {
set pinned_zig [file normalize [file join $suiteroot .. .. .. bin tools zig-x86_64-windows-0.16.0 zig.exe]]
}
if {[info exists env(PUNK_ZIG)]} {
set opt(-zig) $env(PUNK_ZIG)
} elseif {[file exists $pinned_zig]} {
@ -269,29 +331,9 @@ foreach item {build905.zig build_common.zig build_libtommath build_zlib build_tc
}
#-- sources ---------------------------------------------------------------
#Declared in sources.config (the copy-and-tweak surface for the LIVE-checkout dev
#flow - see its header; build.zig.zon is the equivalent PINNED surface for the
#no-tclsh flow). Parsed as line records - never executed.
proc load_sources_config {path} {
set sources [dict create]
set f [open $path r]; set data [read $f]; close $f
set ln 0
foreach line [split $data \n] {
incr ln
set line [string trim $line]
if {$line eq "" || [string index $line 0] eq "#"} {continue}
if {[catch {llength $line} len] || $len != 6 || [lindex $line 0] ne "source"} {
fail "sources.config line $ln: expected 'source <name> <kind> <url> <ref> <dir>' - got: $line"
}
lassign $line -> name kind url ref dir
if {$kind ni {fossil git}} {
fail "sources.config line $ln: unknown kind '$kind' (expected fossil|git)"
}
dict set sources $name [dict create kind $kind url $url ref $ref dir $dir]
}
return $sources
}
set sources [load_sources_config [file join $suiteroot sources.config]]
#(sources.config already loaded near the top - see load_sources_config there;
#$sources holds the source records, $suiteconfig the full record set incl. the
#G-104 self-description records)
foreach required {tcl tclthread tclvfs tk tklib tcllib critcl} {
if {![dict exists $sources $required]} {
fail "sources.config: missing required source record '$required'"

209
src/make.tcl

@ -153,7 +153,7 @@ namespace eval ::punkboot {
variable foldername [file tail $scriptfolder]
variable pkg_requirements [list]; variable pkg_missing [list];variable pkg_loaded [list]
variable help_flags [list -help --help /? -h]
variable known_commands [list bakehouse packages modules libs bake vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow project vfs]
variable known_commands [list bakehouse packages modules libs bake vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow buildsuite project vfs]
}
@ -1563,6 +1563,9 @@ proc ::punkboot::punkboot_gethelp {args} {
append h " - advisory check: verify CHANGELOG.md matches punkproject.toml and warn if src/ has changes since the last project-version bump." \n \n
append h " $scriptname workflow" \n
append h " - print an ASCII data-flow overview of the build/release workflow (edit -> packages -> bootsupport -> kits)" \n \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 " detail (sources/zig pin/products from its sources.config), or run its driver forwarding the args" \n \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 " Deprecated aliases (transition window):" \n
@ -1858,6 +1861,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
workflow "Print an ASCII data-flow overview of the build/release workflow (edit -> packages -> gates -> bake)"
shell "Run the punk shell using bootsupport libraries"
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)"
project "DEPRECATED alias for bakehouse (one-line notice, then runs bakehouse)"
vfs "DEPRECATED alias for bake (one-line notice, then runs bake)"
}
@ -1971,6 +1975,31 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
The text is embedded in make.tcl (::punkboot::workflow_text) so it is
available wherever make.tcl runs; its MAINTENANCE key states the
update contract for keeping it in step with build behaviour."
buildsuite
"
Surface for the defined buildsuites under src/buildsuites (zig-built
runtime factory - an arm's-length subsystem building Tcl runtimes
from external sources, distinct from the project build/bake stages).
Actions:
buildsuite list
Discover the suites (directories carrying a suite.tcl driver;
_build excluded) with their one-line descriptions.
buildsuite info <name>
Show the suite's configured detail: description, source records
(name/kind/url/ref/dir from sources.config), pinned zig and its
resolution, products, doc pointers.
buildsuite build <name> ?driver-args ...?
Run the suite's driver ('suite.tcl build' with the given args
forwarded untouched, e.g -tclbranch/-refresh/-steps), streaming
its output and exiting with the driver's status.
Suites are SELF-describing: list/info read each suite's
sources.config records (description/product/doc/zigpin - the same
manifest the suite.tcl driver parses), so a copied/retargeted tree
(copy-and-tweak workflow) appears here automatically with no
make.tcl edits. The contract is documented in
src/buildsuites/README.md."
project
"
DEPRECATED alias for 'bakehouse' (G-112 stage-true rename) - prints a
@ -2084,6 +2113,15 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
{@values -min 0 -max -1
arg -type any -optional 1 -multiple 1 -help\
"Arguments passed through to the punk repl."}
punk::args::define\
"@id -id (script)::punkboot::buildsuite"\
"@normalize"\
"@cmd -name [list "make.tcl buildsuite"] -summary [list [dict get $SUMMARIES buildsuite]] -help [list [dict get $HELPTEXTS buildsuite]]"\
{@form -synopsis "make.tcl buildsuite list|info|build ?<suitename>? ?driver-args ...?"}\
{@values -min 0 -max -1
arg -type any -optional 1 -multiple 1 -help\
"Action (list|info|build), suite name, and - for build - driver
arguments forwarded to the suite's suite.tcl untouched."}
punk::args::define\
"@id -id (script)::punkboot::help"\
"@normalize"\
@ -2099,6 +2137,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
"build & bake" {bakehouse packages modules libs bake vfslibs bin}
"promotion gates" {bootsupport vfscommonupdate}
"source maintenance" {vendorupdate}
"buildsuites" {buildsuite}
"informational" {info check projectversion workflow help}
"interactive" {shell}
"deprecated aliases" {project vfs}
@ -2184,6 +2223,11 @@ if {$::punkboot::punkargs_ok} {
} elseif {$subcommand eq "shell"} {
#declared passthrough: everything after 'shell' goes to the repl unparsed
set ::punkboot::command shell
} elseif {$subcommand eq "buildsuite"} {
#declared passthrough: the handler parses action/name itself; driver
#args (arbitrary suite flags) are forwarded untouched (G-104)
set ::punkboot::command buildsuite
set ::punkboot::bs_args $subargs
} else {
if {[catch {punk::args::parse $subargs -errorstyle $::punkboot::errstyle withid (script)::punkboot::$subcommand} argd]} {
puts stderr $argd
@ -2204,6 +2248,13 @@ if {$::punkboot::punkargs_ok} {
#unavailable). Keeps check/bootsupport/modules and the -k/-dirty-abort/-confirm flags working.
set commands_found [list]
set argsleft $scriptargs
if {[lindex $scriptargs 0] eq "buildsuite"} {
#declared passthrough (as in the punk::args path): driver args carry
#arbitrary suite flags the fallback flag scan must not consume (G-104)
set commands_found [list buildsuite]
set argsleft [list]
set ::punkboot::bs_args [lrange $scriptargs 1 end]
}
while {[llength $argsleft]} {
set a [lindex $argsleft 0]
set argsleft [lrange $argsleft 1 end]
@ -2319,7 +2370,7 @@ set forcekill $::punkboot::opt_forcekill
# - patch bump -> warn and proceed (non-breaking)
# 'check' is exempt in all cases the warning is shown at the end of its output instead.
# 'projectversion' and 'workflow' are informational/read-only and are likewise exempt.
if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ni {check projectversion workflow}} {
if {[info exists ::punkboot::stale_bootsupport] && $::punkboot::command ni {check projectversion workflow buildsuite}} {
set _stale $::punkboot::stale_bootsupport
set _have_major 0
set _have_minor 0
@ -2867,6 +2918,160 @@ if {$::punkboot::command eq "workflow"} {
exit 0
}
if {$::punkboot::command eq "buildsuite"} {
#G-104: thin front for the buildsuites (zig runtime factory - arm's-length
#subsystem building Tcl runtimes from external sources). Discovery is a
#directory scan; description/info come from each suite's sources.config
#records (description/product/doc/zigpin - the same manifest the suite.tcl
#driver parses), so copied/retargeted trees are first-class with no edits
#here. Contract: src/buildsuites/README.md.
set bs_root [file join $sourcefolder buildsuites]
if {![info exists ::punkboot::bs_args]} {set ::punkboot::bs_args [list]}
set bsargs $::punkboot::bs_args
set bs_action [lindex $bsargs 0]
if {$bs_action eq ""} {set bs_action list}
#tolerant manifest reader (make.tcl side): a suite with a malformed or absent
#sources.config still lists - with the problem as its description - rather
#than breaking discovery of the others. suite.tcl's own parser stays strict.
proc ::punkboot::buildsuite_manifest {suitedir} {
set m [dict create description "" products [list] docs [list] zigpin "" sources [list] note ""]
set cfg [file join $suitedir sources.config]
if {![file exists $cfg]} {
dict set m note "(no sources.config manifest)"
return $m
}
if {[catch {
set f [open $cfg r]; set data [read $f]; close $f
foreach line [split $data \n] {
set line [string trim $line]
if {$line eq "" || [string index $line 0] eq "#"} {continue}
if {[catch {llength $line}]} {continue}
switch -- [lindex $line 0] {
source {dict lappend m sources [lrange $line 1 end]}
description {dict set m description [join [lrange $line 1 end] " "]}
product {dict lappend m products [join [lrange $line 1 end] " "]}
doc {dict lappend m docs [lindex $line 1]}
zigpin {dict set m zigpin [lindex $line 1]}
}
}
} cfgerr]} {
dict set m note "(sources.config unreadable: $cfgerr)"
}
return $m
}
proc ::punkboot::buildsuite_dirs {bs_root} {
set dirs [list]
foreach dir [lsort [glob -nocomplain -dir $bs_root -type d *]] {
if {[file tail $dir] eq "_build"} {continue}
if {![file exists [file join $dir suite.tcl]]} {continue} ;#not a suite (no driver)
lappend dirs $dir
}
return $dirs
}
switch -- $bs_action {
list {
set suitedirs [::punkboot::buildsuite_dirs $bs_root]
if {![llength $suitedirs]} {
puts stdout "no buildsuites found under $bs_root (a suite = a directory carrying a suite.tcl driver)"
exit 0
}
puts stdout "buildsuites under $bs_root:"
foreach dir $suitedirs {
set m [::punkboot::buildsuite_manifest $dir]
set desc [dict get $m description]
if {$desc eq ""} {set desc [dict get $m note]}
if {$desc eq ""} {set desc "(no description record in sources.config)"}
puts stdout [format " %-16s %s" [file tail $dir] $desc]
}
puts stdout ""
puts stdout " - 'make.tcl buildsuite info <name>' shows a suite's configured detail"
puts stdout " - 'make.tcl buildsuite build <name> ?driver-args ...?' runs its driver"
exit 0
}
info {
set bs_name [lindex $bsargs 1]
if {$bs_name eq ""} {
puts stderr "usage: make.tcl buildsuite info <suitename> ('make.tcl buildsuite list' shows the names)"
exit 2
}
set dir [file join $bs_root $bs_name]
if {![file isdirectory $dir] || ![file exists [file join $dir suite.tcl]]} {
puts stderr "buildsuite '$bs_name' not found (no [file join $dir suite.tcl]) - 'make.tcl buildsuite list' shows the suites"
exit 2
}
set m [::punkboot::buildsuite_manifest $dir]
puts stdout "buildsuite: $bs_name"
puts stdout " path: $dir"
if {[dict get $m note] ne ""} {puts stdout " note: [dict get $m note]"}
if {[dict get $m description] ne ""} {puts stdout " description: [dict get $m description]"}
if {[llength [dict get $m sources]]} {
puts stdout " sources (sources.config - the live dev-flow refs; the 'zig build' flow pins per-checkin via build.zig.zon):"
puts stdout [format " %-10s %-7s %-40s %-16s %s" name kind url ref dir]
foreach s [dict get $m sources] {
lassign $s sname skind surl sref sdir
puts stdout [format " %-10s %-7s %-40s %-16s %s" $sname $skind $surl $sref $sdir]
}
}
set zigpin [dict get $m zigpin]
if {$zigpin ne ""} {
set pinpath [file normalize [file join $projectroot $zigpin]]
set pinstate [expr {[file exists $pinpath] ? "present" : "NOT PRESENT (bin/punk-getzig.cmd can fetch it)"}]
puts stdout " zig pin: $zigpin ($pinstate)"
} else {
puts stdout " zig pin: (no zigpin record in sources.config)"
}
if {[info exists ::env(PUNK_ZIG)]} {
puts stdout " zig via env: PUNK_ZIG=$::env(PUNK_ZIG) (overrides the pin for driver runs)"
}
foreach p [dict get $m products] {
puts stdout " product: $p"
}
foreach d [dict get $m docs] {
puts stdout " doc: [file join $dir $d]"
}
exit 0
}
build {
set bs_name [lindex $bsargs 1]
if {$bs_name eq ""} {
puts stderr "usage: make.tcl buildsuite build <suitename> ?driver-args ...?"
exit 2
}
set dir [file join $bs_root $bs_name]
set driver [file join $dir suite.tcl]
if {![file exists $driver]} {
puts stderr "buildsuite '$bs_name' not found (no $driver) - 'make.tcl buildsuite list' shows the suites"
exit 2
}
set fwdargs [lrange $bsargs 2 end]
#interpreter for the driver: this tclsh - or, punk-exe-hosted (the
#G-058 static-capture marker identifies a kit boot), the kit's
#'script' subcommand so the driver runs with plain script semantics
set launcher [list [info nameofexecutable]]
if {[info exists ::punkboot::static_packages]} {
set launcher [list [info nameofexecutable] script]
}
puts stdout "buildsuite build $bs_name: running '$driver build' with forwarded args: $fwdargs"
flush stdout
#stream driver output; exit with the driver's status
if {[catch {exec {*}$launcher $driver build {*}$fwdargs >@stdout 2>@stderr} execerr execopts]} {
set ecode [dict get $execopts -errorcode]
if {[lindex $ecode 0] eq "CHILDSTATUS"} {
exit [lindex $ecode 2]
}
puts stderr "buildsuite build $bs_name: failed to run the driver: $execerr"
exit 1
}
exit 0
}
default {
puts stderr "unknown buildsuite action '$bs_action' - expected list|info|build"
puts stderr "usage: make.tcl buildsuite list|info|build ?<suitename>? ?driver-args ...?"
exit 2
}
}
}
if {$::punkboot::command eq "shell"} {
#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).

Loading…
Cancel
Save