diff --git a/CHANGELOG.md b/CHANGELOG.md index decb57c6..ad0841e4 100644 --- a/CHANGELOG.md +++ b/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 ` renders the suite's configured detail + (sources.config records, pinned zig + presence, products, doc pointers); `buildsuite + build ?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 diff --git a/goals/G-104-maketcl-buildsuite-surface.md b/goals/G-104-maketcl-buildsuite-surface.md index b28a9145..5c260eee 100644 --- a/goals/G-104-maketcl-buildsuite-surface.md +++ b/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 diff --git a/src/AGENTS.md b/src/AGENTS.md index 5aaa6505..870fcb13 100644 --- a/src/AGENTS.md +++ b/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) diff --git a/src/buildsuites/AGENTS.md b/src/buildsuites/AGENTS.md new file mode 100644 index 00000000..e0bf5f64 --- /dev/null +++ b/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/`. + +## 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 ` (which forwards args untouched). + +## Verification + +- `tclsh src/make.tcl buildsuite list` shows every suite with its description. +- `tclsh src/make.tcl buildsuite info ` 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) diff --git a/src/buildsuites/README.md b/src/buildsuites/README.md new file mode 100644 index 00000000..682794bb --- /dev/null +++ b/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/` +- 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 + tclsh src/make.tcl buildsuite build ?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 source-pull declarations (fossil|git) + description one line - the suite's list/info one-liner + product repeatable - what a full build produces + doc repeatable - suite-relative doc pointers + zigpin 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//`, edit `sources.config`) +appears in `list`/`info` automatically and stages into its own +`_build/` - 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. diff --git a/src/buildsuites/suite_tcl90/sources.config b/src/buildsuites/suite_tcl90/sources.config index ddf06589..6c2e2476 100644 --- a/src/buildsuites/suite_tcl90/sources.config +++ b/src/buildsuites/suite_tcl90/sources.config @@ -41,6 +41,22 @@ # cloned directly from and pinned to . 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 one line - the list/info one-liner for this suite +# product repeatable - what a full build produces +# doc repeatable - suite-relative doc pointers +# zigpin 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 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 diff --git a/src/buildsuites/suite_tcl90/suite.tcl b/src/buildsuites/suite_tcl90/suite.tcl index 2e6760c0..55c9a161 100644 --- a/src/buildsuites/suite_tcl90/suite.tcl +++ b/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 source-pull declarations (the original records) +# description one line - the suite's list/info one-liner +# product repeatable - what the suite produces +# doc repeatable - suite-relative doc pointers +# zigpin 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 ' - 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 ' - 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'" diff --git a/src/make.tcl b/src/make.tcl index 08a5656a..43fe1b23 100644 --- a/src/make.tcl +++ b/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 ?? ?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 -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 + 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 ?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 ?? ?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 ' shows a suite's configured detail" + puts stdout " - 'make.tcl buildsuite build ?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 ('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 ?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 ?? ?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).