|
|
|
|
@ -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 |
|
|
|
|
|
|
|
|
|
|