Browse Source

bootsupport: propagate punk::libunknown argdoc and zzzload snapshot_package_paths wiring to bootsupport and project layouts

master
Julian Noble 2 weeks ago
parent
commit
bd8297673d
  1. 130
      src/bootsupport/modules/punk/libunknown-0.1.tm
  2. 12
      src/bootsupport/modules/zzzload-0.1.0.tm
  3. 130
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/libunknown-0.1.tm
  4. 12
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/zzzload-0.1.0.tm
  5. 130
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/libunknown-0.1.tm
  6. 12
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/zzzload-0.1.0.tm

130
src/bootsupport/modules/punk/libunknown-0.1.tm

@ -100,6 +100,42 @@ tcl::namespace::eval ::punk::libunknown {
}
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::zipfs_tm_UnknownHandler
@cmd -name punk::libunknown::zipfs_tm_UnknownHandler\
-summary\
"Custom package unknown handler for tcl::tm::list module search paths."\
-help\
"Replaces Tcl's built-in ::tcl::tm::UnknownHandler as the first entry in the
package unknown handler chain. Called when package require cannot find a
satisfying version among already-registered ifneeded scripts.
Key differences from Tcl's standard tm handler:
- Uses an epoch-based cache to avoid re-scanning directories that have already
been searched. The epoch is incremented when tcl::tm::paths changes (via a
trace), invalidating stale cache entries.
- Registers ifneeded scripts for ALL .tm files found in each scanned directory,
not just the requested package — so sibling packages are discovered as a
side effect.
- For static (zipfs) paths, skips re-scanning a directory if the requested
package was not found there in a previous scan within the same epoch.
- Falls through to the next handler (e.g zipfs_tclPkgUnknown) if no satisfying
candidate is found in the tm paths.
The \$original parameter is the next handler in the package unknown chain,
called as a fallback when the tm search does not satisfy the request."
@leaders
original -type any -help\
"Next handler in the package unknown chain (list or empty). Called as fallback if the tm search does not satisfy the request."
name -type string -help\
"Package name being searched for."
@values -min 0 -max -1
args -type any -optional 1 -multiple 1 -help\
"Version requirements passed through from package require."
}]
}
#will use standard mechanism for non zipfs paths in the tm list.
proc zipfs_tm_UnknownHandler {original name args} {
#------------------------------
@ -441,6 +477,40 @@ tcl::namespace::eval ::punk::libunknown {
uplevel 1 $original [::linsert $args 0 $name]
}
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::zipfs_tclPkgUnknown
@cmd -name punk::libunknown::zipfs_tclPkgUnknown\
-summary\
"Custom package unknown handler for auto_path/pkgIndex.tcl package search."\
-help\
"Replaces Tcl's built-in ::tclPkgUnknown as the second entry in the package
unknown handler chain. Called when zipfs_tm_UnknownHandler could not satisfy
the package request from the tm paths.
Key differences from Tcl's standard tclPkgUnknown:
- Uses an epoch-based cache to avoid re-sourcing pkgIndex.tcl files that have
already been processed in the current epoch.
- Processes auto_path entries from end to front (same as tclPkgUnknown), but
tracks which packages and versions were added or changed by each pkgIndex.tcl
so that ifneeded scripts from earlier (higher-priority) paths can be reverted
if they were overridden by later (lower-priority) paths.
- The refresh/reversion mechanism ensures that path ordering priority is
respected even though auto_path is processed in reverse.
- Handles auto_path expansion: if a pkgIndex.tcl appends to auto_path during
sourcing, the new entries are reordered to follow the longest common prefix
rather than simply appending to the end.
- For static (zipfs) paths, skips re-sourcing pkgIndex.tcl files if the
requested package was not provided by that path in a previous scan."
@leaders
name -type string -help\
"Package name being searched for."
@values -min 0 -max -1
args -type any -optional 1 -multiple 1 -help\
"Version requirements passed through from package require."
}]
}
proc zipfs_tclPkgUnknown {name args} {
#puts "-> zipfs_tclPkgUnknown $name $args EXPERIMENTAL"
@ -1173,6 +1243,39 @@ tcl::namespace::eval ::punk::libunknown {
}
return $versionlist
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::init
@cmd -name punk::libunknown::init\
-summary\
"Install punk::libunknown's custom package unknown handlers and epoch system in the current interp."\
-help\
"Renames the builtin ::package to ::package:: and installs a custom ::package proc
that intercepts 'forget' (controlled forgetting) and adds an 'epoch' subcommand
(for introspection). Sets package unknown to a two-handler chain:
zipfs_tm_UnknownHandler (tm paths) and zipfs_tclPkgUnknown (auto_path/pkgIndex).
Installs traces on ::auto_path and ::tcl::tm::paths that increment the epoch
when these change, invalidating stale scan cache entries.
Epoch sharing: if \$::punk::libunknown::epoch is already set before init is called
(e.g copied from a parent interp via punk::lib::interp_sync_package_paths -libunknown 1),
init accepts it as a pre-provided record and uses the parent's scan cache instead
of building one from scratch. Packages that were already known before the epoch was
set are recorded as 'untracked' — full scans are performed for them on first request.
This proc should be called as early as possible in a new interp or thread, before
any package require calls that would trigger scans, to minimize the number of
untracked packages and maximize cache effectiveness.
See also: punk::lib::interp_sync_package_paths, punk::lib::snapshot_package_paths"
@opts
-caller -type string -default "" -help\
"Informational label identifying the calling context (e.g 'main.tcl', 'repl::init init_script').
Used only for debug logging — does not affect behaviour."
}]
}
proc init {args} {
variable last_auto_path
set last_auto_path [set ::auto_path]
@ -1503,6 +1606,33 @@ tcl::namespace::eval ::punk::libunknown {
package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::package_query
@cmd -name punk::libunknown::package_query\
-summary\
"Diagnostic tool showing epoch tracking and scan cache state for a named package."\
-help\
"Returns a text report showing what punk::libunknown knows about the given
package from its epoch-based scan cache. The report includes:
- Whether the package is in the tm or pkg 'untracked' sets (packages that were
already known before libunknown::init was called, meaning the epoch data is
not conclusive for them).
- A table of auto_path directories (pkg epoch) showing which packages were found
in each, with version numbers and epoch stamps for the requested package.
- A table of tcl::tm::list directories (tm epoch) showing which packages were
found in each, with version numbers for the requested package.
This is primarily a developer diagnostic for understanding why a particular
package version was (or was not) loaded, and which search path provided it.
Requires punk::ansi and textblock for the table formatting."
@values -min 1 -max 1
pkgname -type string -help\
"Name of the package to inspect."
}]
}
proc package_query {pkgname} {
variable epoch

12
src/bootsupport/modules/zzzload-0.1.0.tm

@ -63,9 +63,15 @@ namespace eval zzzload {
return $ver
}
if {$loader_tid eq ""} {
set loader_tid [thread::create -joinable -preserved]
#todo - set tcl::tm::list and ::auto_path in the loader thread to match the main thread.
#(startup process may have modified these paths)
#propagate tm list, auto_path, and package prefer to the loader thread
#so it can find the same packages as the parent interp.
if {![catch {package require punk::lib}]} {
set init_script [punk::lib::snapshot_package_paths]
set loader_tid [thread::create -joinable -preserved $init_script]
} else {
#punk::lib not available — fall back to bare thread
set loader_tid [thread::create -joinable -preserved]
}
}
if {![tsv::exists zzzload_pkg $pkgname]} {
#puts stderr "zzzload pkg_require $pkgname"

130
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/libunknown-0.1.tm

@ -100,6 +100,42 @@ tcl::namespace::eval ::punk::libunknown {
}
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::zipfs_tm_UnknownHandler
@cmd -name punk::libunknown::zipfs_tm_UnknownHandler\
-summary\
"Custom package unknown handler for tcl::tm::list module search paths."\
-help\
"Replaces Tcl's built-in ::tcl::tm::UnknownHandler as the first entry in the
package unknown handler chain. Called when package require cannot find a
satisfying version among already-registered ifneeded scripts.
Key differences from Tcl's standard tm handler:
- Uses an epoch-based cache to avoid re-scanning directories that have already
been searched. The epoch is incremented when tcl::tm::paths changes (via a
trace), invalidating stale cache entries.
- Registers ifneeded scripts for ALL .tm files found in each scanned directory,
not just the requested package — so sibling packages are discovered as a
side effect.
- For static (zipfs) paths, skips re-scanning a directory if the requested
package was not found there in a previous scan within the same epoch.
- Falls through to the next handler (e.g zipfs_tclPkgUnknown) if no satisfying
candidate is found in the tm paths.
The \$original parameter is the next handler in the package unknown chain,
called as a fallback when the tm search does not satisfy the request."
@leaders
original -type any -help\
"Next handler in the package unknown chain (list or empty). Called as fallback if the tm search does not satisfy the request."
name -type string -help\
"Package name being searched for."
@values -min 0 -max -1
args -type any -optional 1 -multiple 1 -help\
"Version requirements passed through from package require."
}]
}
#will use standard mechanism for non zipfs paths in the tm list.
proc zipfs_tm_UnknownHandler {original name args} {
#------------------------------
@ -441,6 +477,40 @@ tcl::namespace::eval ::punk::libunknown {
uplevel 1 $original [::linsert $args 0 $name]
}
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::zipfs_tclPkgUnknown
@cmd -name punk::libunknown::zipfs_tclPkgUnknown\
-summary\
"Custom package unknown handler for auto_path/pkgIndex.tcl package search."\
-help\
"Replaces Tcl's built-in ::tclPkgUnknown as the second entry in the package
unknown handler chain. Called when zipfs_tm_UnknownHandler could not satisfy
the package request from the tm paths.
Key differences from Tcl's standard tclPkgUnknown:
- Uses an epoch-based cache to avoid re-sourcing pkgIndex.tcl files that have
already been processed in the current epoch.
- Processes auto_path entries from end to front (same as tclPkgUnknown), but
tracks which packages and versions were added or changed by each pkgIndex.tcl
so that ifneeded scripts from earlier (higher-priority) paths can be reverted
if they were overridden by later (lower-priority) paths.
- The refresh/reversion mechanism ensures that path ordering priority is
respected even though auto_path is processed in reverse.
- Handles auto_path expansion: if a pkgIndex.tcl appends to auto_path during
sourcing, the new entries are reordered to follow the longest common prefix
rather than simply appending to the end.
- For static (zipfs) paths, skips re-sourcing pkgIndex.tcl files if the
requested package was not provided by that path in a previous scan."
@leaders
name -type string -help\
"Package name being searched for."
@values -min 0 -max -1
args -type any -optional 1 -multiple 1 -help\
"Version requirements passed through from package require."
}]
}
proc zipfs_tclPkgUnknown {name args} {
#puts "-> zipfs_tclPkgUnknown $name $args EXPERIMENTAL"
@ -1173,6 +1243,39 @@ tcl::namespace::eval ::punk::libunknown {
}
return $versionlist
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::init
@cmd -name punk::libunknown::init\
-summary\
"Install punk::libunknown's custom package unknown handlers and epoch system in the current interp."\
-help\
"Renames the builtin ::package to ::package:: and installs a custom ::package proc
that intercepts 'forget' (controlled forgetting) and adds an 'epoch' subcommand
(for introspection). Sets package unknown to a two-handler chain:
zipfs_tm_UnknownHandler (tm paths) and zipfs_tclPkgUnknown (auto_path/pkgIndex).
Installs traces on ::auto_path and ::tcl::tm::paths that increment the epoch
when these change, invalidating stale scan cache entries.
Epoch sharing: if \$::punk::libunknown::epoch is already set before init is called
(e.g copied from a parent interp via punk::lib::interp_sync_package_paths -libunknown 1),
init accepts it as a pre-provided record and uses the parent's scan cache instead
of building one from scratch. Packages that were already known before the epoch was
set are recorded as 'untracked' — full scans are performed for them on first request.
This proc should be called as early as possible in a new interp or thread, before
any package require calls that would trigger scans, to minimize the number of
untracked packages and maximize cache effectiveness.
See also: punk::lib::interp_sync_package_paths, punk::lib::snapshot_package_paths"
@opts
-caller -type string -default "" -help\
"Informational label identifying the calling context (e.g 'main.tcl', 'repl::init init_script').
Used only for debug logging — does not affect behaviour."
}]
}
proc init {args} {
variable last_auto_path
set last_auto_path [set ::auto_path]
@ -1503,6 +1606,33 @@ tcl::namespace::eval ::punk::libunknown {
package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::package_query
@cmd -name punk::libunknown::package_query\
-summary\
"Diagnostic tool showing epoch tracking and scan cache state for a named package."\
-help\
"Returns a text report showing what punk::libunknown knows about the given
package from its epoch-based scan cache. The report includes:
- Whether the package is in the tm or pkg 'untracked' sets (packages that were
already known before libunknown::init was called, meaning the epoch data is
not conclusive for them).
- A table of auto_path directories (pkg epoch) showing which packages were found
in each, with version numbers and epoch stamps for the requested package.
- A table of tcl::tm::list directories (tm epoch) showing which packages were
found in each, with version numbers for the requested package.
This is primarily a developer diagnostic for understanding why a particular
package version was (or was not) loaded, and which search path provided it.
Requires punk::ansi and textblock for the table formatting."
@values -min 1 -max 1
pkgname -type string -help\
"Name of the package to inspect."
}]
}
proc package_query {pkgname} {
variable epoch

12
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/zzzload-0.1.0.tm

@ -63,9 +63,15 @@ namespace eval zzzload {
return $ver
}
if {$loader_tid eq ""} {
set loader_tid [thread::create -joinable -preserved]
#todo - set tcl::tm::list and ::auto_path in the loader thread to match the main thread.
#(startup process may have modified these paths)
#propagate tm list, auto_path, and package prefer to the loader thread
#so it can find the same packages as the parent interp.
if {![catch {package require punk::lib}]} {
set init_script [punk::lib::snapshot_package_paths]
set loader_tid [thread::create -joinable -preserved $init_script]
} else {
#punk::lib not available — fall back to bare thread
set loader_tid [thread::create -joinable -preserved]
}
}
if {![tsv::exists zzzload_pkg $pkgname]} {
#puts stderr "zzzload pkg_require $pkgname"

130
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/libunknown-0.1.tm

@ -100,6 +100,42 @@ tcl::namespace::eval ::punk::libunknown {
}
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::zipfs_tm_UnknownHandler
@cmd -name punk::libunknown::zipfs_tm_UnknownHandler\
-summary\
"Custom package unknown handler for tcl::tm::list module search paths."\
-help\
"Replaces Tcl's built-in ::tcl::tm::UnknownHandler as the first entry in the
package unknown handler chain. Called when package require cannot find a
satisfying version among already-registered ifneeded scripts.
Key differences from Tcl's standard tm handler:
- Uses an epoch-based cache to avoid re-scanning directories that have already
been searched. The epoch is incremented when tcl::tm::paths changes (via a
trace), invalidating stale cache entries.
- Registers ifneeded scripts for ALL .tm files found in each scanned directory,
not just the requested package — so sibling packages are discovered as a
side effect.
- For static (zipfs) paths, skips re-scanning a directory if the requested
package was not found there in a previous scan within the same epoch.
- Falls through to the next handler (e.g zipfs_tclPkgUnknown) if no satisfying
candidate is found in the tm paths.
The \$original parameter is the next handler in the package unknown chain,
called as a fallback when the tm search does not satisfy the request."
@leaders
original -type any -help\
"Next handler in the package unknown chain (list or empty). Called as fallback if the tm search does not satisfy the request."
name -type string -help\
"Package name being searched for."
@values -min 0 -max -1
args -type any -optional 1 -multiple 1 -help\
"Version requirements passed through from package require."
}]
}
#will use standard mechanism for non zipfs paths in the tm list.
proc zipfs_tm_UnknownHandler {original name args} {
#------------------------------
@ -441,6 +477,40 @@ tcl::namespace::eval ::punk::libunknown {
uplevel 1 $original [::linsert $args 0 $name]
}
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::zipfs_tclPkgUnknown
@cmd -name punk::libunknown::zipfs_tclPkgUnknown\
-summary\
"Custom package unknown handler for auto_path/pkgIndex.tcl package search."\
-help\
"Replaces Tcl's built-in ::tclPkgUnknown as the second entry in the package
unknown handler chain. Called when zipfs_tm_UnknownHandler could not satisfy
the package request from the tm paths.
Key differences from Tcl's standard tclPkgUnknown:
- Uses an epoch-based cache to avoid re-sourcing pkgIndex.tcl files that have
already been processed in the current epoch.
- Processes auto_path entries from end to front (same as tclPkgUnknown), but
tracks which packages and versions were added or changed by each pkgIndex.tcl
so that ifneeded scripts from earlier (higher-priority) paths can be reverted
if they were overridden by later (lower-priority) paths.
- The refresh/reversion mechanism ensures that path ordering priority is
respected even though auto_path is processed in reverse.
- Handles auto_path expansion: if a pkgIndex.tcl appends to auto_path during
sourcing, the new entries are reordered to follow the longest common prefix
rather than simply appending to the end.
- For static (zipfs) paths, skips re-sourcing pkgIndex.tcl files if the
requested package was not provided by that path in a previous scan."
@leaders
name -type string -help\
"Package name being searched for."
@values -min 0 -max -1
args -type any -optional 1 -multiple 1 -help\
"Version requirements passed through from package require."
}]
}
proc zipfs_tclPkgUnknown {name args} {
#puts "-> zipfs_tclPkgUnknown $name $args EXPERIMENTAL"
@ -1173,6 +1243,39 @@ tcl::namespace::eval ::punk::libunknown {
}
return $versionlist
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::init
@cmd -name punk::libunknown::init\
-summary\
"Install punk::libunknown's custom package unknown handlers and epoch system in the current interp."\
-help\
"Renames the builtin ::package to ::package:: and installs a custom ::package proc
that intercepts 'forget' (controlled forgetting) and adds an 'epoch' subcommand
(for introspection). Sets package unknown to a two-handler chain:
zipfs_tm_UnknownHandler (tm paths) and zipfs_tclPkgUnknown (auto_path/pkgIndex).
Installs traces on ::auto_path and ::tcl::tm::paths that increment the epoch
when these change, invalidating stale scan cache entries.
Epoch sharing: if \$::punk::libunknown::epoch is already set before init is called
(e.g copied from a parent interp via punk::lib::interp_sync_package_paths -libunknown 1),
init accepts it as a pre-provided record and uses the parent's scan cache instead
of building one from scratch. Packages that were already known before the epoch was
set are recorded as 'untracked' — full scans are performed for them on first request.
This proc should be called as early as possible in a new interp or thread, before
any package require calls that would trigger scans, to minimize the number of
untracked packages and maximize cache effectiveness.
See also: punk::lib::interp_sync_package_paths, punk::lib::snapshot_package_paths"
@opts
-caller -type string -default "" -help\
"Informational label identifying the calling context (e.g 'main.tcl', 'repl::init init_script').
Used only for debug logging — does not affect behaviour."
}]
}
proc init {args} {
variable last_auto_path
set last_auto_path [set ::auto_path]
@ -1503,6 +1606,33 @@ tcl::namespace::eval ::punk::libunknown {
package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::libunknown::package_query
@cmd -name punk::libunknown::package_query\
-summary\
"Diagnostic tool showing epoch tracking and scan cache state for a named package."\
-help\
"Returns a text report showing what punk::libunknown knows about the given
package from its epoch-based scan cache. The report includes:
- Whether the package is in the tm or pkg 'untracked' sets (packages that were
already known before libunknown::init was called, meaning the epoch data is
not conclusive for them).
- A table of auto_path directories (pkg epoch) showing which packages were found
in each, with version numbers and epoch stamps for the requested package.
- A table of tcl::tm::list directories (tm epoch) showing which packages were
found in each, with version numbers for the requested package.
This is primarily a developer diagnostic for understanding why a particular
package version was (or was not) loaded, and which search path provided it.
Requires punk::ansi and textblock for the table formatting."
@values -min 1 -max 1
pkgname -type string -help\
"Name of the package to inspect."
}]
}
proc package_query {pkgname} {
variable epoch

12
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/zzzload-0.1.0.tm

@ -63,9 +63,15 @@ namespace eval zzzload {
return $ver
}
if {$loader_tid eq ""} {
set loader_tid [thread::create -joinable -preserved]
#todo - set tcl::tm::list and ::auto_path in the loader thread to match the main thread.
#(startup process may have modified these paths)
#propagate tm list, auto_path, and package prefer to the loader thread
#so it can find the same packages as the parent interp.
if {![catch {package require punk::lib}]} {
set init_script [punk::lib::snapshot_package_paths]
set loader_tid [thread::create -joinable -preserved $init_script]
} else {
#punk::lib not available — fall back to bare thread
set loader_tid [thread::create -joinable -preserved]
}
}
if {![tsv::exists zzzload_pkg $pkgname]} {
#puts stderr "zzzload pkg_require $pkgname"

Loading…
Cancel
Save