Browse Source

G-139 phase 2 increment 1: PACKAGES_tcl<N> deployment + vfslibs packages-root declarations (0.31.1)

make.tcl libs/packages/bakehouse gain the PACKAGES_tcl<N> phase: materialized
punkbin lib-tier packages under bin/packages/<target>/tcl<N>/ deploy into
lib_tcl<N>/allplatforms + lib_tcl<N>/<this platform> with punkcheck
provenance, mirroring the VENDORLIB_tcl<N> shape (embedded
punkbin-artifact.toml records ride into the deployed trees; absent tier =
silent per-item no-op with a libfetch pointer).

vfslibs declaration schema extended (vendorlib_vfs.toml header documents
both): source_root = "packages" resolves an entry's source against the
bin/packages tier (missing source errors name 'make.tcl libfetch');
replace = true clean-slates a SAME-NAMED existing target folder before
install (supersedes deliberately cannot name the folder being installed -
needed because the pre-G-139 tcl9 hand-drops nested md5c + tcllibc INSIDE
tcllib2.0).

Declarations added for the switchover set (per-kit, never blanket - the
trees that carried hand-drops at 2026-07-30): 8 win32 tcl9 kit vfs trees get
tcllib2.0-tcl9 + tcllibc-tcl9 (supersedes the stray-named tcllibc2.0);
punk9linux (linux target) gets only platform-neutral tcllib2.0 (its
linux-built tcllibc siblings stay - a linux lib-tier emission is future
work); punk86/punk8win/punk8_statictwapi upgrade tcllib1.21 (+nested tcllibc
0.4 + md5c, removed with it via supersedes) to tcllib2.0-tcl8 + tcllibc-tcl8;
punk86bawt refreshes its bare tcllibc only.

Verified: make.tcl libs deployed the tier into lib_tcl8|9 (allplatforms +
win32-x86_64) with embedded records present; vendored mirrors coexist in the
deployed trees until the sequenced retirement. Thin-layout make.tcl sync
copies updated by the run (punkcheck-managed outputs, batched per the
carve-out). Project 0.31.1 + CHANGELOG.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 1 day ago
parent
commit
e7e2ec81f4
  1. 16
      CHANGELOG.md
  2. 2
      punkproject.toml
  3. 71
      src/make.tcl
  4. 455
      src/modules/punk/mix/#modpod-templates-999999.0a1.0/templates/project_layouts/vendor/punk/project-0.1/src/make.tcl
  5. 455
      src/project_layouts/vendor/punk/basic/src/make.tcl
  6. 455
      src/project_layouts/vendor/punk/project-0.1/src/make.tcl
  7. 86
      src/runtime/vendorlib_vfs.toml

16
CHANGELOG.md

@ -5,6 +5,22 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to
Entries are newest-first; one bullet per notable change. See the root `AGENTS.md`
"Project Versioning" section for the bump policy.
## [0.31.1] - 2026-07-30
- `make.tcl libs`/`packages`/`bakehouse` gain the PACKAGES_tcl<N> phase
(G-139): materialized punkbin lib-tier packages under `bin/packages/`
deploy into `lib_tcl<N>/allplatforms` + `lib_tcl<N>/<platform>` with
punkcheck provenance (silent no-op when the tier is absent). The vfslibs
declaration schema (`src/runtime/vendorlib_vfs.toml`) gains `source_root =
"packages"` (sources resolved against the bin/packages tier, with an
actionable libfetch hint when missing) and `replace = true` (clean-slate
same-name refresh - supersedes deliberately cannot name the folder being
installed). tcllib/tcllibc enter the kit vfs declarations: tcl9 kits
switch their hand-dropped tcllib2.0 (which nested md5c/tcllibc) to the
suite-built artifact pair; tcl8 kits upgrade tcllib1.21 (+nested tcllibc
0.4/md5c) to tcllib 2.0 + current tcllibc via supersedes; punk9linux
(linux target) gets only the platform-neutral tcllib2.0.
## [0.31.0] - 2026-07-30
- New `make.tcl libfetch` subcommand (G-139 phase 1): fetches the punkbin

2
punkproject.toml

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

71
src/make.tcl

