|
|
|
|
@ -8,7 +8,7 @@
|
|
|
|
|
# (C) 2024 |
|
|
|
|
# |
|
|
|
|
# @@ Meta Begin |
|
|
|
|
# Application punk::lib 0.1.6 |
|
|
|
|
# Application punk::lib 0.2.0 |
|
|
|
|
# Meta platform tcl |
|
|
|
|
# Meta license BSD |
|
|
|
|
# @@ Meta End |
|
|
|
|
@ -18,7 +18,7 @@
|
|
|
|
|
# doctools header |
|
|
|
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
|
|
|
|
#*** !doctools |
|
|
|
|
#[manpage_begin punkshell_module_punk::lib 0 0.1.6] |
|
|
|
|
#[manpage_begin punkshell_module_punk::lib 0 0.2.0] |
|
|
|
|
#[copyright "2024"] |
|
|
|
|
#[titledesc {punk general utility functions}] [comment {-- Name section and table of contents description --}] |
|
|
|
|
#[moddesc {punk library}] [comment {-- Description at end of page heading --}] |
|
|
|
|
@ -8106,13 +8106,216 @@ namespace eval punk::lib {
|
|
|
|
|
return [expr {($deg_celsius * (9/5.0)) + 32}] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
proc interp_sync_package_paths {interp} { |
|
|
|
|
namespace eval argdoc { |
|
|
|
|
variable PUNKARGS |
|
|
|
|
lappend PUNKARGS [list { |
|
|
|
|
@id -id ::punk::lib::snapshot_package_paths |
|
|
|
|
@cmd -name punk::lib::snapshot_package_paths\ |
|
|
|
|
-summary\ |
|
|
|
|
"Return a script string that reproduces the caller's package loading state in a new interp or thread."\ |
|
|
|
|
-help\ |
|
|
|
|
"Captures the caller's tcl::tm::list (ordered), ::auto_path (ordered), and package prefer |
|
|
|
|
setting and returns a script string that, when evaluated in a new interpreter or thread |
|
|
|
|
init script, reproduces the same package search paths and version preference. |
|
|
|
|
|
|
|
|
|
This is intended for use in thread::create init scripts and interp eval calls where |
|
|
|
|
a child interp or thread needs to inherit the parent's package resolution state. |
|
|
|
|
|
|
|
|
|
With -libunknown 1, the script also copies the punk::libunknown epoch dict and |
|
|
|
|
sources+inits punk::libunknown in the target, so the child gets the same custom |
|
|
|
|
package unknown handler and scan cache as the parent. This avoids re-scanning |
|
|
|
|
all module and library paths on every package require in the child. |
|
|
|
|
|
|
|
|
|
The returned script uses only Tcl builtins (tcl::tm, set, package) and does not |
|
|
|
|
require any punk packages to be loaded in the target — except when -libunknown 1 |
|
|
|
|
is used, in which case punk::libunknown is sourced from the tm paths that were |
|
|
|
|
already set up by the earlier part of the script. |
|
|
|
|
|
|
|
|
|
See also: punk::lib::interp_sync_package_paths" |
|
|
|
|
@opts |
|
|
|
|
-libunknown -type boolean -default 0 -help\ |
|
|
|
|
"If 1, the script also sets up punk::libunknown in the target: copies the epoch |
|
|
|
|
dict, finds and sources libunknown-*.tm from the tm paths, and calls |
|
|
|
|
punk::libunknown::init. The child inherits the parent's scan cache and |
|
|
|
|
custom package unknown handler." |
|
|
|
|
}] |
|
|
|
|
} |
|
|
|
|
proc snapshot_package_paths {args} { |
|
|
|
|
#Returns a script string that reproduces the caller's tcl::tm::list, |
|
|
|
|
#auto_path, and package prefer state in a new interp or thread. |
|
|
|
|
#Optional -libunknown 1 also includes punk::libunknown epoch copy + init. |
|
|
|
|
set do_libunknown 0 |
|
|
|
|
for {set i 0} {$i < [llength $args]} {incr i} { |
|
|
|
|
set arg [lindex $args $i] |
|
|
|
|
switch -- $arg { |
|
|
|
|
-libunknown { |
|
|
|
|
set do_libunknown 1 |
|
|
|
|
incr i |
|
|
|
|
#value is 0 or 1 |
|
|
|
|
if {$i < [llength $args]} { |
|
|
|
|
set do_libunknown [lindex $args $i] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
error "snapshot_package_paths: unknown option '$arg'" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
set tmlist [tcl::tm::list] |
|
|
|
|
set ap $::auto_path |
|
|
|
|
set prefer [package prefer] |
|
|
|
|
set script "" |
|
|
|
|
append script "tcl::tm::remove \{*\}\[tcl::tm::list\]\n" |
|
|
|
|
append script "tcl::tm::add \{*\}\[list [lreverse $tmlist]\]\n" |
|
|
|
|
append script "set ::auto_path \[list $ap\]\n" |
|
|
|
|
append script "package prefer $prefer\n" |
|
|
|
|
if {$do_libunknown} { |
|
|
|
|
if {[info exists ::punk::libunknown::epoch]} { |
|
|
|
|
append script "namespace eval ::punk::libunknown {}\n" |
|
|
|
|
append script "set ::punk::libunknown::epoch [list $::punk::libunknown::epoch]\n" |
|
|
|
|
} |
|
|
|
|
#find and source libunknown, then call init |
|
|
|
|
append script { |
|
|
|
|
apply {{} { |
|
|
|
|
set libunks [list] |
|
|
|
|
foreach tm_path [tcl::tm::list] { |
|
|
|
|
set punkdir [file join $tm_path punk] |
|
|
|
|
if {![file exists $punkdir]} {continue} |
|
|
|
|
lappend libunks {*}[glob -nocomplain -dir $punkdir -type f libunknown-*.tm] |
|
|
|
|
} |
|
|
|
|
set libunknown "" |
|
|
|
|
set libunknown_version_sofar "" |
|
|
|
|
foreach lib $libunks { |
|
|
|
|
set vtail [lindex [split [file tail $lib] -] 1] |
|
|
|
|
set thisver [file rootname $vtail] |
|
|
|
|
if {$libunknown_version_sofar eq ""} { |
|
|
|
|
set libunknown_version_sofar $thisver |
|
|
|
|
set libunknown $lib |
|
|
|
|
} else { |
|
|
|
|
if {[package vcompare $thisver $libunknown_version_sofar] == 1} { |
|
|
|
|
set libunknown_version_sofar $thisver |
|
|
|
|
set libunknown $lib |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if {$libunknown ne ""} { |
|
|
|
|
uplevel 1 [list source $libunknown] |
|
|
|
|
if {[catch {punk::libunknown::init -caller "snapshot_package_paths"} errM]} { |
|
|
|
|
puts stderr "snapshot_package_paths: error initialising punk::libunknown\n$errM" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
} |
|
|
|
|
append script "\n" |
|
|
|
|
} |
|
|
|
|
return $script |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
namespace eval argdoc { |
|
|
|
|
variable PUNKARGS |
|
|
|
|
lappend PUNKARGS [list { |
|
|
|
|
@id -id ::punk::lib::interp_sync_package_paths |
|
|
|
|
@cmd -name punk::lib::interp_sync_package_paths\ |
|
|
|
|
-summary\ |
|
|
|
|
"Propagate the caller's tcl::tm::list, auto_path, and package prefer to a child interpreter."\ |
|
|
|
|
-help\ |
|
|
|
|
"Synchronises a child interpreter's package search paths and version preference |
|
|
|
|
to match the caller's state. The child interp must already exist (create it first |
|
|
|
|
with [interp create] or [interp create -safe]). |
|
|
|
|
|
|
|
|
|
This propagates: |
|
|
|
|
- tcl::tm::list (ordered — same priority ordering as parent) |
|
|
|
|
- ::auto_path (ordered) |
|
|
|
|
- package prefer (e.g 'latest' or 'stable') |
|
|
|
|
|
|
|
|
|
With -libunknown 1, also copies the punk::libunknown epoch dict to the child |
|
|
|
|
and sources+inits punk::libunknown there, giving the child the same custom |
|
|
|
|
package unknown handler and scan cache as the parent. This is recommended |
|
|
|
|
when the child will do significant package loading. |
|
|
|
|
|
|
|
|
|
This is an opt-in helper — call sites that don't use it keep their current |
|
|
|
|
behavior. It does not load packages, install punk::packagepreference, share |
|
|
|
|
channels, or configure safe-interp restrictions — those remain caller |
|
|
|
|
responsibilities. |
|
|
|
|
|
|
|
|
|
See also: punk::lib::snapshot_package_paths" |
|
|
|
|
@leaders |
|
|
|
|
interp -type string -help\ |
|
|
|
|
"Name of the child interpreter to synchronise. Must already exist." |
|
|
|
|
@opts |
|
|
|
|
-libunknown -type boolean -default 0 -help\ |
|
|
|
|
"If 1, also copy punk::libunknown epoch, source libunknown-*.tm in the child, |
|
|
|
|
and call punk::libunknown::init so the child inherits the parent's scan |
|
|
|
|
cache and custom package unknown handler." |
|
|
|
|
}] |
|
|
|
|
} |
|
|
|
|
proc interp_sync_package_paths {interp args} { |
|
|
|
|
if {![interp exists $interp]} { |
|
|
|
|
error "interp_sync_package_paths error. interp '$interp' not found. Create it first with \[interp create $interp\]" |
|
|
|
|
} |
|
|
|
|
set do_libunknown 0 |
|
|
|
|
for {set i 0} {$i < [llength $args]} {incr i} { |
|
|
|
|
set arg [lindex $args $i] |
|
|
|
|
switch -- $arg { |
|
|
|
|
-libunknown { |
|
|
|
|
set do_libunknown 1 |
|
|
|
|
incr i |
|
|
|
|
if {$i < [llength $args]} { |
|
|
|
|
set do_libunknown [lindex $args $i] |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
default { |
|
|
|
|
error "interp_sync_package_paths: unknown option '$arg'" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#basic propagation: tm list, auto_path, package prefer |
|
|
|
|
interp eval $interp [list set ::auto_path $::auto_path] |
|
|
|
|
interp eval $interp {tcl::tm::remove {*}[tcl::tm::list]} |
|
|
|
|
interp eval $interp [list tcl::tm::add {*}[lreverse [tcl::tm::list]]] |
|
|
|
|
interp eval $interp [list package prefer [package prefer]] |
|
|
|
|
#extended: copy epoch + source libunknown + call init |
|
|
|
|
if {$do_libunknown} { |
|
|
|
|
if {[info exists ::punk::libunknown::epoch]} { |
|
|
|
|
interp eval $interp {namespace eval ::punk::libunknown {}} |
|
|
|
|
interp eval $interp [list set ::punk::libunknown::epoch $::punk::libunknown::epoch] |
|
|
|
|
} |
|
|
|
|
#use snapshot's libunknown sourcing logic via interp eval |
|
|
|
|
set libunknown_script [punk::lib::snapshot_package_paths -libunknown 1] |
|
|
|
|
#extract just the libunknown sourcing part (after the basic propagation) |
|
|
|
|
#we already did basic propagation above, so only run the libunknown init part |
|
|
|
|
interp eval $interp { |
|
|
|
|
apply {{} { |
|
|
|
|
set libunks [list] |
|
|
|
|
foreach tm_path [tcl::tm::list] { |
|
|
|
|
set punkdir [file join $tm_path punk] |
|
|
|
|
if {![file exists $punkdir]} {continue} |
|
|
|
|
lappend libunks {*}[glob -nocomplain -dir $punkdir -type f libunknown-*.tm] |
|
|
|
|
} |
|
|
|
|
set libunknown "" |
|
|
|
|
set libunknown_version_sofar "" |
|
|
|
|
foreach lib $libunks { |
|
|
|
|
set vtail [lindex [split [file tail $lib] -] 1] |
|
|
|
|
set thisver [file rootname $vtail] |
|
|
|
|
if {$libunknown_version_sofar eq ""} { |
|
|
|
|
set libunknown_version_sofar $thisver |
|
|
|
|
set libunknown $lib |
|
|
|
|
} else { |
|
|
|
|
if {[package vcompare $thisver $libunknown_version_sofar] == 1} { |
|
|
|
|
set libunknown_version_sofar $thisver |
|
|
|
|
set libunknown $lib |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if {$libunknown ne ""} { |
|
|
|
|
uplevel 1 [list source $libunknown] |
|
|
|
|
if {[catch {punk::libunknown::init -caller "interp_sync_package_paths"} errM]} { |
|
|
|
|
puts stderr "interp_sync_package_paths: error initialising punk::libunknown\n$errM" |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
proc valcopy {obj} { |
|
|
|
|
@ -8866,7 +9069,7 @@ namespace eval ::punk::args::register {
|
|
|
|
|
package provide punk::lib [tcl::namespace::eval punk::lib { |
|
|
|
|
variable pkg punk::lib |
|
|
|
|
variable version |
|
|
|
|
set version 0.1.6 |
|
|
|
|
set version 0.2.0 |
|
|
|
|
}] |
|
|
|
|
return |
|
|
|
|
|