@ -5618,6 +5618,36 @@ if {$::punkboot::command in {bakehouse packages libs}} {
if {![llength $vendorlibfolders]} {
puts stderr "$A(BAD)VENDORLIB: No src/vendorlib or src/vendorlib_tcl* folder found.$A(RST)"
}
#G-139: punkbin lib-tier packages from the bin/packages input tier (populated
#by 'make.tcl libfetch') into the deployed lib_tcl<N> trees - allplatforms +
#this host's platform dir, mirroring the vendorlib_tcl<N> shape above. The
#materialized trees are self-describing (embedded punkbin-artifact.toml
#records - G-138) and the records ride along into the deployed trees, and
#from there into kit vfs payloads via the vfslibs declarations. An absent
#tier (or target/generation subdir) is a silent per-item no-op: the tier is
#fetch-regenerable and optional until artifacts are declared and fetched.
set packages_root $projectroot/bin/packages
if {[file isdirectory $packages_root]} {
foreach ptarget [list allplatforms $this_platform_generic] {
foreach gendir [lsort [glob -nocomplain -dir $packages_root/$ptarget -type d tcl*]] {
set which [file tail $gendir] ;#tcl8|tcl9 ...
foreach pkgdir [lsort [glob -nocomplain -dir $gendir -type d *]] {
set pkgtail [file tail $pkgdir]
set target_lib_folder $projectroot/lib_$which/$ptarget
file mkdir $target_lib_folder
puts stdout "PACKAGES_$which: copying $ptarget/$which/$pkgtail from the bin/packages tier to $target_lib_folder (if source file changed)"
set resultdict [punkcheck::install $pkgdir $target_lib_folder/$pkgtail\
-createdir 1\
-overwrite installedsourcechanged-targets\
-progresschannel stdout\
]
puts stdout [punkcheck::summarize_install_resultdict $resultdict]
}
}
}
} else {
puts stdout "PACKAGES: no bin/packages tier at $packages_root (populate via 'make.tcl libfetch') - skipping lib-tier package deployment"
}
}
if {$::punkboot::command in {bakehouse bake vfslibs}} {
@ -5672,9 +5702,42 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
if {[dict exists $ientry supersedes]} {
set isupersedes [punkboot::lib::toml_untag [dict get $ientry supersedes]]
}
set source_pkg_folder $sourcefolder/$isource
#source_root (G-139): 'src' (default - the original vendorlib
#declarations) or 'packages' - resolve against the untracked
#bin/packages lib-tier input (populated by 'make.tcl libfetch').
set isource_root "src"
if {[dict exists $ientry source_root]} {
set isource_root [punkboot::lib::toml_untag [dict get $ientry source_root]]
}
#replace (G-139): clean-slate a SAME-NAMED existing target folder
#before install. supersedes deliberately cannot name the folder being
#installed; replace covers same-name refreshes where the old copy may
#carry strays the new tree lacks (e.g. hand-drops nesting md5c/tcllibc
#inside tcllib2.0).
set ireplace 0
if {[dict exists $ientry replace]} {
set ireplace [punkboot::lib::toml_untag [dict get $ientry replace]]
if {![string is boolean -strict $ireplace]} {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname 'replace' must be boolean (got '$ireplace')$A(RST)"
exit 3
}
}
switch -- $isource_root {
src {
set source_pkg_folder $sourcefolder/$isource
set source_missing_hint ""
}
packages {
set source_pkg_folder $projectroot/bin/packages/$isource
set source_missing_hint " - populate the bin/packages tier first: 'tclsh src/make.tcl libfetch' (declarations in src/runtime/libpackages.toml)"
}
default {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname has unknown source_root '$isource_root' (expected src|packages)$A(RST)"
exit 3
}
}
if {![file isdirectory $source_pkg_folder]} {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname source '$isource' not found at $source_pkg_folder$A(RST)"
puts stderr "$A(BAD)VFSLIBS: entry install.$iname source '$isource' not found at $source_pkg_folder$source_missing_hint$A(RST)"
exit 3
}
set pkgtail [file tail $source_pkg_folder]
@ -5704,6 +5767,10 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
file delete -force $suppath
}
}
if {$ireplace && [file isdirectory $target_lib_folder/$pkgtail]} {
puts stdout "VFSLIBS install.$iname: replace=true - removing existing '$pkgtail' from vfs/$t (clean-slate install)"
file delete -force $target_lib_folder/$pkgtail
}
puts stdout "VFSLIBS install.$iname: $isource -> vfs/$t/$pkgtail (if source file changed)"
set resultdict [punkcheck::install $source_pkg_folder $target_lib_folder/$pkgtail\
-installer make.tcl\

455
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 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 bakelist vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow buildsuite tool project vfs]
variable known_commands [list bakehouse packages modules libs bake bakelist vfslibs bin info check shell vendorupdate libfetch bootsupport vfscommonupdate projectversion workflow buildsuite tool project vfs]
}
@ -2135,6 +2135,10 @@ proc ::punkboot::punkboot_gethelp {args} {
append h " - propagate declared vendored platform-library packages into kit vfs lib_tcl<N> trees" \n
append h " - declarations (per-package per-kit, with superseded-version removal) live in src/runtime/vendorlib_vfs.toml" \n
append h " - also runs automatically as a phase of '$scriptname bake' (and therefore of '$scriptname bakehouse')" \n \n
append h " $scriptname libfetch ?-serverurl <url>? ?-trust-server? ?-force?" \n
append h " - fetch declared punkbin lib-tier library artifacts (src/runtime/libpackages.toml) into bin/packages/<target>" \n
append h " - sha1-verified against the server's per-target sha1sums.txt; materializes package trees under bin/packages/<target>/tcl<N>" \n
append h " - canonical origin trusted by default; other servers (incl. PUNKBIN_URL overrides) require -trust-server" \n \n
append h " $scriptname vfscommonupdate" \n
append h " - promotion gate: update the src/vfs/_vfscommon.vfs from compiled src/modules and src/lib etc" \n
append h " - before calling this (followed by '$scriptname bake') - you can test using '<builtexe>(.exe) dev'" \n
@ -2323,6 +2327,26 @@ DIAGRAM 2 - KIT ASSEMBLY DETAIL (the 'make.tcl bake' stage; incl. vfslibs phase)
running shell still holds the old exe [K5]
LIBRARY-ARTIFACT FETCH (G-139; input tier so far - lib_tcl<N>/kit consumption follows)
----------------------------------------------------------------------------
src/runtime/libpackages.toml which punkbin LIB-TIER artifacts this checkout
consumes (declared artifact names + targets)
|
| 'make.tcl libfetch' - sha1-verified download of the declared
| <pkg>-<tcl8|tcl9>-r<N>.zip artifacts + .toml sidecars from
| <origin>/lib/<target>/ (canonical punkbin origin trusted by
| default; -serverurl/PUNKBIN_URL override needs -trust-server;
| file:// origins serve local mirrors/fixtures), then
| materialization of each verified zip's package tree
v
bin/packages/<target>/ verified -r<N> zips + toml sidecars (input tier,
untracked - mirrors bin/runtime/<target>)
bin/packages/<target>/tcl<N>/<pkgfolder>/
materialized installed-shape trees, self-describing
via their embedded punkbin-artifact.toml records
KEY / NOTES
----------------------------------------------------------------------------
[K1] Source modules carry the literal magic version 999999.0a1.0 in the filename.
@ -2527,6 +2551,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
vfslibs "Propagate declared vendored platform-library packages into kit vfs lib_tcl<N> trees"
bin "Install executables from src/bin into <projectdir>/bin, then build kits as for bake"
vendorupdate "Update src/vendormodules based on src/vendormodules/include_modules.config"
libfetch "Fetch declared punkbin lib-tier library artifacts into bin/packages/<target> (sha1-verified) and materialize the package trees"
bootsupport "Promotion gate: update src/bootsupport modules from built project modules"
vfscommonupdate "Promotion gate: replace src/vfs/_vfscommon.vfs modules and libs with the project's built set"
info "Show the name and base folder of the project to be built"
@ -2630,6 +2655,24 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
Also runs automatically as a phase of 'make.tcl bake' (and therefore
of 'make.tcl bakehouse'); this standalone narrowing serves quick
iteration on the declarations."
libfetch
"
Fetch the punkbin LIB-TIER library artifacts declared in
src/runtime/libpackages.toml into the untracked input tier
bin/packages/<target>/ - immutable <pkg>-<tcl8|tcl9>-r<N>.zip
artifacts plus their .toml sidecars, each verified against the
server's per-target sha1sums.txt - then materialize each verified
zip's installed-shape package tree under
bin/packages/<target>/tcl<N>/ (self-describing via the embedded
punkbin-artifact.toml record; G-138/G-139).
Present artifacts that already verify are skipped (-force
re-downloads). The canonical punkbin origin is trusted by
default; -serverurl (or env PUNKBIN_URL) overrides it, and any
NON-canonical origin requires the explicit -trust-server flag
(never an interactive prompt - unattended runs stay unattended).
A file:// origin is supported for local mirrors/fixtures.
Transport for http(s): Tcl http+tls when loadable, else curl,
else PowerShell (windows)."
bin
"
Install executables from src/bin to <projectdir>/bin, then check vfs
@ -2799,6 +2842,30 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
(packages -> test -> bootsupport/vfscommonupdate -> commit -> bake).
Pass -dirty-abort 0 to build anyway with PROVENANCE-WARNINGs."
}
#libfetch fragments (G-139): consent is keyed to SERVER TRUST (the G-123
#posture) - the canonical punkbin origin needs no acknowledgement, any
#other origin needs the explicit flag. Never an interactive prompt.
variable OPT_SERVERURL {
-serverurl -type string -default "" -help\
"Artifact server base url override (default: the canonical punkbin
origin; env PUNKBIN_URL overrides the default, this flag overrides
both). The lib tier is addressed as <serverurl>/lib/<target>/.
file:// urls are supported for local mirrors and fixtures.
A NON-canonical origin additionally requires -trust-server."
}
variable OPT_TRUSTSERVER {
-trust-server -type none -default 0 -help\
"Acknowledge fetching from a NON-canonical artifact server
(consent keyed to server trust - the interim G-123/G-006
mechanism). Without this flag, a non-canonical -serverurl or
PUNKBIN_URL aborts before any network access. Fetches from the
canonical origin never require it."
}
variable OPT_FORCE {
-force -type none -default 0 -help\
"Re-download and re-materialize even when a present artifact
already verifies against the server sha1sums."
}
#which shared option fragments each subcommand declares
#(shell and help have bespoke definitions below: shell passes trailing args
# through to the repl untouched, help takes a subject value)
@ -2812,6 +2879,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
vfslibs {OPT_DIRTYABORT OPT_CONFIRM}
bin {OPT_FORCEKILL OPT_DIRTYABORT OPT_CONFIRM}
vendorupdate {OPT_CONFIRM}
libfetch {OPT_SERVERURL OPT_TRUSTSERVER OPT_FORCE}
bootsupport {OPT_DIRTYABORT OPT_CONFIRM}
vfscommonupdate {OPT_DIRTYABORT OPT_CONFIRM}
info {OPT_CONFIRM}
@ -2829,6 +2897,9 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
OPT_DIRTYABORT "?-dirty-abort?"
OPT_DIRTYABORT_ON "?-dirty-abort 1|0?"
OPT_CONFIRM "?-confirm 0|1?"
OPT_SERVERURL "?-serverurl <url>?"
OPT_TRUSTSERVER "?-trust-server?"
OPT_FORCE "?-force?"
}
#per-subcommand positional values (default: none). bake (and its deprecated
#alias vfs) and bakelist take optional kit names (G-121 selective bake).
@ -2940,7 +3011,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
variable SUBGROUPS {
"build & bake" {bakehouse packages modules libs bake vfslibs bin}
"promotion gates" {bootsupport vfscommonupdate}
"source maintenance" {vendorupdate}
"source maintenance" {vendorupdate libfetch}
"buildsuites" {buildsuite}
"vendored tools" {tool}
"informational" {info check bakelist projectversion workflow help}
@ -2996,6 +3067,9 @@ set help_exitcode 0
set ::punkboot::opt_forcekill 0
set ::punkboot::opt_dirty_abort 0
set ::punkboot::opt_confirm 1
set ::punkboot::opt_serverurl ""
set ::punkboot::opt_trust_server 0
set ::punkboot::opt_force 0
set ::punkboot::opt_kitnames [list] ;#G-121: requested kit names for bake/bakelist (empty = all configured)
if {$::punkboot::punkargs_ok} {
@ -3046,7 +3120,7 @@ if {$::punkboot::punkargs_ok} {
}
set ::punkboot::command $subcommand
set _opts [dict get $argd opts]
foreach {_optname _var} {-k opt_forcekill -dirty-abort opt_dirty_abort -confirm opt_confirm} {
foreach {_optname _var} {-k opt_forcekill -dirty-abort opt_dirty_abort -confirm opt_confirm -serverurl opt_serverurl -trust-server opt_trust_server -force opt_force} {
if {[dict exists $_opts $_optname]} {
set ::punkboot::$_var [dict get $_opts $_optname]
}
@ -3083,6 +3157,12 @@ if {$::punkboot::punkargs_ok} {
switch -- $a {
-k {set ::punkboot::opt_forcekill 1}
-dirty-abort {set ::punkboot::opt_dirty_abort 1}
-trust-server {set ::punkboot::opt_trust_server 1}
-force {set ::punkboot::opt_force 1}
-serverurl {
set ::punkboot::opt_serverurl [lindex $argsleft 0]
set argsleft [lrange $argsleft 1 end]
}
-confirm {
set v [lindex $argsleft 0]
set argsleft [lrange $argsleft 1 end]
@ -5121,6 +5201,303 @@ if {$::punkboot::command eq "bootsupport"} {
if {$::punkboot::command eq "libfetch"} {
#G-139 phase 1: fetch the punkbin LIB-TIER artifacts declared in
#src/runtime/libpackages.toml into the untracked bin/packages/<target> input
#tier (mirroring bin/runtime/<target>) with sha1 verification against the
#server's per-target sha1sums.txt, then materialize each verified zip's
#installed-shape package tree under bin/packages/<target>/tcl<N>/ (the tree
#is self-describing via its embedded punkbin-artifact.toml - the G-138
#record). Consumption into lib_tcl<N>/ and kit vfs trees is the remainder
#of G-139 - this entrypoint owns fetch + verify + materialize only.
proc ::punkboot::libfetch_transfer {url outfile} {
#one url -> local file. file:// is served natively (local mirrors,
#fixtures - no network, no external tools). http(s) transports in
#order: Tcl http (+tls for https) when loadable, curl (ubiquitous,
#including stock windows 10+), powershell Invoke-WebRequest (windows).
#Returns the transport used; errors when all fail.
file mkdir [file dirname $outfile]
if {[string match -nocase "file://*" $url]} {
set path [string range $url 7 end]
if {[regexp {^/+([A-Za-z]:/.*)$} $path -> winpath]} {
set path $winpath ;#file:///C:/x -> C:/x
}
if {![file isfile $path]} {
error "file origin has no such file: $path"
}
file copy -force $path $outfile
return "file-copy"
}
set is_https [string match -nocase "https://*" $url]
set tcl_http_ok 0
if {![catch {package require http}]} {
if {!$is_https} {
set tcl_http_ok 1
} elseif {![catch {package require tls}]} {
catch {http::register https 443 [list ::tls::socket -autoservername true]}
set tcl_http_ok 1
}
}
if {$tcl_http_ok} {
set fd [open $outfile wb]
set ok 0
if {![catch {http::geturl $url -channel $fd -binary 1} tok]} {
if {[http::status $tok] eq "ok" && [http::ncode $tok] == 200} {set ok 1}
http::cleanup $tok
}
close $fd
if {$ok} {return "tcl-http"}
file delete -force $outfile
}
set curl [auto_execok curl]
if {$curl ne ""} {
if {![catch {exec {*}$curl --fail -sSL -o $outfile $url 2>@1} curlerr]} {
return "curl"
}
file delete -force $outfile
}
if {$::tcl_platform(platform) eq "windows"} {
set ps [auto_execok powershell]
if {$ps ne ""} {
set pscmd "\$ProgressPreference='SilentlyContinue'; Invoke-WebRequest -Uri '$url' -OutFile '$outfile' -ErrorAction Stop"
if {![catch {exec {*}$ps -NoProfile -NonInteractive -Command $pscmd 2>@1} pserr]} {
return "powershell"
}
file delete -force $outfile
}
}
set detail ""
if {[info exists curlerr]} {set detail " (curl: [string range $curlerr 0 200])"}
error "all transports failed for $url$detail"
}
set libfetch_config $sourcefolder/runtime/libpackages.toml
#Canonical origin: the punkbin raw-file base (the punk-runtime.cmd
#convention; lib tier addressed as <origin>/lib/<target>/...).
#Server-trust consent (G-139, the G-123 posture): the canonical origin
#never gates; ANY other origin - flag or PUNKBIN_URL env - requires the
#explicit -trust-server flag. Never an interactive prompt: unattended
#runs stay unattended, and refusal happens before any network access.
set libfetch_canonical "https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master"
set libfetch_origin $libfetch_canonical
if {[info exists ::env(PUNKBIN_URL)] && $::env(PUNKBIN_URL) ne ""} {
set libfetch_origin $::env(PUNKBIN_URL)
}
if {$::punkboot::opt_serverurl ne ""} {
set libfetch_origin $::punkboot::opt_serverurl
}
set libfetch_origin [string trimright $libfetch_origin /]
if {$libfetch_origin ne $libfetch_canonical && !$::punkboot::opt_trust_server} {
puts stderr "$A(BAD)LIBFETCH: origin '$libfetch_origin' is not the canonical punkbin origin$A(RST)"
puts stderr "LIBFETCH: canonical: $libfetch_canonical"
puts stderr "LIBFETCH: fetching from a non-canonical server requires the explicit -trust-server flag (consent keyed to server trust - G-139/G-123). Nothing was fetched."
exit 3
}
if {![file exists $libfetch_config]} {
puts stdout "LIBFETCH: no config at $libfetch_config - nothing declared, nothing to fetch"
} else {
if {[catch {package require tomlish} tomlish_err]} {
puts stderr "$A(BAD)LIBFETCH: cannot process $libfetch_config - tomlish package unavailable ($tomlish_err)$A(RST)"
exit 3
}
if {[catch {package require sha1} sha1_err]} {
puts stderr "$A(BAD)LIBFETCH: sha1 package unavailable ($sha1_err) - cannot verify artifacts$A(RST)"
exit 3
}
if {[catch {package require punk::zip} punkzip_err]} {
puts stderr "$A(BAD)LIBFETCH: punk::zip package unavailable ($punkzip_err) - cannot materialize package trees$A(RST)"
exit 3
}
set fd [open $libfetch_config r]
fconfigure $fd -encoding utf-8
set libfetch_tomldata [read $fd]
close $fd
if {[catch {tomlish::to_dict [tomlish::from_toml $libfetch_tomldata]} libfetch_dict]} {
puts stderr "$A(BAD)LIBFETCH: failed to parse $libfetch_config\n$libfetch_dict$A(RST)"
exit 3
}
if {![llength [info commands ::punkboot::lib::toml_untag]]} {
#tomlish::to_dict values are type-tagged (also defined by the vfslibs
#phase - that block does not run for the libfetch command)
proc ::punkboot::lib::toml_untag {tagged} {
if {[dict get $tagged type] eq "ARRAY"} {
set plain [list]
foreach el [dict get $tagged value] {
lappend plain [::punkboot::lib::toml_untag $el]
}
return $plain
}
return [dict get $tagged value]
}
}
set libfetch_artifacts [dict create]
if {[dict exists $libfetch_dict artifact]} {
set libfetch_artifacts [dict get $libfetch_dict artifact]
}
if {![dict size $libfetch_artifacts]} {
puts stdout "LIBFETCH: no \[artifact.<name>\] entries found in $libfetch_config"
}
puts stdout "LIBFETCH: origin $libfetch_origin ([dict size $libfetch_artifacts] declared artifact(s))"
set libfetch_sums [dict create] ;#target -> dict(filename -> sha1) from the server's sha1sums.txt
set libfetch_failed 0
set libfetch_actions [list]
dict for {aname aentry} $libfetch_artifacts {
foreach reqkey {name target} {
if {![dict exists $aentry $reqkey]} {
puts stderr "$A(BAD)LIBFETCH: entry artifact.$aname in $libfetch_config is missing required key '$reqkey'$A(RST)"
exit 3
}
}
set artifact [punkboot::lib::toml_untag [dict get $aentry name]]
set target [punkboot::lib::toml_untag [dict get $aentry target]]
if {![regexp {^(.+)-(tcl[0-9]+)-r([0-9]+)\.zip$} $artifact -> pkgfolder generation rev]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname name '$artifact' does not match <pkgfolder>-tcl<N>-r<N>.zip$A(RST)"
exit 3
}
set tierdir $projectroot/bin/packages/$target
file mkdir $tierdir
#server truth per target: lib/<target>/sha1sums.txt (fetched once per
#run per target; the local copy in the tier mirrors the punk-runtime
#store idiom)
if {![dict exists $libfetch_sums $target]} {
set sumsurl "$libfetch_origin/lib/$target/sha1sums.txt"
set sumslocal $tierdir/sha1sums.txt
if {[catch {::punkboot::libfetch_transfer $sumsurl $sumslocal} terr]} {
puts stderr "$A(BAD)LIBFETCH: cannot fetch $sumsurl - $terr$A(RST)"
exit 3
}
set sfd [open $sumslocal r]
set sumsdata [read $sfd]
close $sfd
set sums [dict create]
foreach ln [split $sumsdata \n] {
set ln [string trim $ln]
if {$ln eq ""} {continue}
set sp [string first " " $ln]
if {$sp < 1} {continue}
set h [string range $ln 0 $sp-1]
set tag [string range $ln $sp+1 end]
dict set sums [string range $tag 1 end] [string tolower $h]
}
dict set libfetch_sums $target $sums
}
set sums [dict get $libfetch_sums $target]
if {![dict exists $sums $artifact]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: '$artifact' is not listed in the server's lib/$target/sha1sums.txt$A(RST)"
set libfetch_failed 1
continue
}
set want_sha1 [dict get $sums $artifact]
set ziplocal $tierdir/$artifact
set have_ok 0
if {[file isfile $ziplocal] && !$::punkboot::opt_force} {
if {[string tolower [sha1::sha1 -hex -file $ziplocal]] eq $want_sha1} {
set have_ok 1
}
}
if {!$have_ok} {
set zipurl "$libfetch_origin/lib/$target/$artifact"
set partfile $ziplocal.part
if {[catch {::punkboot::libfetch_transfer $zipurl $partfile} terr]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: fetch failed - $terr$A(RST)"
set libfetch_failed 1
continue
}
set got_sha1 [string tolower [sha1::sha1 -hex -file $partfile]]
if {$got_sha1 ne $want_sha1} {
file delete -force $partfile
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: sha1 MISMATCH for $artifact (got $got_sha1, server sha1sums says $want_sha1) - deleted$A(RST)"
set libfetch_failed 1
continue
}
file rename -force $partfile $ziplocal
lappend libfetch_actions "fetched lib/$target/$artifact"
} else {
lappend libfetch_actions "verified-present lib/$target/$artifact"
}
#beside-toml sidecar (also sha1sums-listed by emission)
set sidecar "[string range $artifact 0 end-4].toml"
set sidecarlocal $tierdir/$sidecar
set sidecar_ok 0
if {[dict exists $sums $sidecar]} {
set want_side [dict get $sums $sidecar]
if {[file isfile $sidecarlocal] && !$::punkboot::opt_force} {
if {[string tolower [sha1::sha1 -hex -file $sidecarlocal]] eq $want_side} {
set sidecar_ok 1
}
}
if {!$sidecar_ok} {
if {[catch {::punkboot::libfetch_transfer "$libfetch_origin/lib/$target/$sidecar" $sidecarlocal.part} terr]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: sidecar fetch failed - $terr$A(RST)"
set libfetch_failed 1
continue
}
if {[string tolower [sha1::sha1 -hex -file $sidecarlocal.part]] ne $want_side} {
file delete -force $sidecarlocal.part
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: sidecar sha1 MISMATCH for $sidecar - deleted$A(RST)"
set libfetch_failed 1
continue
}
file rename -force $sidecarlocal.part $sidecarlocal
}
} else {
puts stderr "LIBFETCH: note - $sidecar not listed in server sha1sums (artifact accepted; sidecar skipped)"
}
#materialize: installed-shape tree under <target>/tcl<N>/<pkgfolder>
#(generation subdir because both generations install identically-named
#folders). Fresh tree per materialization; -mtime restores member
#mtimes so the tree mirrors what was zipped.
set gendir $tierdir/$generation
file mkdir $gendir
set treedir $gendir/$pkgfolder
if {[file isdirectory $treedir] && !$::punkboot::opt_force} {
#re-materialize only when the tree's embedded record no longer
#matches this artifact name (self-describing tier - G-138)
set embrec $treedir/punkbin-artifact.toml
set tree_current 0
if {[file isfile $embrec]} {
set efd [open $embrec r]
set edata [read $efd]
close $efd
if {[regexp -line "^name = \"$artifact\"$" $edata]} {
set tree_current 1
}
}
if {$tree_current} {
lappend libfetch_actions "tree-current $target/$generation/$pkgfolder"
continue
}
}
file delete -force $treedir
#defaults: whole archive, -overwrite 1 -mtime 1 (member mtimes restored)
#-verify 1 (per-member crc32) - and accelerator-eligible (punkzip exe)
if {[catch {punk::zip::unzip $ziplocal $gendir} unzip_err]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: materialization failed - $unzip_err$A(RST)"
file delete -force $treedir
set libfetch_failed 1
continue
}
if {![file isfile $treedir/pkgIndex.tcl] || ![file isfile $treedir/punkbin-artifact.toml]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: materialized tree at $treedir lacks pkgIndex.tcl and/or punkbin-artifact.toml$A(RST)"
set libfetch_failed 1
continue
}
lappend libfetch_actions "materialized $target/$generation/$pkgfolder"
}
foreach act $libfetch_actions {
puts stdout "LIBFETCH: $act"
}
if {$libfetch_failed} {
puts stderr "$A(BAD)LIBFETCH: FAILED - one or more declared artifacts could not be fetched/verified/materialized (see above)$A(RST)"
exit 3
}
puts stdout "LIBFETCH: done ([llength $libfetch_actions] action(s)) -> $projectroot/bin/packages"
}
flush stdout
::exit 0
}
if {$::punkboot::command ni {bakehouse packages modules libs bake vfslibs bin}} {
puts stderr "Command $::punkboot::command not implemented - aborting."
flush stderr
@ -5241,6 +5618,36 @@ if {$::punkboot::command in {bakehouse packages libs}} {
if {![llength $vendorlibfolders]} {
puts stderr "$A(BAD)VENDORLIB: No src/vendorlib or src/vendorlib_tcl* folder found.$A(RST)"
}
#G-139: punkbin lib-tier packages from the bin/packages input tier (populated
#by 'make.tcl libfetch') into the deployed lib_tcl<N> trees - allplatforms +
#this host's platform dir, mirroring the vendorlib_tcl<N> shape above. The
#materialized trees are self-describing (embedded punkbin-artifact.toml
#records - G-138) and the records ride along into the deployed trees, and
#from there into kit vfs payloads via the vfslibs declarations. An absent
#tier (or target/generation subdir) is a silent per-item no-op: the tier is
#fetch-regenerable and optional until artifacts are declared and fetched.
set packages_root $projectroot/bin/packages
if {[file isdirectory $packages_root]} {
foreach ptarget [list allplatforms $this_platform_generic] {
foreach gendir [lsort [glob -nocomplain -dir $packages_root/$ptarget -type d tcl*]] {
set which [file tail $gendir] ;#tcl8|tcl9 ...
foreach pkgdir [lsort [glob -nocomplain -dir $gendir -type d *]] {
set pkgtail [file tail $pkgdir]
set target_lib_folder $projectroot/lib_$which/$ptarget
file mkdir $target_lib_folder
puts stdout "PACKAGES_$which: copying $ptarget/$which/$pkgtail from the bin/packages tier to $target_lib_folder (if source file changed)"
set resultdict [punkcheck::install $pkgdir $target_lib_folder/$pkgtail\
-createdir 1\
-overwrite installedsourcechanged-targets\
-progresschannel stdout\
]
puts stdout [punkcheck::summarize_install_resultdict $resultdict]
}
}
}
} else {
puts stdout "PACKAGES: no bin/packages tier at $packages_root (populate via 'make.tcl libfetch') - skipping lib-tier package deployment"
}
}
if {$::punkboot::command in {bakehouse bake vfslibs}} {
@ -5295,9 +5702,42 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
if {[dict exists $ientry supersedes]} {
set isupersedes [punkboot::lib::toml_untag [dict get $ientry supersedes]]
}
set source_pkg_folder $sourcefolder/$isource
#source_root (G-139): 'src' (default - the original vendorlib
#declarations) or 'packages' - resolve against the untracked
#bin/packages lib-tier input (populated by 'make.tcl libfetch').
set isource_root "src"
if {[dict exists $ientry source_root]} {
set isource_root [punkboot::lib::toml_untag [dict get $ientry source_root]]
}
#replace (G-139): clean-slate a SAME-NAMED existing target folder
#before install. supersedes deliberately cannot name the folder being
#installed; replace covers same-name refreshes where the old copy may
#carry strays the new tree lacks (e.g. hand-drops nesting md5c/tcllibc
#inside tcllib2.0).
set ireplace 0
if {[dict exists $ientry replace]} {
set ireplace [punkboot::lib::toml_untag [dict get $ientry replace]]
if {![string is boolean -strict $ireplace]} {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname 'replace' must be boolean (got '$ireplace')$A(RST)"
exit 3
}
}
switch -- $isource_root {
src {
set source_pkg_folder $sourcefolder/$isource
set source_missing_hint ""
}
packages {
set source_pkg_folder $projectroot/bin/packages/$isource
set source_missing_hint " - populate the bin/packages tier first: 'tclsh src/make.tcl libfetch' (declarations in src/runtime/libpackages.toml)"
}
default {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname has unknown source_root '$isource_root' (expected src|packages)$A(RST)"
exit 3
}
}
if {![file isdirectory $source_pkg_folder]} {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname source '$isource' not found at $source_pkg_folder$A(RST)"
puts stderr "$A(BAD)VFSLIBS: entry install.$iname source '$isource' not found at $source_pkg_folder$source_missing_hint$A(RST)"
exit 3
}
set pkgtail [file tail $source_pkg_folder]
@ -5327,6 +5767,10 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
file delete -force $suppath
}
}
if {$ireplace && [file isdirectory $target_lib_folder/$pkgtail]} {
puts stdout "VFSLIBS install.$iname: replace=true - removing existing '$pkgtail' from vfs/$t (clean-slate install)"
file delete -force $target_lib_folder/$pkgtail
}
puts stdout "VFSLIBS install.$iname: $isource -> vfs/$t/$pkgtail (if source file changed)"
set resultdict [punkcheck::install $source_pkg_folder $target_lib_folder/$pkgtail\
-installer make.tcl\
@ -5341,6 +5785,7 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
}
}
if {$::punkboot::command in {bakehouse packages libs}} {
########################################################
lappend projectlibfolders lib

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

@ -187,7 +187,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 bakelist vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow buildsuite tool project vfs]
variable known_commands [list bakehouse packages modules libs bake bakelist vfslibs bin info check shell vendorupdate libfetch bootsupport vfscommonupdate projectversion workflow buildsuite tool project vfs]
}
@ -2135,6 +2135,10 @@ proc ::punkboot::punkboot_gethelp {args} {
append h " - propagate declared vendored platform-library packages into kit vfs lib_tcl<N> trees" \n
append h " - declarations (per-package per-kit, with superseded-version removal) live in src/runtime/vendorlib_vfs.toml" \n
append h " - also runs automatically as a phase of '$scriptname bake' (and therefore of '$scriptname bakehouse')" \n \n
append h " $scriptname libfetch ?-serverurl <url>? ?-trust-server? ?-force?" \n
append h " - fetch declared punkbin lib-tier library artifacts (src/runtime/libpackages.toml) into bin/packages/<target>" \n
append h " - sha1-verified against the server's per-target sha1sums.txt; materializes package trees under bin/packages/<target>/tcl<N>" \n
append h " - canonical origin trusted by default; other servers (incl. PUNKBIN_URL overrides) require -trust-server" \n \n
append h " $scriptname vfscommonupdate" \n
append h " - promotion gate: update the src/vfs/_vfscommon.vfs from compiled src/modules and src/lib etc" \n
append h " - before calling this (followed by '$scriptname bake') - you can test using '<builtexe>(.exe) dev'" \n
@ -2323,6 +2327,26 @@ DIAGRAM 2 - KIT ASSEMBLY DETAIL (the 'make.tcl bake' stage; incl. vfslibs phase)
running shell still holds the old exe [K5]
LIBRARY-ARTIFACT FETCH (G-139; input tier so far - lib_tcl<N>/kit consumption follows)
----------------------------------------------------------------------------
src/runtime/libpackages.toml which punkbin LIB-TIER artifacts this checkout
consumes (declared artifact names + targets)
|
| 'make.tcl libfetch' - sha1-verified download of the declared
| <pkg>-<tcl8|tcl9>-r<N>.zip artifacts + .toml sidecars from
| <origin>/lib/<target>/ (canonical punkbin origin trusted by
| default; -serverurl/PUNKBIN_URL override needs -trust-server;
| file:// origins serve local mirrors/fixtures), then
| materialization of each verified zip's package tree
v
bin/packages/<target>/ verified -r<N> zips + toml sidecars (input tier,
untracked - mirrors bin/runtime/<target>)
bin/packages/<target>/tcl<N>/<pkgfolder>/
materialized installed-shape trees, self-describing
via their embedded punkbin-artifact.toml records
KEY / NOTES
----------------------------------------------------------------------------
[K1] Source modules carry the literal magic version 999999.0a1.0 in the filename.
@ -2527,6 +2551,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
vfslibs "Propagate declared vendored platform-library packages into kit vfs lib_tcl<N> trees"
bin "Install executables from src/bin into <projectdir>/bin, then build kits as for bake"
vendorupdate "Update src/vendormodules based on src/vendormodules/include_modules.config"
libfetch "Fetch declared punkbin lib-tier library artifacts into bin/packages/<target> (sha1-verified) and materialize the package trees"
bootsupport "Promotion gate: update src/bootsupport modules from built project modules"
vfscommonupdate "Promotion gate: replace src/vfs/_vfscommon.vfs modules and libs with the project's built set"
info "Show the name and base folder of the project to be built"
@ -2630,6 +2655,24 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
Also runs automatically as a phase of 'make.tcl bake' (and therefore
of 'make.tcl bakehouse'); this standalone narrowing serves quick
iteration on the declarations."
libfetch
"
Fetch the punkbin LIB-TIER library artifacts declared in
src/runtime/libpackages.toml into the untracked input tier
bin/packages/<target>/ - immutable <pkg>-<tcl8|tcl9>-r<N>.zip
artifacts plus their .toml sidecars, each verified against the
server's per-target sha1sums.txt - then materialize each verified
zip's installed-shape package tree under
bin/packages/<target>/tcl<N>/ (self-describing via the embedded
punkbin-artifact.toml record; G-138/G-139).
Present artifacts that already verify are skipped (-force
re-downloads). The canonical punkbin origin is trusted by
default; -serverurl (or env PUNKBIN_URL) overrides it, and any
NON-canonical origin requires the explicit -trust-server flag
(never an interactive prompt - unattended runs stay unattended).
A file:// origin is supported for local mirrors/fixtures.
Transport for http(s): Tcl http+tls when loadable, else curl,
else PowerShell (windows)."
bin
"
Install executables from src/bin to <projectdir>/bin, then check vfs
@ -2799,6 +2842,30 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
(packages -> test -> bootsupport/vfscommonupdate -> commit -> bake).
Pass -dirty-abort 0 to build anyway with PROVENANCE-WARNINGs."
}
#libfetch fragments (G-139): consent is keyed to SERVER TRUST (the G-123
#posture) - the canonical punkbin origin needs no acknowledgement, any
#other origin needs the explicit flag. Never an interactive prompt.
variable OPT_SERVERURL {
-serverurl -type string -default "" -help\
"Artifact server base url override (default: the canonical punkbin
origin; env PUNKBIN_URL overrides the default, this flag overrides
both). The lib tier is addressed as <serverurl>/lib/<target>/.
file:// urls are supported for local mirrors and fixtures.
A NON-canonical origin additionally requires -trust-server."
}
variable OPT_TRUSTSERVER {
-trust-server -type none -default 0 -help\
"Acknowledge fetching from a NON-canonical artifact server
(consent keyed to server trust - the interim G-123/G-006
mechanism). Without this flag, a non-canonical -serverurl or
PUNKBIN_URL aborts before any network access. Fetches from the
canonical origin never require it."
}
variable OPT_FORCE {
-force -type none -default 0 -help\
"Re-download and re-materialize even when a present artifact
already verifies against the server sha1sums."
}
#which shared option fragments each subcommand declares
#(shell and help have bespoke definitions below: shell passes trailing args
# through to the repl untouched, help takes a subject value)
@ -2812,6 +2879,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
vfslibs {OPT_DIRTYABORT OPT_CONFIRM}
bin {OPT_FORCEKILL OPT_DIRTYABORT OPT_CONFIRM}
vendorupdate {OPT_CONFIRM}
libfetch {OPT_SERVERURL OPT_TRUSTSERVER OPT_FORCE}
bootsupport {OPT_DIRTYABORT OPT_CONFIRM}
vfscommonupdate {OPT_DIRTYABORT OPT_CONFIRM}
info {OPT_CONFIRM}
@ -2829,6 +2897,9 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
OPT_DIRTYABORT "?-dirty-abort?"
OPT_DIRTYABORT_ON "?-dirty-abort 1|0?"
OPT_CONFIRM "?-confirm 0|1?"
OPT_SERVERURL "?-serverurl <url>?"
OPT_TRUSTSERVER "?-trust-server?"
OPT_FORCE "?-force?"
}
#per-subcommand positional values (default: none). bake (and its deprecated
#alias vfs) and bakelist take optional kit names (G-121 selective bake).
@ -2940,7 +3011,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
variable SUBGROUPS {
"build & bake" {bakehouse packages modules libs bake vfslibs bin}
"promotion gates" {bootsupport vfscommonupdate}
"source maintenance" {vendorupdate}
"source maintenance" {vendorupdate libfetch}
"buildsuites" {buildsuite}
"vendored tools" {tool}
"informational" {info check bakelist projectversion workflow help}
@ -2996,6 +3067,9 @@ set help_exitcode 0
set ::punkboot::opt_forcekill 0
set ::punkboot::opt_dirty_abort 0
set ::punkboot::opt_confirm 1
set ::punkboot::opt_serverurl ""
set ::punkboot::opt_trust_server 0
set ::punkboot::opt_force 0
set ::punkboot::opt_kitnames [list] ;#G-121: requested kit names for bake/bakelist (empty = all configured)
if {$::punkboot::punkargs_ok} {
@ -3046,7 +3120,7 @@ if {$::punkboot::punkargs_ok} {
}
set ::punkboot::command $subcommand
set _opts [dict get $argd opts]
foreach {_optname _var} {-k opt_forcekill -dirty-abort opt_dirty_abort -confirm opt_confirm} {
foreach {_optname _var} {-k opt_forcekill -dirty-abort opt_dirty_abort -confirm opt_confirm -serverurl opt_serverurl -trust-server opt_trust_server -force opt_force} {
if {[dict exists $_opts $_optname]} {
set ::punkboot::$_var [dict get $_opts $_optname]
}
@ -3083,6 +3157,12 @@ if {$::punkboot::punkargs_ok} {
switch -- $a {
-k {set ::punkboot::opt_forcekill 1}
-dirty-abort {set ::punkboot::opt_dirty_abort 1}
-trust-server {set ::punkboot::opt_trust_server 1}
-force {set ::punkboot::opt_force 1}
-serverurl {
set ::punkboot::opt_serverurl [lindex $argsleft 0]
set argsleft [lrange $argsleft 1 end]
}
-confirm {
set v [lindex $argsleft 0]
set argsleft [lrange $argsleft 1 end]
@ -5121,6 +5201,303 @@ if {$::punkboot::command eq "bootsupport"} {
if {$::punkboot::command eq "libfetch"} {
#G-139 phase 1: fetch the punkbin LIB-TIER artifacts declared in
#src/runtime/libpackages.toml into the untracked bin/packages/<target> input
#tier (mirroring bin/runtime/<target>) with sha1 verification against the
#server's per-target sha1sums.txt, then materialize each verified zip's
#installed-shape package tree under bin/packages/<target>/tcl<N>/ (the tree
#is self-describing via its embedded punkbin-artifact.toml - the G-138
#record). Consumption into lib_tcl<N>/ and kit vfs trees is the remainder
#of G-139 - this entrypoint owns fetch + verify + materialize only.
proc ::punkboot::libfetch_transfer {url outfile} {
#one url -> local file. file:// is served natively (local mirrors,
#fixtures - no network, no external tools). http(s) transports in
#order: Tcl http (+tls for https) when loadable, curl (ubiquitous,
#including stock windows 10+), powershell Invoke-WebRequest (windows).
#Returns the transport used; errors when all fail.
file mkdir [file dirname $outfile]
if {[string match -nocase "file://*" $url]} {
set path [string range $url 7 end]
if {[regexp {^/+([A-Za-z]:/.*)$} $path -> winpath]} {
set path $winpath ;#file:///C:/x -> C:/x
}
if {![file isfile $path]} {
error "file origin has no such file: $path"
}
file copy -force $path $outfile
return "file-copy"
}
set is_https [string match -nocase "https://*" $url]
set tcl_http_ok 0
if {![catch {package require http}]} {
if {!$is_https} {
set tcl_http_ok 1
} elseif {![catch {package require tls}]} {
catch {http::register https 443 [list ::tls::socket -autoservername true]}
set tcl_http_ok 1
}
}
if {$tcl_http_ok} {
set fd [open $outfile wb]
set ok 0
if {![catch {http::geturl $url -channel $fd -binary 1} tok]} {
if {[http::status $tok] eq "ok" && [http::ncode $tok] == 200} {set ok 1}
http::cleanup $tok
}
close $fd
if {$ok} {return "tcl-http"}
file delete -force $outfile
}
set curl [auto_execok curl]
if {$curl ne ""} {
if {![catch {exec {*}$curl --fail -sSL -o $outfile $url 2>@1} curlerr]} {
return "curl"
}
file delete -force $outfile
}
if {$::tcl_platform(platform) eq "windows"} {
set ps [auto_execok powershell]
if {$ps ne ""} {
set pscmd "\$ProgressPreference='SilentlyContinue'; Invoke-WebRequest -Uri '$url' -OutFile '$outfile' -ErrorAction Stop"
if {![catch {exec {*}$ps -NoProfile -NonInteractive -Command $pscmd 2>@1} pserr]} {
return "powershell"
}
file delete -force $outfile
}
}
set detail ""
if {[info exists curlerr]} {set detail " (curl: [string range $curlerr 0 200])"}
error "all transports failed for $url$detail"
}
set libfetch_config $sourcefolder/runtime/libpackages.toml
#Canonical origin: the punkbin raw-file base (the punk-runtime.cmd
#convention; lib tier addressed as <origin>/lib/<target>/...).
#Server-trust consent (G-139, the G-123 posture): the canonical origin
#never gates; ANY other origin - flag or PUNKBIN_URL env - requires the
#explicit -trust-server flag. Never an interactive prompt: unattended
#runs stay unattended, and refusal happens before any network access.
set libfetch_canonical "https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master"
set libfetch_origin $libfetch_canonical
if {[info exists ::env(PUNKBIN_URL)] && $::env(PUNKBIN_URL) ne ""} {
set libfetch_origin $::env(PUNKBIN_URL)
}
if {$::punkboot::opt_serverurl ne ""} {
set libfetch_origin $::punkboot::opt_serverurl
}
set libfetch_origin [string trimright $libfetch_origin /]
if {$libfetch_origin ne $libfetch_canonical && !$::punkboot::opt_trust_server} {
puts stderr "$A(BAD)LIBFETCH: origin '$libfetch_origin' is not the canonical punkbin origin$A(RST)"
puts stderr "LIBFETCH: canonical: $libfetch_canonical"
puts stderr "LIBFETCH: fetching from a non-canonical server requires the explicit -trust-server flag (consent keyed to server trust - G-139/G-123). Nothing was fetched."
exit 3
}
if {![file exists $libfetch_config]} {
puts stdout "LIBFETCH: no config at $libfetch_config - nothing declared, nothing to fetch"
} else {
if {[catch {package require tomlish} tomlish_err]} {
puts stderr "$A(BAD)LIBFETCH: cannot process $libfetch_config - tomlish package unavailable ($tomlish_err)$A(RST)"
exit 3
}
if {[catch {package require sha1} sha1_err]} {
puts stderr "$A(BAD)LIBFETCH: sha1 package unavailable ($sha1_err) - cannot verify artifacts$A(RST)"
exit 3
}
if {[catch {package require punk::zip} punkzip_err]} {
puts stderr "$A(BAD)LIBFETCH: punk::zip package unavailable ($punkzip_err) - cannot materialize package trees$A(RST)"
exit 3
}
set fd [open $libfetch_config r]
fconfigure $fd -encoding utf-8
set libfetch_tomldata [read $fd]
close $fd
if {[catch {tomlish::to_dict [tomlish::from_toml $libfetch_tomldata]} libfetch_dict]} {
puts stderr "$A(BAD)LIBFETCH: failed to parse $libfetch_config\n$libfetch_dict$A(RST)"
exit 3
}
if {![llength [info commands ::punkboot::lib::toml_untag]]} {
#tomlish::to_dict values are type-tagged (also defined by the vfslibs
#phase - that block does not run for the libfetch command)
proc ::punkboot::lib::toml_untag {tagged} {
if {[dict get $tagged type] eq "ARRAY"} {
set plain [list]
foreach el [dict get $tagged value] {
lappend plain [::punkboot::lib::toml_untag $el]
}
return $plain
}
return [dict get $tagged value]
}
}
set libfetch_artifacts [dict create]
if {[dict exists $libfetch_dict artifact]} {
set libfetch_artifacts [dict get $libfetch_dict artifact]
}
if {![dict size $libfetch_artifacts]} {
puts stdout "LIBFETCH: no \[artifact.<name>\] entries found in $libfetch_config"
}
puts stdout "LIBFETCH: origin $libfetch_origin ([dict size $libfetch_artifacts] declared artifact(s))"
set libfetch_sums [dict create] ;#target -> dict(filename -> sha1) from the server's sha1sums.txt
set libfetch_failed 0
set libfetch_actions [list]
dict for {aname aentry} $libfetch_artifacts {
foreach reqkey {name target} {
if {![dict exists $aentry $reqkey]} {
puts stderr "$A(BAD)LIBFETCH: entry artifact.$aname in $libfetch_config is missing required key '$reqkey'$A(RST)"
exit 3
}
}
set artifact [punkboot::lib::toml_untag [dict get $aentry name]]
set target [punkboot::lib::toml_untag [dict get $aentry target]]
if {![regexp {^(.+)-(tcl[0-9]+)-r([0-9]+)\.zip$} $artifact -> pkgfolder generation rev]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname name '$artifact' does not match <pkgfolder>-tcl<N>-r<N>.zip$A(RST)"
exit 3
}
set tierdir $projectroot/bin/packages/$target
file mkdir $tierdir
#server truth per target: lib/<target>/sha1sums.txt (fetched once per
#run per target; the local copy in the tier mirrors the punk-runtime
#store idiom)
if {![dict exists $libfetch_sums $target]} {
set sumsurl "$libfetch_origin/lib/$target/sha1sums.txt"
set sumslocal $tierdir/sha1sums.txt
if {[catch {::punkboot::libfetch_transfer $sumsurl $sumslocal} terr]} {
puts stderr "$A(BAD)LIBFETCH: cannot fetch $sumsurl - $terr$A(RST)"
exit 3
}
set sfd [open $sumslocal r]
set sumsdata [read $sfd]
close $sfd
set sums [dict create]
foreach ln [split $sumsdata \n] {
set ln [string trim $ln]
if {$ln eq ""} {continue}
set sp [string first " " $ln]
if {$sp < 1} {continue}
set h [string range $ln 0 $sp-1]
set tag [string range $ln $sp+1 end]
dict set sums [string range $tag 1 end] [string tolower $h]
}
dict set libfetch_sums $target $sums
}
set sums [dict get $libfetch_sums $target]
if {![dict exists $sums $artifact]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: '$artifact' is not listed in the server's lib/$target/sha1sums.txt$A(RST)"
set libfetch_failed 1
continue
}
set want_sha1 [dict get $sums $artifact]
set ziplocal $tierdir/$artifact
set have_ok 0
if {[file isfile $ziplocal] && !$::punkboot::opt_force} {
if {[string tolower [sha1::sha1 -hex -file $ziplocal]] eq $want_sha1} {
set have_ok 1
}
}
if {!$have_ok} {
set zipurl "$libfetch_origin/lib/$target/$artifact"
set partfile $ziplocal.part
if {[catch {::punkboot::libfetch_transfer $zipurl $partfile} terr]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: fetch failed - $terr$A(RST)"
set libfetch_failed 1
continue
}
set got_sha1 [string tolower [sha1::sha1 -hex -file $partfile]]
if {$got_sha1 ne $want_sha1} {
file delete -force $partfile
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: sha1 MISMATCH for $artifact (got $got_sha1, server sha1sums says $want_sha1) - deleted$A(RST)"
set libfetch_failed 1
continue
}
file rename -force $partfile $ziplocal
lappend libfetch_actions "fetched lib/$target/$artifact"
} else {
lappend libfetch_actions "verified-present lib/$target/$artifact"
}
#beside-toml sidecar (also sha1sums-listed by emission)
set sidecar "[string range $artifact 0 end-4].toml"
set sidecarlocal $tierdir/$sidecar
set sidecar_ok 0
if {[dict exists $sums $sidecar]} {
set want_side [dict get $sums $sidecar]
if {[file isfile $sidecarlocal] && !$::punkboot::opt_force} {
if {[string tolower [sha1::sha1 -hex -file $sidecarlocal]] eq $want_side} {
set sidecar_ok 1
}
}
if {!$sidecar_ok} {
if {[catch {::punkboot::libfetch_transfer "$libfetch_origin/lib/$target/$sidecar" $sidecarlocal.part} terr]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: sidecar fetch failed - $terr$A(RST)"
set libfetch_failed 1
continue
}
if {[string tolower [sha1::sha1 -hex -file $sidecarlocal.part]] ne $want_side} {
file delete -force $sidecarlocal.part
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: sidecar sha1 MISMATCH for $sidecar - deleted$A(RST)"
set libfetch_failed 1
continue
}
file rename -force $sidecarlocal.part $sidecarlocal
}
} else {
puts stderr "LIBFETCH: note - $sidecar not listed in server sha1sums (artifact accepted; sidecar skipped)"
}
#materialize: installed-shape tree under <target>/tcl<N>/<pkgfolder>
#(generation subdir because both generations install identically-named
#folders). Fresh tree per materialization; -mtime restores member
#mtimes so the tree mirrors what was zipped.
set gendir $tierdir/$generation
file mkdir $gendir
set treedir $gendir/$pkgfolder
if {[file isdirectory $treedir] && !$::punkboot::opt_force} {
#re-materialize only when the tree's embedded record no longer
#matches this artifact name (self-describing tier - G-138)
set embrec $treedir/punkbin-artifact.toml
set tree_current 0
if {[file isfile $embrec]} {
set efd [open $embrec r]
set edata [read $efd]
close $efd
if {[regexp -line "^name = \"$artifact\"$" $edata]} {
set tree_current 1
}
}
if {$tree_current} {
lappend libfetch_actions "tree-current $target/$generation/$pkgfolder"
continue
}
}
file delete -force $treedir
#defaults: whole archive, -overwrite 1 -mtime 1 (member mtimes restored)
#-verify 1 (per-member crc32) - and accelerator-eligible (punkzip exe)
if {[catch {punk::zip::unzip $ziplocal $gendir} unzip_err]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: materialization failed - $unzip_err$A(RST)"
file delete -force $treedir
set libfetch_failed 1
continue
}
if {![file isfile $treedir/pkgIndex.tcl] || ![file isfile $treedir/punkbin-artifact.toml]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: materialized tree at $treedir lacks pkgIndex.tcl and/or punkbin-artifact.toml$A(RST)"
set libfetch_failed 1
continue
}
lappend libfetch_actions "materialized $target/$generation/$pkgfolder"
}
foreach act $libfetch_actions {
puts stdout "LIBFETCH: $act"
}
if {$libfetch_failed} {
puts stderr "$A(BAD)LIBFETCH: FAILED - one or more declared artifacts could not be fetched/verified/materialized (see above)$A(RST)"
exit 3
}
puts stdout "LIBFETCH: done ([llength $libfetch_actions] action(s)) -> $projectroot/bin/packages"
}
flush stdout
::exit 0
}
if {$::punkboot::command ni {bakehouse packages modules libs bake vfslibs bin}} {
puts stderr "Command $::punkboot::command not implemented - aborting."
flush stderr
@ -5241,6 +5618,36 @@ if {$::punkboot::command in {bakehouse packages libs}} {
if {![llength $vendorlibfolders]} {
puts stderr "$A(BAD)VENDORLIB: No src/vendorlib or src/vendorlib_tcl* folder found.$A(RST)"
}
#G-139: punkbin lib-tier packages from the bin/packages input tier (populated
#by 'make.tcl libfetch') into the deployed lib_tcl<N> trees - allplatforms +
#this host's platform dir, mirroring the vendorlib_tcl<N> shape above. The
#materialized trees are self-describing (embedded punkbin-artifact.toml
#records - G-138) and the records ride along into the deployed trees, and
#from there into kit vfs payloads via the vfslibs declarations. An absent
#tier (or target/generation subdir) is a silent per-item no-op: the tier is
#fetch-regenerable and optional until artifacts are declared and fetched.
set packages_root $projectroot/bin/packages
if {[file isdirectory $packages_root]} {
foreach ptarget [list allplatforms $this_platform_generic] {
foreach gendir [lsort [glob -nocomplain -dir $packages_root/$ptarget -type d tcl*]] {
set which [file tail $gendir] ;#tcl8|tcl9 ...
foreach pkgdir [lsort [glob -nocomplain -dir $gendir -type d *]] {
set pkgtail [file tail $pkgdir]
set target_lib_folder $projectroot/lib_$which/$ptarget
file mkdir $target_lib_folder
puts stdout "PACKAGES_$which: copying $ptarget/$which/$pkgtail from the bin/packages tier to $target_lib_folder (if source file changed)"
set resultdict [punkcheck::install $pkgdir $target_lib_folder/$pkgtail\
-createdir 1\
-overwrite installedsourcechanged-targets\
-progresschannel stdout\
]
puts stdout [punkcheck::summarize_install_resultdict $resultdict]
}
}
}
} else {
puts stdout "PACKAGES: no bin/packages tier at $packages_root (populate via 'make.tcl libfetch') - skipping lib-tier package deployment"
}
}
if {$::punkboot::command in {bakehouse bake vfslibs}} {
@ -5295,9 +5702,42 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
if {[dict exists $ientry supersedes]} {
set isupersedes [punkboot::lib::toml_untag [dict get $ientry supersedes]]
}
set source_pkg_folder $sourcefolder/$isource
#source_root (G-139): 'src' (default - the original vendorlib
#declarations) or 'packages' - resolve against the untracked
#bin/packages lib-tier input (populated by 'make.tcl libfetch').
set isource_root "src"
if {[dict exists $ientry source_root]} {
set isource_root [punkboot::lib::toml_untag [dict get $ientry source_root]]
}
#replace (G-139): clean-slate a SAME-NAMED existing target folder
#before install. supersedes deliberately cannot name the folder being
#installed; replace covers same-name refreshes where the old copy may
#carry strays the new tree lacks (e.g. hand-drops nesting md5c/tcllibc
#inside tcllib2.0).
set ireplace 0
if {[dict exists $ientry replace]} {
set ireplace [punkboot::lib::toml_untag [dict get $ientry replace]]
if {![string is boolean -strict $ireplace]} {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname 'replace' must be boolean (got '$ireplace')$A(RST)"
exit 3
}
}
switch -- $isource_root {
src {
set source_pkg_folder $sourcefolder/$isource
set source_missing_hint ""
}
packages {
set source_pkg_folder $projectroot/bin/packages/$isource
set source_missing_hint " - populate the bin/packages tier first: 'tclsh src/make.tcl libfetch' (declarations in src/runtime/libpackages.toml)"
}
default {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname has unknown source_root '$isource_root' (expected src|packages)$A(RST)"
exit 3
}
}
if {![file isdirectory $source_pkg_folder]} {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname source '$isource' not found at $source_pkg_folder$A(RST)"
puts stderr "$A(BAD)VFSLIBS: entry install.$iname source '$isource' not found at $source_pkg_folder$source_missing_hint$A(RST)"
exit 3
}
set pkgtail [file tail $source_pkg_folder]
@ -5327,6 +5767,10 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
file delete -force $suppath
}
}
if {$ireplace && [file isdirectory $target_lib_folder/$pkgtail]} {
puts stdout "VFSLIBS install.$iname: replace=true - removing existing '$pkgtail' from vfs/$t (clean-slate install)"
file delete -force $target_lib_folder/$pkgtail
}
puts stdout "VFSLIBS install.$iname: $isource -> vfs/$t/$pkgtail (if source file changed)"
set resultdict [punkcheck::install $source_pkg_folder $target_lib_folder/$pkgtail\
-installer make.tcl\
@ -5341,6 +5785,7 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
}
}
if {$::punkboot::command in {bakehouse packages libs}} {
########################################################
lappend projectlibfolders lib

455
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 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 bakelist vfslibs bin info check shell vendorupdate bootsupport vfscommonupdate projectversion workflow buildsuite tool project vfs]
variable known_commands [list bakehouse packages modules libs bake bakelist vfslibs bin info check shell vendorupdate libfetch bootsupport vfscommonupdate projectversion workflow buildsuite tool project vfs]
}
@ -2135,6 +2135,10 @@ proc ::punkboot::punkboot_gethelp {args} {
append h " - propagate declared vendored platform-library packages into kit vfs lib_tcl<N> trees" \n
append h " - declarations (per-package per-kit, with superseded-version removal) live in src/runtime/vendorlib_vfs.toml" \n
append h " - also runs automatically as a phase of '$scriptname bake' (and therefore of '$scriptname bakehouse')" \n \n
append h " $scriptname libfetch ?-serverurl <url>? ?-trust-server? ?-force?" \n
append h " - fetch declared punkbin lib-tier library artifacts (src/runtime/libpackages.toml) into bin/packages/<target>" \n
append h " - sha1-verified against the server's per-target sha1sums.txt; materializes package trees under bin/packages/<target>/tcl<N>" \n
append h " - canonical origin trusted by default; other servers (incl. PUNKBIN_URL overrides) require -trust-server" \n \n
append h " $scriptname vfscommonupdate" \n
append h " - promotion gate: update the src/vfs/_vfscommon.vfs from compiled src/modules and src/lib etc" \n
append h " - before calling this (followed by '$scriptname bake') - you can test using '<builtexe>(.exe) dev'" \n
@ -2323,6 +2327,26 @@ DIAGRAM 2 - KIT ASSEMBLY DETAIL (the 'make.tcl bake' stage; incl. vfslibs phase)
running shell still holds the old exe [K5]
LIBRARY-ARTIFACT FETCH (G-139; input tier so far - lib_tcl<N>/kit consumption follows)
----------------------------------------------------------------------------
src/runtime/libpackages.toml which punkbin LIB-TIER artifacts this checkout
consumes (declared artifact names + targets)
|
| 'make.tcl libfetch' - sha1-verified download of the declared
| <pkg>-<tcl8|tcl9>-r<N>.zip artifacts + .toml sidecars from
| <origin>/lib/<target>/ (canonical punkbin origin trusted by
| default; -serverurl/PUNKBIN_URL override needs -trust-server;
| file:// origins serve local mirrors/fixtures), then
| materialization of each verified zip's package tree
v
bin/packages/<target>/ verified -r<N> zips + toml sidecars (input tier,
untracked - mirrors bin/runtime/<target>)
bin/packages/<target>/tcl<N>/<pkgfolder>/
materialized installed-shape trees, self-describing
via their embedded punkbin-artifact.toml records
KEY / NOTES
----------------------------------------------------------------------------
[K1] Source modules carry the literal magic version 999999.0a1.0 in the filename.
@ -2527,6 +2551,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
vfslibs "Propagate declared vendored platform-library packages into kit vfs lib_tcl<N> trees"
bin "Install executables from src/bin into <projectdir>/bin, then build kits as for bake"
vendorupdate "Update src/vendormodules based on src/vendormodules/include_modules.config"
libfetch "Fetch declared punkbin lib-tier library artifacts into bin/packages/<target> (sha1-verified) and materialize the package trees"
bootsupport "Promotion gate: update src/bootsupport modules from built project modules"
vfscommonupdate "Promotion gate: replace src/vfs/_vfscommon.vfs modules and libs with the project's built set"
info "Show the name and base folder of the project to be built"
@ -2630,6 +2655,24 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
Also runs automatically as a phase of 'make.tcl bake' (and therefore
of 'make.tcl bakehouse'); this standalone narrowing serves quick
iteration on the declarations."
libfetch
"
Fetch the punkbin LIB-TIER library artifacts declared in
src/runtime/libpackages.toml into the untracked input tier
bin/packages/<target>/ - immutable <pkg>-<tcl8|tcl9>-r<N>.zip
artifacts plus their .toml sidecars, each verified against the
server's per-target sha1sums.txt - then materialize each verified
zip's installed-shape package tree under
bin/packages/<target>/tcl<N>/ (self-describing via the embedded
punkbin-artifact.toml record; G-138/G-139).
Present artifacts that already verify are skipped (-force
re-downloads). The canonical punkbin origin is trusted by
default; -serverurl (or env PUNKBIN_URL) overrides it, and any
NON-canonical origin requires the explicit -trust-server flag
(never an interactive prompt - unattended runs stay unattended).
A file:// origin is supported for local mirrors/fixtures.
Transport for http(s): Tcl http+tls when loadable, else curl,
else PowerShell (windows)."
bin
"
Install executables from src/bin to <projectdir>/bin, then check vfs
@ -2799,6 +2842,30 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
(packages -> test -> bootsupport/vfscommonupdate -> commit -> bake).
Pass -dirty-abort 0 to build anyway with PROVENANCE-WARNINGs."
}
#libfetch fragments (G-139): consent is keyed to SERVER TRUST (the G-123
#posture) - the canonical punkbin origin needs no acknowledgement, any
#other origin needs the explicit flag. Never an interactive prompt.
variable OPT_SERVERURL {
-serverurl -type string -default "" -help\
"Artifact server base url override (default: the canonical punkbin
origin; env PUNKBIN_URL overrides the default, this flag overrides
both). The lib tier is addressed as <serverurl>/lib/<target>/.
file:// urls are supported for local mirrors and fixtures.
A NON-canonical origin additionally requires -trust-server."
}
variable OPT_TRUSTSERVER {
-trust-server -type none -default 0 -help\
"Acknowledge fetching from a NON-canonical artifact server
(consent keyed to server trust - the interim G-123/G-006
mechanism). Without this flag, a non-canonical -serverurl or
PUNKBIN_URL aborts before any network access. Fetches from the
canonical origin never require it."
}
variable OPT_FORCE {
-force -type none -default 0 -help\
"Re-download and re-materialize even when a present artifact
already verifies against the server sha1sums."
}
#which shared option fragments each subcommand declares
#(shell and help have bespoke definitions below: shell passes trailing args
# through to the repl untouched, help takes a subject value)
@ -2812,6 +2879,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
vfslibs {OPT_DIRTYABORT OPT_CONFIRM}
bin {OPT_FORCEKILL OPT_DIRTYABORT OPT_CONFIRM}
vendorupdate {OPT_CONFIRM}
libfetch {OPT_SERVERURL OPT_TRUSTSERVER OPT_FORCE}
bootsupport {OPT_DIRTYABORT OPT_CONFIRM}
vfscommonupdate {OPT_DIRTYABORT OPT_CONFIRM}
info {OPT_CONFIRM}
@ -2829,6 +2897,9 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
OPT_DIRTYABORT "?-dirty-abort?"
OPT_DIRTYABORT_ON "?-dirty-abort 1|0?"
OPT_CONFIRM "?-confirm 0|1?"
OPT_SERVERURL "?-serverurl <url>?"
OPT_TRUSTSERVER "?-trust-server?"
OPT_FORCE "?-force?"
}
#per-subcommand positional values (default: none). bake (and its deprecated
#alias vfs) and bakelist take optional kit names (G-121 selective bake).
@ -2940,7 +3011,7 @@ if {[info exists ::env(PUNKBOOT_PLAIN)] && [string is true -strict $::env(PUNKBO
variable SUBGROUPS {
"build & bake" {bakehouse packages modules libs bake vfslibs bin}
"promotion gates" {bootsupport vfscommonupdate}
"source maintenance" {vendorupdate}
"source maintenance" {vendorupdate libfetch}
"buildsuites" {buildsuite}
"vendored tools" {tool}
"informational" {info check bakelist projectversion workflow help}
@ -2996,6 +3067,9 @@ set help_exitcode 0
set ::punkboot::opt_forcekill 0
set ::punkboot::opt_dirty_abort 0
set ::punkboot::opt_confirm 1
set ::punkboot::opt_serverurl ""
set ::punkboot::opt_trust_server 0
set ::punkboot::opt_force 0
set ::punkboot::opt_kitnames [list] ;#G-121: requested kit names for bake/bakelist (empty = all configured)
if {$::punkboot::punkargs_ok} {
@ -3046,7 +3120,7 @@ if {$::punkboot::punkargs_ok} {
}
set ::punkboot::command $subcommand
set _opts [dict get $argd opts]
foreach {_optname _var} {-k opt_forcekill -dirty-abort opt_dirty_abort -confirm opt_confirm} {
foreach {_optname _var} {-k opt_forcekill -dirty-abort opt_dirty_abort -confirm opt_confirm -serverurl opt_serverurl -trust-server opt_trust_server -force opt_force} {
if {[dict exists $_opts $_optname]} {
set ::punkboot::$_var [dict get $_opts $_optname]
}
@ -3083,6 +3157,12 @@ if {$::punkboot::punkargs_ok} {
switch -- $a {
-k {set ::punkboot::opt_forcekill 1}
-dirty-abort {set ::punkboot::opt_dirty_abort 1}
-trust-server {set ::punkboot::opt_trust_server 1}
-force {set ::punkboot::opt_force 1}
-serverurl {
set ::punkboot::opt_serverurl [lindex $argsleft 0]
set argsleft [lrange $argsleft 1 end]
}
-confirm {
set v [lindex $argsleft 0]
set argsleft [lrange $argsleft 1 end]
@ -5121,6 +5201,303 @@ if {$::punkboot::command eq "bootsupport"} {
if {$::punkboot::command eq "libfetch"} {
#G-139 phase 1: fetch the punkbin LIB-TIER artifacts declared in
#src/runtime/libpackages.toml into the untracked bin/packages/<target> input
#tier (mirroring bin/runtime/<target>) with sha1 verification against the
#server's per-target sha1sums.txt, then materialize each verified zip's
#installed-shape package tree under bin/packages/<target>/tcl<N>/ (the tree
#is self-describing via its embedded punkbin-artifact.toml - the G-138
#record). Consumption into lib_tcl<N>/ and kit vfs trees is the remainder
#of G-139 - this entrypoint owns fetch + verify + materialize only.
proc ::punkboot::libfetch_transfer {url outfile} {
#one url -> local file. file:// is served natively (local mirrors,
#fixtures - no network, no external tools). http(s) transports in
#order: Tcl http (+tls for https) when loadable, curl (ubiquitous,
#including stock windows 10+), powershell Invoke-WebRequest (windows).
#Returns the transport used; errors when all fail.
file mkdir [file dirname $outfile]
if {[string match -nocase "file://*" $url]} {
set path [string range $url 7 end]
if {[regexp {^/+([A-Za-z]:/.*)$} $path -> winpath]} {
set path $winpath ;#file:///C:/x -> C:/x
}
if {![file isfile $path]} {
error "file origin has no such file: $path"
}
file copy -force $path $outfile
return "file-copy"
}
set is_https [string match -nocase "https://*" $url]
set tcl_http_ok 0
if {![catch {package require http}]} {
if {!$is_https} {
set tcl_http_ok 1
} elseif {![catch {package require tls}]} {
catch {http::register https 443 [list ::tls::socket -autoservername true]}
set tcl_http_ok 1
}
}
if {$tcl_http_ok} {
set fd [open $outfile wb]
set ok 0
if {![catch {http::geturl $url -channel $fd -binary 1} tok]} {
if {[http::status $tok] eq "ok" && [http::ncode $tok] == 200} {set ok 1}
http::cleanup $tok
}
close $fd
if {$ok} {return "tcl-http"}
file delete -force $outfile
}
set curl [auto_execok curl]
if {$curl ne ""} {
if {![catch {exec {*}$curl --fail -sSL -o $outfile $url 2>@1} curlerr]} {
return "curl"
}
file delete -force $outfile
}
if {$::tcl_platform(platform) eq "windows"} {
set ps [auto_execok powershell]
if {$ps ne ""} {
set pscmd "\$ProgressPreference='SilentlyContinue'; Invoke-WebRequest -Uri '$url' -OutFile '$outfile' -ErrorAction Stop"
if {![catch {exec {*}$ps -NoProfile -NonInteractive -Command $pscmd 2>@1} pserr]} {
return "powershell"
}
file delete -force $outfile
}
}
set detail ""
if {[info exists curlerr]} {set detail " (curl: [string range $curlerr 0 200])"}
error "all transports failed for $url$detail"
}
set libfetch_config $sourcefolder/runtime/libpackages.toml
#Canonical origin: the punkbin raw-file base (the punk-runtime.cmd
#convention; lib tier addressed as <origin>/lib/<target>/...).
#Server-trust consent (G-139, the G-123 posture): the canonical origin
#never gates; ANY other origin - flag or PUNKBIN_URL env - requires the
#explicit -trust-server flag. Never an interactive prompt: unattended
#runs stay unattended, and refusal happens before any network access.
set libfetch_canonical "https://www.gitea1.intx.com.au/jn/punkbin/raw/branch/master"
set libfetch_origin $libfetch_canonical
if {[info exists ::env(PUNKBIN_URL)] && $::env(PUNKBIN_URL) ne ""} {
set libfetch_origin $::env(PUNKBIN_URL)
}
if {$::punkboot::opt_serverurl ne ""} {
set libfetch_origin $::punkboot::opt_serverurl
}
set libfetch_origin [string trimright $libfetch_origin /]
if {$libfetch_origin ne $libfetch_canonical && !$::punkboot::opt_trust_server} {
puts stderr "$A(BAD)LIBFETCH: origin '$libfetch_origin' is not the canonical punkbin origin$A(RST)"
puts stderr "LIBFETCH: canonical: $libfetch_canonical"
puts stderr "LIBFETCH: fetching from a non-canonical server requires the explicit -trust-server flag (consent keyed to server trust - G-139/G-123). Nothing was fetched."
exit 3
}
if {![file exists $libfetch_config]} {
puts stdout "LIBFETCH: no config at $libfetch_config - nothing declared, nothing to fetch"
} else {
if {[catch {package require tomlish} tomlish_err]} {
puts stderr "$A(BAD)LIBFETCH: cannot process $libfetch_config - tomlish package unavailable ($tomlish_err)$A(RST)"
exit 3
}
if {[catch {package require sha1} sha1_err]} {
puts stderr "$A(BAD)LIBFETCH: sha1 package unavailable ($sha1_err) - cannot verify artifacts$A(RST)"
exit 3
}
if {[catch {package require punk::zip} punkzip_err]} {
puts stderr "$A(BAD)LIBFETCH: punk::zip package unavailable ($punkzip_err) - cannot materialize package trees$A(RST)"
exit 3
}
set fd [open $libfetch_config r]
fconfigure $fd -encoding utf-8
set libfetch_tomldata [read $fd]
close $fd
if {[catch {tomlish::to_dict [tomlish::from_toml $libfetch_tomldata]} libfetch_dict]} {
puts stderr "$A(BAD)LIBFETCH: failed to parse $libfetch_config\n$libfetch_dict$A(RST)"
exit 3
}
if {![llength [info commands ::punkboot::lib::toml_untag]]} {
#tomlish::to_dict values are type-tagged (also defined by the vfslibs
#phase - that block does not run for the libfetch command)
proc ::punkboot::lib::toml_untag {tagged} {
if {[dict get $tagged type] eq "ARRAY"} {
set plain [list]
foreach el [dict get $tagged value] {
lappend plain [::punkboot::lib::toml_untag $el]
}
return $plain
}
return [dict get $tagged value]
}
}
set libfetch_artifacts [dict create]
if {[dict exists $libfetch_dict artifact]} {
set libfetch_artifacts [dict get $libfetch_dict artifact]
}
if {![dict size $libfetch_artifacts]} {
puts stdout "LIBFETCH: no \[artifact.<name>\] entries found in $libfetch_config"
}
puts stdout "LIBFETCH: origin $libfetch_origin ([dict size $libfetch_artifacts] declared artifact(s))"
set libfetch_sums [dict create] ;#target -> dict(filename -> sha1) from the server's sha1sums.txt
set libfetch_failed 0
set libfetch_actions [list]
dict for {aname aentry} $libfetch_artifacts {
foreach reqkey {name target} {
if {![dict exists $aentry $reqkey]} {
puts stderr "$A(BAD)LIBFETCH: entry artifact.$aname in $libfetch_config is missing required key '$reqkey'$A(RST)"
exit 3
}
}
set artifact [punkboot::lib::toml_untag [dict get $aentry name]]
set target [punkboot::lib::toml_untag [dict get $aentry target]]
if {![regexp {^(.+)-(tcl[0-9]+)-r([0-9]+)\.zip$} $artifact -> pkgfolder generation rev]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname name '$artifact' does not match <pkgfolder>-tcl<N>-r<N>.zip$A(RST)"
exit 3
}
set tierdir $projectroot/bin/packages/$target
file mkdir $tierdir
#server truth per target: lib/<target>/sha1sums.txt (fetched once per
#run per target; the local copy in the tier mirrors the punk-runtime
#store idiom)
if {![dict exists $libfetch_sums $target]} {
set sumsurl "$libfetch_origin/lib/$target/sha1sums.txt"
set sumslocal $tierdir/sha1sums.txt
if {[catch {::punkboot::libfetch_transfer $sumsurl $sumslocal} terr]} {
puts stderr "$A(BAD)LIBFETCH: cannot fetch $sumsurl - $terr$A(RST)"
exit 3
}
set sfd [open $sumslocal r]
set sumsdata [read $sfd]
close $sfd
set sums [dict create]
foreach ln [split $sumsdata \n] {
set ln [string trim $ln]
if {$ln eq ""} {continue}
set sp [string first " " $ln]
if {$sp < 1} {continue}
set h [string range $ln 0 $sp-1]
set tag [string range $ln $sp+1 end]
dict set sums [string range $tag 1 end] [string tolower $h]
}
dict set libfetch_sums $target $sums
}
set sums [dict get $libfetch_sums $target]
if {![dict exists $sums $artifact]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: '$artifact' is not listed in the server's lib/$target/sha1sums.txt$A(RST)"
set libfetch_failed 1
continue
}
set want_sha1 [dict get $sums $artifact]
set ziplocal $tierdir/$artifact
set have_ok 0
if {[file isfile $ziplocal] && !$::punkboot::opt_force} {
if {[string tolower [sha1::sha1 -hex -file $ziplocal]] eq $want_sha1} {
set have_ok 1
}
}
if {!$have_ok} {
set zipurl "$libfetch_origin/lib/$target/$artifact"
set partfile $ziplocal.part
if {[catch {::punkboot::libfetch_transfer $zipurl $partfile} terr]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: fetch failed - $terr$A(RST)"
set libfetch_failed 1
continue
}
set got_sha1 [string tolower [sha1::sha1 -hex -file $partfile]]
if {$got_sha1 ne $want_sha1} {
file delete -force $partfile
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: sha1 MISMATCH for $artifact (got $got_sha1, server sha1sums says $want_sha1) - deleted$A(RST)"
set libfetch_failed 1
continue
}
file rename -force $partfile $ziplocal
lappend libfetch_actions "fetched lib/$target/$artifact"
} else {
lappend libfetch_actions "verified-present lib/$target/$artifact"
}
#beside-toml sidecar (also sha1sums-listed by emission)
set sidecar "[string range $artifact 0 end-4].toml"
set sidecarlocal $tierdir/$sidecar
set sidecar_ok 0
if {[dict exists $sums $sidecar]} {
set want_side [dict get $sums $sidecar]
if {[file isfile $sidecarlocal] && !$::punkboot::opt_force} {
if {[string tolower [sha1::sha1 -hex -file $sidecarlocal]] eq $want_side} {
set sidecar_ok 1
}
}
if {!$sidecar_ok} {
if {[catch {::punkboot::libfetch_transfer "$libfetch_origin/lib/$target/$sidecar" $sidecarlocal.part} terr]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: sidecar fetch failed - $terr$A(RST)"
set libfetch_failed 1
continue
}
if {[string tolower [sha1::sha1 -hex -file $sidecarlocal.part]] ne $want_side} {
file delete -force $sidecarlocal.part
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: sidecar sha1 MISMATCH for $sidecar - deleted$A(RST)"
set libfetch_failed 1
continue
}
file rename -force $sidecarlocal.part $sidecarlocal
}
} else {
puts stderr "LIBFETCH: note - $sidecar not listed in server sha1sums (artifact accepted; sidecar skipped)"
}
#materialize: installed-shape tree under <target>/tcl<N>/<pkgfolder>
#(generation subdir because both generations install identically-named
#folders). Fresh tree per materialization; -mtime restores member
#mtimes so the tree mirrors what was zipped.
set gendir $tierdir/$generation
file mkdir $gendir
set treedir $gendir/$pkgfolder
if {[file isdirectory $treedir] && !$::punkboot::opt_force} {
#re-materialize only when the tree's embedded record no longer
#matches this artifact name (self-describing tier - G-138)
set embrec $treedir/punkbin-artifact.toml
set tree_current 0
if {[file isfile $embrec]} {
set efd [open $embrec r]
set edata [read $efd]
close $efd
if {[regexp -line "^name = \"$artifact\"$" $edata]} {
set tree_current 1
}
}
if {$tree_current} {
lappend libfetch_actions "tree-current $target/$generation/$pkgfolder"
continue
}
}
file delete -force $treedir
#defaults: whole archive, -overwrite 1 -mtime 1 (member mtimes restored)
#-verify 1 (per-member crc32) - and accelerator-eligible (punkzip exe)
if {[catch {punk::zip::unzip $ziplocal $gendir} unzip_err]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: materialization failed - $unzip_err$A(RST)"
file delete -force $treedir
set libfetch_failed 1
continue
}
if {![file isfile $treedir/pkgIndex.tcl] || ![file isfile $treedir/punkbin-artifact.toml]} {
puts stderr "$A(BAD)LIBFETCH: artifact.$aname: materialized tree at $treedir lacks pkgIndex.tcl and/or punkbin-artifact.toml$A(RST)"
set libfetch_failed 1
continue
}
lappend libfetch_actions "materialized $target/$generation/$pkgfolder"
}
foreach act $libfetch_actions {
puts stdout "LIBFETCH: $act"
}
if {$libfetch_failed} {
puts stderr "$A(BAD)LIBFETCH: FAILED - one or more declared artifacts could not be fetched/verified/materialized (see above)$A(RST)"
exit 3
}
puts stdout "LIBFETCH: done ([llength $libfetch_actions] action(s)) -> $projectroot/bin/packages"
}
flush stdout
::exit 0
}
if {$::punkboot::command ni {bakehouse packages modules libs bake vfslibs bin}} {
puts stderr "Command $::punkboot::command not implemented - aborting."
flush stderr
@ -5241,6 +5618,36 @@ if {$::punkboot::command in {bakehouse packages libs}} {
if {![llength $vendorlibfolders]} {
puts stderr "$A(BAD)VENDORLIB: No src/vendorlib or src/vendorlib_tcl* folder found.$A(RST)"
}
#G-139: punkbin lib-tier packages from the bin/packages input tier (populated
#by 'make.tcl libfetch') into the deployed lib_tcl<N> trees - allplatforms +
#this host's platform dir, mirroring the vendorlib_tcl<N> shape above. The
#materialized trees are self-describing (embedded punkbin-artifact.toml
#records - G-138) and the records ride along into the deployed trees, and
#from there into kit vfs payloads via the vfslibs declarations. An absent
#tier (or target/generation subdir) is a silent per-item no-op: the tier is
#fetch-regenerable and optional until artifacts are declared and fetched.
set packages_root $projectroot/bin/packages
if {[file isdirectory $packages_root]} {
foreach ptarget [list allplatforms $this_platform_generic] {
foreach gendir [lsort [glob -nocomplain -dir $packages_root/$ptarget -type d tcl*]] {
set which [file tail $gendir] ;#tcl8|tcl9 ...
foreach pkgdir [lsort [glob -nocomplain -dir $gendir -type d *]] {
set pkgtail [file tail $pkgdir]
set target_lib_folder $projectroot/lib_$which/$ptarget
file mkdir $target_lib_folder
puts stdout "PACKAGES_$which: copying $ptarget/$which/$pkgtail from the bin/packages tier to $target_lib_folder (if source file changed)"
set resultdict [punkcheck::install $pkgdir $target_lib_folder/$pkgtail\
-createdir 1\
-overwrite installedsourcechanged-targets\
-progresschannel stdout\
]
puts stdout [punkcheck::summarize_install_resultdict $resultdict]
}
}
}
} else {
puts stdout "PACKAGES: no bin/packages tier at $packages_root (populate via 'make.tcl libfetch') - skipping lib-tier package deployment"
}
}
if {$::punkboot::command in {bakehouse bake vfslibs}} {
@ -5295,9 +5702,42 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
if {[dict exists $ientry supersedes]} {
set isupersedes [punkboot::lib::toml_untag [dict get $ientry supersedes]]
}
set source_pkg_folder $sourcefolder/$isource
#source_root (G-139): 'src' (default - the original vendorlib
#declarations) or 'packages' - resolve against the untracked
#bin/packages lib-tier input (populated by 'make.tcl libfetch').
set isource_root "src"
if {[dict exists $ientry source_root]} {
set isource_root [punkboot::lib::toml_untag [dict get $ientry source_root]]
}
#replace (G-139): clean-slate a SAME-NAMED existing target folder
#before install. supersedes deliberately cannot name the folder being
#installed; replace covers same-name refreshes where the old copy may
#carry strays the new tree lacks (e.g. hand-drops nesting md5c/tcllibc
#inside tcllib2.0).
set ireplace 0
if {[dict exists $ientry replace]} {
set ireplace [punkboot::lib::toml_untag [dict get $ientry replace]]
if {![string is boolean -strict $ireplace]} {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname 'replace' must be boolean (got '$ireplace')$A(RST)"
exit 3
}
}
switch -- $isource_root {
src {
set source_pkg_folder $sourcefolder/$isource
set source_missing_hint ""
}
packages {
set source_pkg_folder $projectroot/bin/packages/$isource
set source_missing_hint " - populate the bin/packages tier first: 'tclsh src/make.tcl libfetch' (declarations in src/runtime/libpackages.toml)"
}
default {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname has unknown source_root '$isource_root' (expected src|packages)$A(RST)"
exit 3
}
}
if {![file isdirectory $source_pkg_folder]} {
puts stderr "$A(BAD)VFSLIBS: entry install.$iname source '$isource' not found at $source_pkg_folder$A(RST)"
puts stderr "$A(BAD)VFSLIBS: entry install.$iname source '$isource' not found at $source_pkg_folder$source_missing_hint$A(RST)"
exit 3
}
set pkgtail [file tail $source_pkg_folder]
@ -5327,6 +5767,10 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
file delete -force $suppath
}
}
if {$ireplace && [file isdirectory $target_lib_folder/$pkgtail]} {
puts stdout "VFSLIBS install.$iname: replace=true - removing existing '$pkgtail' from vfs/$t (clean-slate install)"
file delete -force $target_lib_folder/$pkgtail
}
puts stdout "VFSLIBS install.$iname: $isource -> vfs/$t/$pkgtail (if source file changed)"
set resultdict [punkcheck::install $source_pkg_folder $target_lib_folder/$pkgtail\
-installer make.tcl\
@ -5341,6 +5785,7 @@ if {$::punkboot::command in {bakehouse bake vfslibs}} {
}
}
if {$::punkboot::command in {bakehouse packages libs}} {
########################################################
lappend projectlibfolders lib

86
src/runtime/vendorlib_vfs.toml

@ -16,11 +16,20 @@
# by generation - so the same source folder serves lib_tcl9 and lib_tcl8 targets).
#
# Keys per [install.<name>] entry:
# source - package folder path relative to src/
# targets - list of kit vfs lib folders relative to src/vfs/
# supersedes - optional list of legacy/older package folder names to remove from each
# target before install (explicit - no silent mixed-version provision, per
# the G-035 concerns)
# source - package folder path, resolved per source_root
# source_root - optional: 'src' (default; source is relative to src/ - the
# vendored-tree declarations) or 'packages' (G-139; source is
# relative to <projectroot>/bin/packages - the untracked punkbin
# lib-tier input populated by 'tclsh src/make.tcl libfetch')
# targets - list of kit vfs lib folders relative to src/vfs/
# supersedes - optional list of legacy/older package folder names to remove from
# each target before install (explicit - no silent mixed-version
# provision, per the G-035 concerns). Cannot name the folder being
# installed (same-name entries are ignored) - use 'replace' for that.
# replace - optional boolean (G-139): clean-slate a SAME-NAMED existing target
# folder before install. For same-name refreshes where the old copy
# may carry strays the new tree lacks (the pre-G-139 hand-drops
# nested md5c/tcllibc INSIDE their tcllib2.0 folder).
#
# This file is a candidate for absorption into the mapvfs toml conversion (goal G-024).
@ -34,3 +43,70 @@ targets = [
"punk8win.vfs/lib_tcl8",
]
supersedes = ["udp1.0.12", "tcludp1.0.12"]
# -- G-139: suite-built tcllib/tcllibc from the punkbin lib tier ---------------
# Sourced from the bin/packages input tier ('make.tcl libfetch'; artifacts
# declared in libpackages.toml). Targets = the kit vfs trees that carried
# hand-dropped copies at switchover (2026-07-30) - per-kit participation, never
# blanket. replace=true because the old tcl9 hand-drops nested md5c + tcllibc
# INSIDE tcllib2.0 (same folder name as the new install - supersedes cannot
# touch it). The tcl8 kits upgrade tcllib1.21 (+nested tcllibc 0.4 + md5c) ->
# tcllib 2.0 via supersedes. tcllibc is the win32-x86_64 build: punk9linux
# (linux target) deliberately gets only the platform-neutral tcllib2.0 - its
# linux-built tcllibc/tcllibc2.0 sibling folders are left as-is (a linux
# lib-tier emission is future work). punk86bawt carried a bare tcllibc only -
# it gets the tcllibc refresh and no tcllib entry.
[install.tcllib_tcl9]
source_root = "packages"
source = "allplatforms/tcl9/tcllib2.0"
replace = true
targets = [
"mkzipfix.vfs/lib_tcl9",
"punk9cook.vfs/lib_tcl9",
"punk9cookbasic.vfs/lib_tcl9",
"punk9linux.vfs/lib_tcl9",
"punk9magicsplat.vfs/lib_tcl9",
"punk9win_for_tkruntime.vfs/lib_tcl9",
"punk9wintk903.vfs/lib_tcl9",
"punk9wintk905.vfs/lib_tcl9",
"punk9wintk90b2.vfs/lib_tcl9",
]
[install.tcllibc_tcl9]
source_root = "packages"
source = "win32-x86_64/tcl9/tcllibc"
replace = true
targets = [
"mkzipfix.vfs/lib_tcl9",
"punk9cook.vfs/lib_tcl9",
"punk9cookbasic.vfs/lib_tcl9",
"punk9magicsplat.vfs/lib_tcl9",
"punk9win_for_tkruntime.vfs/lib_tcl9",
"punk9wintk903.vfs/lib_tcl9",
"punk9wintk905.vfs/lib_tcl9",
"punk9wintk90b2.vfs/lib_tcl9",
]
supersedes = ["tcllibc2.0"]
[install.tcllib_tcl8]
source_root = "packages"
source = "allplatforms/tcl8/tcllib2.0"
replace = true
targets = [
"punk86.vfs/lib_tcl8",
"punk8win.vfs/lib_tcl8",
"punk8_statictwapi.vfs/lib_tcl8",
]
supersedes = ["tcllib1.21"]
[install.tcllibc_tcl8]
source_root = "packages"
source = "win32-x86_64/tcl8/tcllibc"
replace = true
targets = [
"punk86.vfs/lib_tcl8",
"punk8win.vfs/lib_tcl8",
"punk8_statictwapi.vfs/lib_tcl8",
"punk86bawt.vfs/lib_tcl8",
]

Loading…
Cancel
Save