Browse Source

update bootsupport and vfs

master
Julian Noble 1 week ago
parent
commit
077059e043
  1. 1002
      src/bootsupport/modules/punk-0.2.0.tm
  2. 50
      src/bootsupport/modules/punk/args-0.2.3.tm
  3. 14
      src/bootsupport/modules/punk/ns-0.1.1.tm
  4. 10
      src/bootsupport/modules/punk/packagepreference-0.1.1.tm
  5. 94
      src/bootsupport/modules/punk/path-0.2.2.tm
  6. 9
      src/bootsupport/modules/shellfilter-0.2.4.tm
  7. 20
      src/bootsupport/modules/shellthread-1.6.3.tm
  8. 200
      src/bootsupport/modules/tomlish-1.1.10.tm
  9. 1002
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk-0.2.0.tm
  10. 50
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/args-0.2.3.tm
  11. 14
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ns-0.1.1.tm
  12. 10
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/packagepreference-0.1.1.tm
  13. 94
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.2.2.tm
  14. 9
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/shellfilter-0.2.4.tm
  15. 20
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/shellthread-1.6.3.tm
  16. 200
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/tomlish-1.1.10.tm
  17. 1002
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk-0.2.0.tm
  18. 50
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/args-0.2.3.tm
  19. 14
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ns-0.1.1.tm
  20. 10
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/packagepreference-0.1.1.tm
  21. 94
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.2.2.tm
  22. 9
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/shellfilter-0.2.4.tm
  23. 20
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/shellthread-1.6.3.tm
  24. 200
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/tomlish-1.1.10.tm
  25. 1002
      src/vfs/_vfscommon.vfs/modules/punk-0.2.0.tm
  26. 50
      src/vfs/_vfscommon.vfs/modules/punk/args-0.2.3.tm
  27. 14
      src/vfs/_vfscommon.vfs/modules/punk/ns-0.1.1.tm

1002
src/bootsupport/modules/punk-0.1.1.tm → src/bootsupport/modules/punk-0.2.0.tm

File diff suppressed because it is too large Load Diff

50
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/args-0.2.1.tm → src/bootsupport/modules/punk/args-0.2.3.tm

@ -8,7 +8,7 @@
# (C) 2024
#
# @@ Meta Begin
# Application punk::args 0.2.1
# Application punk::args 0.2.3
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -18,7 +18,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::args 0 0.2.1]
#[manpage_begin punkshell_module_punk::args 0 0.2.3]
#[copyright "2024"]
#[titledesc {args parsing}] [comment {-- Name section and table of contents description --}]
#[moddesc {args to nested dict of opts and values}] [comment {-- Description at end of page heading --}]
@ -871,19 +871,46 @@ tcl::namespace::eval punk::args {
-choicerestricted <bool>
Whether values not specified in -choices or -choicegroups are
allowed. Defaults to true.
When false, an input that matches no choice - including an
ambiguous prefix, a prefix of a -choiceprefixdenylist entry,
or a -choiceprefixreservelist word - is accepted unchanged as
an ordinary value (subject to -type validation) instead of
raising an error. This passthrough is the pattern for
arguments that mix a known choice set with free-form values
(e.g. a help topic word falling through to command lookup).
-choiceprefix <bool>
This specifies whether unique prefixes are able to be used
instead of the complete string. This is calculated using
tcl::prefix::match - and will display in the autogenerated
usage output. Defaults to true.
A matching prefix is normalized: the parse result contains
the full choice string, never the typed prefix - so callers
switch on canonical choice values only. The usage display
highlights each choice's minimal accepted prefix (a choice
in -choiceprefixdenylist displays fully highlighted - the
whole word is required).
-choiceprefixdenylist {<choices>}
These choices should match exactly a choice entry in one of
the settings -choices or -choicegroups.
These will still be used in prefix calculation - but the full
choice argument must be entered to select the choice.
A shorter prefix of a denied choice is an error when
-choicerestricted is true, and passes through as an ordinary
(non-choice) value when -choicerestricted is false - use this
to keep short words available for other purposes (e.g. with
'help' denied, h/he/hel remain free-form values).
-choiceprefixreservelist {<choices>}
These choices are additional values used in prefix calculation.
The values will not be added to the list of available choices.
A reserved word never matches: entered exactly it is an error
when -choicerestricted is true and passes through when false,
as do any shorter words it shadows into ambiguity. This gives
per-choice control of the minimum accepted prefix by reserving
phantom entries: e.g. -choices {environment}
-choiceprefixreservelist {en} means e/en do not match while
env, envi, ... environment all normalize to environment.
(To require a longer minimum, reserve each shorter form:
reserving {en env} raises the minimum to envi.)
-choicegroups {<dict>}
Generally this would be used instead of -choices to allow
usage display of choices grouped by some name (or the empty
@ -6156,7 +6183,7 @@ tcl::namespace::eval punk::args {
#puts stderr ">>>_get_dict_can_assign_value idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
set d [dict create consumed $alloc_count resultlist $resultlist typelist $newtypelist]
} else {
puts stderr ">>>_get_dict_can_assign_value NOT alloc_ok: idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
#puts stderr ">>>_get_dict_can_assign_value NOT alloc_ok: idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
set d [dict create consumed 0 resultlist {} typelist $thistype]
}
#puts ">>>> _get_dict_can_assign_value $d"
@ -9835,7 +9862,10 @@ tcl::namespace::eval punk::args {
set argname [dict get $lookup_optset $fullflag]
#idents should already have correct parsekey
} else {
puts stderr "punk::args::get_dict unable to find $fullflag in $lookup_optset (parsekey:$parsekey) (value_group: $value_group)"
#adhoc option (allowed via "@opts -any|-arbitrary true") - not in lookup_optset.
#argstate/arg_checks were populated for it under its raw supplied name at scan time.
set argname $fullflag
#puts stderr "punk::args::get_dict unable to find $fullflag in $lookup_optset (parsekey:$parsekey) (value_group: $value_group)"
}
} else {
if {[dict exists $lookup_optset $argname_or_ident]} {
@ -9850,7 +9880,15 @@ tcl::namespace::eval punk::args {
set parsekey [string trimright [lindex [split $argname |] end] =]
}
} else {
puts stderr "punk::args::get_dict unable to find $argname_or_ident in $lookup_optset (value_group: $value_group)"
#adhoc option (allowed via "@opts -any|-arbitrary true") - not in lookup_optset.
#argstate/arg_checks were populated for it under its raw supplied name at scan time.
set argname $argname_or_ident
if {$pkoverride ne ""} {
set parsekey $pkoverride
} else {
set parsekey [string trimright [lindex [split $argname |] end] =]
}
#puts stderr "punk::args::get_dict unable to find $argname_or_ident in $lookup_optset (value_group: $value_group)"
}
}
} else {
@ -12357,7 +12395,7 @@ package provide punk::args [tcl::namespace::eval punk::args {
tcl::namespace::path {::punk::args::lib ::punk::args::system}
variable pkg punk::args
variable version
set version 0.2.1
set version 0.2.3
}]
return

14
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ns-0.1.0.tm → src/bootsupport/modules/punk/ns-0.1.1.tm

@ -7,7 +7,7 @@
# (C) 2023
#
# @@ Meta Begin
# Application punk::ns 0.1.0
# Application punk::ns 0.1.1
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -4633,7 +4633,7 @@ y" {return quirkykeyscript}
set vline [punk::args::ensemble_subcommands_definition -columns 2 $origin]
set autoid "(autodef)$origin"
puts "ENSEMBLE auto def $autoid (generate_autodef)"
#puts "ENSEMBLE auto def $autoid (generate_autodef)"
#A namespace can contain spaces, so an ensemble command can contain spaces. We must quote the -id value in the autodef
set argdef [punk::lib::tstr -return string {
@id -id "${$autoid}"
@ -4699,7 +4699,7 @@ y" {return quirkykeyscript}
append argdef \n "@formdisplay -body {$tepamhelp}"
punk::args::define $argdef
} else {
puts "PROC auto def $autoid (generate_autodef)"
#puts "PROC auto def $autoid (generate_autodef)"
#to handle procs like ":" (eg used by colin's bytecode based expr replacement) or other names of the form ":xyz"
#we can't use 'info args :::' - tcl won't find it
set ns [nsprefix $origin]
@ -5026,7 +5026,7 @@ y" {return quirkykeyscript}
if {[punk::args::id_exists "$origin [lindex $args $i]"]} {
set a [lindex $args $i]
#review - tests?
puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'"
#puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'"
#we can only seek beyond an undocumented subcommand level via a space delimited path, as we can make no assumption about the actual location of a subcommand relative to its parent
#There could be a different command at for example "${origin}::$a" which is unrelated to the actual resolution path.
set docid_exists 1
@ -5120,7 +5120,7 @@ y" {return quirkykeyscript}
lappend resolvedargs $q
lpop queryargs_untested 0
lappend eparams $q
puts stderr "---> cmd_traverse ensembleparam $q ($lname)"
#puts stderr "---> cmd_traverse ensembleparam $q ($lname)"
#puts stderr "arginfo: $arginfo"
#puts stderr "---> eparams: $eparams"
#puts stderr "---> existing args: $args"
@ -5304,7 +5304,7 @@ y" {return quirkykeyscript}
}
}
#REVIEW!!!
puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
#puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
return [list 10 $origin $resolvedargs $queryargs_untested $docid]
}
@ -7591,6 +7591,6 @@ namespace eval ::punk::args::register {
## Ready
package provide punk::ns [tcl::namespace::eval punk::ns {
variable version
set version 0.1.0
set version 0.1.1
}]
return

10
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/packagepreference-0.1.0.tm → src/bootsupport/modules/punk/packagepreference-0.1.1.tm

@ -8,7 +8,7 @@
# (C) 2024
#
# @@ Meta Begin
# Application punk::packagepreference 0.1.0
# Application punk::packagepreference 0.1.1
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -18,7 +18,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::packagepreference 0 0.1.0]
#[manpage_begin punkshell_module_punk::packagepreference 0 0.1.1]
#[copyright "2024"]
#[titledesc {punkshell package/module loading}] [comment {-- Name section and table of contents description --}]
#[moddesc {package/module load}] [comment {-- Description at end of page heading --}]
@ -321,7 +321,9 @@ tcl::namespace::eval punk::packagepreference {
if {[catch {thread::id} threadid]} {
set threadid "unknown-threadid"
}
puts stdout "punk::packagepreference overloaded 'package require': Loaded punk::args::moduledoc::$dp for package '$pkg' threadid: $threadid"
#notice goes to stderr: stdout must stay clean for script/exec contexts
#(e.g the punk executable's 'script' subcommand - machine-consumed output)
puts stderr "punk::packagepreference overloaded 'package require': Loaded punk::args::moduledoc::$dp for package '$pkg' threadid: $threadid"
}
}
#---------------------------------------------------------------
@ -487,7 +489,7 @@ namespace eval ::punk::args::register {
package provide punk::packagepreference [tcl::namespace::eval punk::packagepreference {
variable pkg punk::packagepreference
variable version
set version 0.1.0
set version 0.1.1
}]
return

94
src/bootsupport/modules/punk/path-0.2.1.tm → src/bootsupport/modules/punk/path-0.2.2.tm

@ -7,7 +7,7 @@
# (C) 2023
#
# @@ Meta Begin
# Application punk::path 0.2.1
# Application punk::path 0.2.2
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -17,7 +17,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::path 0 0.2.1]
#[manpage_begin punkshell_module_punk::path 0 0.2.2]
#[copyright "2023"]
#[titledesc {Filesystem path utilities}] [comment {-- Name section and table of contents description --}]
#[moddesc {punk path filesystem utils}] [comment {-- Description at end of page heading --}]
@ -485,6 +485,87 @@ namespace eval punk::path {
return relative
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::punk::path::scriptlib_resolve
@cmd -name "punk::path::scriptlib_resolve"\
-summary\
"Resolve a scriptlib script name to a path using the punk kit search policy"\
-help\
"Resolves a relative script name (the part after a 'lib:' prefix
in punk executable launch arguments) against the scriptlib
locations, in the same order the punk shell uses:
1. the kit vfs internal scriptlib (<zipfs-root>/app/scriptlib,
or <exedir>/scriptlib for an unwrapped kit directory).
Internal scripts are deliberately NOT overridable by
external files (integrity and performance).
2. <exedir-parent>/scriptlib - e.g <projectroot>/scriptlib for
an executable in <projectroot>/bin.
3. <exedir-grandparent>/scriptlib.
If the name's extension (lowercased) is not one of the known
scriptlib extensions (.tcl .py .pl .ps1 .sh), '.tcl' is
appended - only .tcl scripts may be named extensionlessly.
Returns a dict with keys:
path - resolved absolute path, or empty string if not found
scriptname - the name searched for (extension applied)
candidates - the locations that were (or would be) checked,
for use in error messages.
Raises an error if name is not a relative path."
@leaders
name -type string -optional 0 -help\
"relative script name, with or without a known extension
(any leading lib: prefix should already be stripped)"
}]
}
proc scriptlib_resolve {name} {
#shared resolution policy for the 'lib:' script prefix - used by the punk
#executable 'script' subcommand (app-punkscript); app-punkshell's shell
#subcommand encodes the same policy (todo: refactor it onto this proc).
if {[lindex [pathtype $name] 0] ne "relative"} {
error "punk::path::scriptlib_resolve name must be a relative path (got '$name')"
}
set known_extensions [list .tcl .py .pl .ps1 .sh]
if {[string tolower [file extension $name]] ni $known_extensions} {
#only .tcl scripts allowed to be called extensionlessly
set scriptname $name.tcl
} else {
set scriptname $name
}
set exepath [file dirname [file normalize [file join [info nameofexecutable] ___]]] ;#symlink resolve
set candidates [list]
#1) kit-internal scriptlib - not overridable externally
set has_zipfs_command [expr {[info commands ::tcl::zipfs::root] ne ""}]
set kit_base ""
if {$has_zipfs_command && [file exists [tcl::zipfs::root]]} {
set kit_base [tcl::zipfs::root]
} elseif {[file type $exepath] eq "directory"} {
set kit_base $exepath
}
set kit_libdir ""
if {$has_zipfs_command && $kit_base ne "" && [file exists $kit_base/app/scriptlib]} {
set kit_libdir $kit_base/app/scriptlib
} elseif {[file exists $exepath/scriptlib]} {
set kit_libdir $exepath/scriptlib
}
if {$kit_libdir ne ""} {
lappend candidates $kit_libdir/$scriptname
if {[file exists $kit_libdir/$scriptname]} {
return [dict create path $kit_libdir/$scriptname scriptname $scriptname candidates $candidates]
}
}
#2,3) external scriptlib folders relative to the executable location
set exedir [file dirname $exepath]
foreach dir [list [file join $exedir scriptlib] [file join [file dirname $exedir] scriptlib]] {
lappend candidates [file join $dir $scriptname]
if {[file isdirectory $dir] && [file exists [file join $dir $scriptname]]} {
return [dict create path [file join $dir $scriptname] scriptname $scriptname candidates $candidates]
}
}
return [dict create path "" scriptname $scriptname candidates $candidates]
}
proc plain {str} {
set str [string map "\\\\ /" $str]
@ -1598,12 +1679,19 @@ namespace eval punk::path::system {
}
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
#documentation-only PUNKARGS registration - discovered lazily if/when punk::args loads
lappend ::punk::args::register::NAMESPACES ::punk::path::argdoc
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::path [namespace eval punk::path {
variable pkg punk::path
variable version
set version 0.2.1
set version 0.2.2
}]
return

9
src/bootsupport/modules/shellfilter-0.2.3.tm → src/bootsupport/modules/shellfilter-0.2.4.tm

@ -2813,8 +2813,11 @@ namespace eval shellfilter {
set syslog [dict get $opts -syslog]
dict unset opts -syslog
set runtag "shellfilter-run"
set tid [::shellfilter::log::open $runtag [list -syslog 127.0.0.1:514]]
#set tid [::shellfilter::log::open $runtag [list -syslog $syslog]]
#honor the -syslog option (default empty) - the previous hardcoded 127.0.0.1:514 was a
#debug leftover. With no -syslog and no -file the runtag log worker is a noop (no thread
#is created). Syslog remains supported when explicitly configured; see G-036 for the
#Tcl 9 console+udp worker wedge that the always-on syslog worker exposed on exit/quit.
set tid [::shellfilter::log::open $runtag [list -syslog $syslog]]
log::info {::shellfilter::log::write $runtag " opts: $opts"}
log::info {::shellfilter::log::write $runtag " commandlist:'$commandlist' listlen:$listlen strlen:[string length $commandlist]"}
@ -3827,5 +3830,5 @@ namespace eval shellfilter {
package provide shellfilter [namespace eval shellfilter {
variable version
set version 0.2.3
set version 0.2.4
}]

20
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/shellthread-1.6.2.tm → src/bootsupport/modules/shellthread-1.6.3.tm

@ -788,8 +788,12 @@ namespace eval shellthread::manager {
foreach workertid $subscriberless_workers {
if {$workertid ni $shuttingdown_workers} {
if {$workertid ni $free_threads && $workertid ne "noop"} {
#JMN
thread::send $workertid {set ::shellthread::worker::settings $::shellthread::worker::settings_defaults}
#Must be async: unsubscribe is on the exit/quit teardown path and a worker whose
#event loop has stopped servicing events (G-036: Tcl 9 console+udp worker wedge)
#would block a synchronous send forever, freezing the shell. Async is safe -
#sends to a thread are processed FIFO, so a later reuse via new_worker sees the
#settings reset applied before anything it sends.
thread::send -async $workertid {set ::shellthread::worker::settings $::shellthread::worker::settings_defaults}
#todo - log freeing up of thread
lappend free_threads $workertid
}
@ -812,7 +816,10 @@ namespace eval shellthread::manager {
}
proc get_tag_config {tag} {
#review
#review - bare synchronous thread::send: blocks forever if the worker's event loop is
#wedged (G-036 hazard class). Reached from new_worker when a tag already has a live
#worker. Needs a result so can't simply go async - convert to async + vwait-with-timeout
#if this path shows up in a hang.
variable workers
if {![dict exists $workers $tag]} {
error "shellthread::manager::get_tag_config error no existing tag $tag"
@ -858,10 +865,13 @@ namespace eval shellthread::manager {
set timedout 1
break
} else {
after cancel $timeout_timer
#Do not cancel the timeout timer until all awaited workers have responded -
#cancelling on the first response left later vwait iterations unbounded, so a
#wedged worker (G-036) after a healthy one hung shutdown forever.
lappend ended $::shellthread::waitfor
}
}
after cancel $timeout_timer
}
set free_threads [list]
return [dict create existed $waiting_for ended $ended timedout $timedout allthreads [thread::names]]
@ -963,7 +973,7 @@ namespace eval shellthread::manager {
package provide shellthread [namespace eval shellthread {
variable version
set version 1.6.2
set version 1.6.3
}]

200
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/tomlish-1.1.8.tm → src/bootsupport/modules/tomlish-1.1.10.tm

@ -7,7 +7,7 @@
# (C) 2024
#
# @@ Meta Begin
# Application tomlish 1.1.8
# Application tomlish 1.1.10
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -17,7 +17,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin tomlish_module_tomlish 0 1.1.8]
#[manpage_begin tomlish_module_tomlish 0 1.1.10]
#[copyright "2024"]
#[titledesc {tomlish toml parser}] [comment {-- Name section and table of contents description --}]
#[moddesc {tomlish}] [comment {-- Description at end of page heading --}]
@ -385,6 +385,45 @@ namespace eval tomlish {
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::to_dict
@cmd -name "tomlish::to_dict"\
-summary\
"Convert a tomlish structure to a Tcl dict with typed leaf values"\
-help\
"Converts tomlish (the tagged-list representation produced
by tomlish::from_toml) to a Tcl dict datastructure.
Toml tables map to nested dict keys. Each leaf value is a
two-element dict of the form {type <TYPE> value <value>}
where <TYPE> is a toml/tomlish type such as INT, FLOAT,
BOOL, STRING, LITERAL, MULTISTRING, MULTILITERAL, DATETIME
or ARRAY (an ARRAY value is a list of typed elements).
Escape sequences in quoted strings are substituted during
this conversion.
Whitespace and comments are not represented in the result,
so a dict alone cannot round-trip formatting - use
tomlish::update_tomlish_from_dict to write dict values back
into an existing tomlish structure when preservation
matters.
Toml validity rules that require whole-document knowledge
(e.g 'You cannot define any key or table more than once')
are enforced here and raise errors.
Returns the dict, or with returnextra true a dict with keys
'datastructure' (the converted dict) and 'tablenames_info'
(per-tablename creation/definition metadata)."
@leaders
tomlish -type list -optional 0 -help\
"tomlish tagged list (e.g from tomlish::from_toml)"
returnextra -type boolean -optional 1 -default 0 -help\
"when true, return a dict of keys 'datastructure' and
'tablenames_info' instead of the datastructure alone"
}]
}
proc to_dict {tomlish {returnextra 0}} {
tomlish::dict::from_tomlish $tomlish $returnextra
}
@ -708,6 +747,31 @@ namespace eval tomlish {
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::from_dict
@cmd -name "tomlish::from_dict"\
-summary\
"Convert a dict with typed leaf values to a tomlish structure"\
-help\
"Converts a Tcl dict whose leaf values are typed
({type <TYPE> value <value>} - the form produced by
tomlish::to_dict) into a new tomlish tagged-list structure,
which tomlish::to_toml can serialise to toml text.
The dict must be a full typed representation - plain
untyped leaf values are not accepted. As a dict carries no
whitespace/comment information, the generated tomlish (and
any toml produced from it) uses generated formatting; to
preserve the formatting of an existing document, write
values back with tomlish::update_tomlish_from_dict instead.
Returns the tomlish list."
@leaders
d -type dict -optional 0 -help\
"dict with typed leaf values (e.g from tomlish::to_dict)"
}]
}
proc from_dict {d} {
#consider:
# t1={a=1,b=2}
@ -906,6 +970,33 @@ namespace eval tomlish {
# For this reason, we also do absolutely no line-ending transformations based on platform.
# All line-endings are maintained as is, and even a file with mixed lf crlf line-endings will be correctly interpreted and can be 'roundtripped'
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::from_toml
@cmd -name "tomlish::from_toml"\
-summary\
"Parse toml text into a tomlish tagged-list structure"\
-help\
"Parses toml source text into 'tomlish' - the intermediate
tagged-list representation used by the tomlish package.
tomlish is whitespace and comment preserving: serialising
the result with tomlish::to_toml reproduces the input byte
for byte (lossless round-trip). No escape sequences in
quoted strings are processed at this stage and no
line-ending transformations are performed - that occurs in
datastructure conversions such as tomlish::to_dict.
Returns the tomlish list: first element is the tag TOMLISH,
remaining elements are tagged records such as TABLE,
TABLEARRAY, DOTTEDKEY, WS, COMMENT, NEWLINE.
Raises an error for invalid toml."
@values -min 1 -max -1
toml -type string -optional 0 -multiple 1 -help\
"toml source text. Multiple values are joined with newline
characters before parsing."
}]
}
proc from_toml {args} {
namespace upvar ::tomlish::parse s s
@ -1764,6 +1855,34 @@ namespace eval tomlish {
# updating from a subset dict (reduces processing - and more flexible to supply only paths to leaves requiring update?)
#
#todo - allow adding extra leaves e.g keys in tables,tablearrays, itables, arrays
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::update_tomlish_from_dict
@cmd -name "tomlish::update_tomlish_from_dict"\
-summary\
"Update leaf values in a tomlish structure from a typed dict, preserving formatting"\
-help\
"Merges values from dict d into an existing tomlish
structure and returns the updated tomlish, in which
whitespace, comments and key ordering are preserved.
This is the formatting-preserving write path: parse a
document with tomlish::from_toml, convert with
tomlish::to_dict, modify values in the dict, apply them
with this command, then serialise with tomlish::to_toml.
d must be a full typed representation of the datastructure
(as produced by tomlish::to_dict). The initial
implementation updates leaf values only - adding or pruning
keys/branches is not yet supported."
@leaders
tomlish -type list -optional 0 -help\
"existing tomlish tagged list (e.g from tomlish::from_toml)"
d -type dict -optional 0 -help\
"full typed-dict representation carrying the updated leaf
values"
}]
}
proc update_tomlish_from_dict {tomlish d} {
set returnextra true
#validate supplied tomlish and keep tablenames_info (review - validate structure only - allow invalid values to be overwritten from dict?)
@ -2441,6 +2560,34 @@ namespace eval tomlish::encode {
#fish toml from tomlish
#(encode tomlish as toml)
namespace eval ::tomlish::argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::to_toml
@cmd -name "tomlish::to_toml"\
-summary\
"Serialise a tomlish structure to toml text"\
-help\
"Encodes tomlish (the tagged-list representation produced by
tomlish::from_toml or tomlish::from_dict) as toml text.
For tomlish obtained from tomlish::from_toml this reproduces
the original document byte for byte, including whitespace and
comments (lossless round-trip).
Validation here is structural only - toml validity rules that
need whole-document knowledge (e.g duplicate keys/tables) are
not detected; they are the role of the dict conversion pair
tomlish::to_dict / tomlish::from_dict.
tomlish::to_toml is an alias of tomlish::encode::tomlish.
Returns the toml text."
@leaders
list -type list -optional 0 -help\
"tomlish tagged list"
context -type string -optional 1 -default "" -help\
"internal recursion context tag - omit in normal use"
}]
}
interp alias {} tomlish::to_toml {} tomlish::encode::tomlish
#
@ -9408,12 +9555,48 @@ namespace eval tomlish::system {
#[list_end] [comment {--- end definitions namespace tomlish::system ---}]
}
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
#documentation-only PUNKARGS registration - discovered lazily if/when punk::args is loaded;
#adds no punk::args dependency to the tomlish library itself.
lappend ::punk::args::register::NAMESPACES ::tomlish::argdoc
}
# if {[info exists ::argc] && $::argc > 0} {} ;#not a valid way to test if main script
if {[tomlish::system::is_main_script]} {
#puts stderr "argc: $::argc args: $::argv"
set arglist $::argv
namespace eval tomlish {
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::cmdline_main
@cmd -name "tomlish::cmdline_main"\
-summary\
"Run the tomlish command-line application on an argument list"\
-help\
"Explicit entry point for the tomlish command-line app
(usage display and -app dispatch to the tomlish::app::*
applications such as decode_to_typedjson,
encode_from_typedjson, test).
Called automatically with \$::argv when the tomlish module
file is the main script (tclsh tomlish.tcl ...). Launchers
such as a wrapped tomlish executable's app package must
call this explicitly after package require tomlish - since
the tomlish::system::is_main_script gate (1.1.8) the app
no longer runs as a load-time side effect of ::argc/::argv
being set.
Zeroes the global ::argv/::argc before loading dependent
packages (argument hygiene) and terminates the process via
exit on every path: 0 for success/help, 1 for usage or
application errors."
@leaders
arglist -type list -optional 0 -help\
"command-line argument list (typically \$::argv)"
}]
}
}
proc ::tomlish::cmdline_main {arglist} {
# --------------
#make sure any dependant packages that are sourced don't get any commandline args
set ::argv {}
@ -9476,11 +9659,16 @@ if {[tomlish::system::is_main_script]} {
}
}
if {[tomlish::system::is_main_script]} {
#puts stderr "argc: $::argc args: $::argv"
tomlish::cmdline_main $::argv
}
## Ready
package provide tomlish [namespace eval tomlish {
variable pkg tomlish
variable version
set version 1.1.8
set version 1.1.10
}]
return

1002
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk-0.1.1.tm → src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk-0.2.0.tm

File diff suppressed because it is too large Load Diff

50
src/bootsupport/modules/punk/args-0.2.1.tm → src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/args-0.2.3.tm

@ -8,7 +8,7 @@
# (C) 2024
#
# @@ Meta Begin
# Application punk::args 0.2.1
# Application punk::args 0.2.3
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -18,7 +18,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::args 0 0.2.1]
#[manpage_begin punkshell_module_punk::args 0 0.2.3]
#[copyright "2024"]
#[titledesc {args parsing}] [comment {-- Name section and table of contents description --}]
#[moddesc {args to nested dict of opts and values}] [comment {-- Description at end of page heading --}]
@ -871,19 +871,46 @@ tcl::namespace::eval punk::args {
-choicerestricted <bool>
Whether values not specified in -choices or -choicegroups are
allowed. Defaults to true.
When false, an input that matches no choice - including an
ambiguous prefix, a prefix of a -choiceprefixdenylist entry,
or a -choiceprefixreservelist word - is accepted unchanged as
an ordinary value (subject to -type validation) instead of
raising an error. This passthrough is the pattern for
arguments that mix a known choice set with free-form values
(e.g. a help topic word falling through to command lookup).
-choiceprefix <bool>
This specifies whether unique prefixes are able to be used
instead of the complete string. This is calculated using
tcl::prefix::match - and will display in the autogenerated
usage output. Defaults to true.
A matching prefix is normalized: the parse result contains
the full choice string, never the typed prefix - so callers
switch on canonical choice values only. The usage display
highlights each choice's minimal accepted prefix (a choice
in -choiceprefixdenylist displays fully highlighted - the
whole word is required).
-choiceprefixdenylist {<choices>}
These choices should match exactly a choice entry in one of
the settings -choices or -choicegroups.
These will still be used in prefix calculation - but the full
choice argument must be entered to select the choice.
A shorter prefix of a denied choice is an error when
-choicerestricted is true, and passes through as an ordinary
(non-choice) value when -choicerestricted is false - use this
to keep short words available for other purposes (e.g. with
'help' denied, h/he/hel remain free-form values).
-choiceprefixreservelist {<choices>}
These choices are additional values used in prefix calculation.
The values will not be added to the list of available choices.
A reserved word never matches: entered exactly it is an error
when -choicerestricted is true and passes through when false,
as do any shorter words it shadows into ambiguity. This gives
per-choice control of the minimum accepted prefix by reserving
phantom entries: e.g. -choices {environment}
-choiceprefixreservelist {en} means e/en do not match while
env, envi, ... environment all normalize to environment.
(To require a longer minimum, reserve each shorter form:
reserving {en env} raises the minimum to envi.)
-choicegroups {<dict>}
Generally this would be used instead of -choices to allow
usage display of choices grouped by some name (or the empty
@ -6156,7 +6183,7 @@ tcl::namespace::eval punk::args {
#puts stderr ">>>_get_dict_can_assign_value idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
set d [dict create consumed $alloc_count resultlist $resultlist typelist $newtypelist]
} else {
puts stderr ">>>_get_dict_can_assign_value NOT alloc_ok: idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
#puts stderr ">>>_get_dict_can_assign_value NOT alloc_ok: idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
set d [dict create consumed 0 resultlist {} typelist $thistype]
}
#puts ">>>> _get_dict_can_assign_value $d"
@ -9835,7 +9862,10 @@ tcl::namespace::eval punk::args {
set argname [dict get $lookup_optset $fullflag]
#idents should already have correct parsekey
} else {
puts stderr "punk::args::get_dict unable to find $fullflag in $lookup_optset (parsekey:$parsekey) (value_group: $value_group)"
#adhoc option (allowed via "@opts -any|-arbitrary true") - not in lookup_optset.
#argstate/arg_checks were populated for it under its raw supplied name at scan time.
set argname $fullflag
#puts stderr "punk::args::get_dict unable to find $fullflag in $lookup_optset (parsekey:$parsekey) (value_group: $value_group)"
}
} else {
if {[dict exists $lookup_optset $argname_or_ident]} {
@ -9850,7 +9880,15 @@ tcl::namespace::eval punk::args {
set parsekey [string trimright [lindex [split $argname |] end] =]
}
} else {
puts stderr "punk::args::get_dict unable to find $argname_or_ident in $lookup_optset (value_group: $value_group)"
#adhoc option (allowed via "@opts -any|-arbitrary true") - not in lookup_optset.
#argstate/arg_checks were populated for it under its raw supplied name at scan time.
set argname $argname_or_ident
if {$pkoverride ne ""} {
set parsekey $pkoverride
} else {
set parsekey [string trimright [lindex [split $argname |] end] =]
}
#puts stderr "punk::args::get_dict unable to find $argname_or_ident in $lookup_optset (value_group: $value_group)"
}
}
} else {
@ -12357,7 +12395,7 @@ package provide punk::args [tcl::namespace::eval punk::args {
tcl::namespace::path {::punk::args::lib ::punk::args::system}
variable pkg punk::args
variable version
set version 0.2.1
set version 0.2.3
}]
return

14
src/vfs/_vfscommon.vfs/modules/punk/ns-0.1.0.tm → src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ns-0.1.1.tm

@ -7,7 +7,7 @@
# (C) 2023
#
# @@ Meta Begin
# Application punk::ns 0.1.0
# Application punk::ns 0.1.1
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -4633,7 +4633,7 @@ y" {return quirkykeyscript}
set vline [punk::args::ensemble_subcommands_definition -columns 2 $origin]
set autoid "(autodef)$origin"
puts "ENSEMBLE auto def $autoid (generate_autodef)"
#puts "ENSEMBLE auto def $autoid (generate_autodef)"
#A namespace can contain spaces, so an ensemble command can contain spaces. We must quote the -id value in the autodef
set argdef [punk::lib::tstr -return string {
@id -id "${$autoid}"
@ -4699,7 +4699,7 @@ y" {return quirkykeyscript}
append argdef \n "@formdisplay -body {$tepamhelp}"
punk::args::define $argdef
} else {
puts "PROC auto def $autoid (generate_autodef)"
#puts "PROC auto def $autoid (generate_autodef)"
#to handle procs like ":" (eg used by colin's bytecode based expr replacement) or other names of the form ":xyz"
#we can't use 'info args :::' - tcl won't find it
set ns [nsprefix $origin]
@ -5026,7 +5026,7 @@ y" {return quirkykeyscript}
if {[punk::args::id_exists "$origin [lindex $args $i]"]} {
set a [lindex $args $i]
#review - tests?
puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'"
#puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'"
#we can only seek beyond an undocumented subcommand level via a space delimited path, as we can make no assumption about the actual location of a subcommand relative to its parent
#There could be a different command at for example "${origin}::$a" which is unrelated to the actual resolution path.
set docid_exists 1
@ -5120,7 +5120,7 @@ y" {return quirkykeyscript}
lappend resolvedargs $q
lpop queryargs_untested 0
lappend eparams $q
puts stderr "---> cmd_traverse ensembleparam $q ($lname)"
#puts stderr "---> cmd_traverse ensembleparam $q ($lname)"
#puts stderr "arginfo: $arginfo"
#puts stderr "---> eparams: $eparams"
#puts stderr "---> existing args: $args"
@ -5304,7 +5304,7 @@ y" {return quirkykeyscript}
}
}
#REVIEW!!!
puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
#puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
return [list 10 $origin $resolvedargs $queryargs_untested $docid]
}
@ -7591,6 +7591,6 @@ namespace eval ::punk::args::register {
## Ready
package provide punk::ns [tcl::namespace::eval punk::ns {
variable version
set version 0.1.0
set version 0.1.1
}]
return

10
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/packagepreference-0.1.0.tm → src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/packagepreference-0.1.1.tm

@ -8,7 +8,7 @@
# (C) 2024
#
# @@ Meta Begin
# Application punk::packagepreference 0.1.0
# Application punk::packagepreference 0.1.1
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -18,7 +18,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::packagepreference 0 0.1.0]
#[manpage_begin punkshell_module_punk::packagepreference 0 0.1.1]
#[copyright "2024"]
#[titledesc {punkshell package/module loading}] [comment {-- Name section and table of contents description --}]
#[moddesc {package/module load}] [comment {-- Description at end of page heading --}]
@ -321,7 +321,9 @@ tcl::namespace::eval punk::packagepreference {
if {[catch {thread::id} threadid]} {
set threadid "unknown-threadid"
}
puts stdout "punk::packagepreference overloaded 'package require': Loaded punk::args::moduledoc::$dp for package '$pkg' threadid: $threadid"
#notice goes to stderr: stdout must stay clean for script/exec contexts
#(e.g the punk executable's 'script' subcommand - machine-consumed output)
puts stderr "punk::packagepreference overloaded 'package require': Loaded punk::args::moduledoc::$dp for package '$pkg' threadid: $threadid"
}
}
#---------------------------------------------------------------
@ -487,7 +489,7 @@ namespace eval ::punk::args::register {
package provide punk::packagepreference [tcl::namespace::eval punk::packagepreference {
variable pkg punk::packagepreference
variable version
set version 0.1.0
set version 0.1.1
}]
return

94
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.2.1.tm → src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.2.2.tm

@ -7,7 +7,7 @@
# (C) 2023
#
# @@ Meta Begin
# Application punk::path 0.2.1
# Application punk::path 0.2.2
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -17,7 +17,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::path 0 0.2.1]
#[manpage_begin punkshell_module_punk::path 0 0.2.2]
#[copyright "2023"]
#[titledesc {Filesystem path utilities}] [comment {-- Name section and table of contents description --}]
#[moddesc {punk path filesystem utils}] [comment {-- Description at end of page heading --}]
@ -485,6 +485,87 @@ namespace eval punk::path {
return relative
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::punk::path::scriptlib_resolve
@cmd -name "punk::path::scriptlib_resolve"\
-summary\
"Resolve a scriptlib script name to a path using the punk kit search policy"\
-help\
"Resolves a relative script name (the part after a 'lib:' prefix
in punk executable launch arguments) against the scriptlib
locations, in the same order the punk shell uses:
1. the kit vfs internal scriptlib (<zipfs-root>/app/scriptlib,
or <exedir>/scriptlib for an unwrapped kit directory).
Internal scripts are deliberately NOT overridable by
external files (integrity and performance).
2. <exedir-parent>/scriptlib - e.g <projectroot>/scriptlib for
an executable in <projectroot>/bin.
3. <exedir-grandparent>/scriptlib.
If the name's extension (lowercased) is not one of the known
scriptlib extensions (.tcl .py .pl .ps1 .sh), '.tcl' is
appended - only .tcl scripts may be named extensionlessly.
Returns a dict with keys:
path - resolved absolute path, or empty string if not found
scriptname - the name searched for (extension applied)
candidates - the locations that were (or would be) checked,
for use in error messages.
Raises an error if name is not a relative path."
@leaders
name -type string -optional 0 -help\
"relative script name, with or without a known extension
(any leading lib: prefix should already be stripped)"
}]
}
proc scriptlib_resolve {name} {
#shared resolution policy for the 'lib:' script prefix - used by the punk
#executable 'script' subcommand (app-punkscript); app-punkshell's shell
#subcommand encodes the same policy (todo: refactor it onto this proc).
if {[lindex [pathtype $name] 0] ne "relative"} {
error "punk::path::scriptlib_resolve name must be a relative path (got '$name')"
}
set known_extensions [list .tcl .py .pl .ps1 .sh]
if {[string tolower [file extension $name]] ni $known_extensions} {
#only .tcl scripts allowed to be called extensionlessly
set scriptname $name.tcl
} else {
set scriptname $name
}
set exepath [file dirname [file normalize [file join [info nameofexecutable] ___]]] ;#symlink resolve
set candidates [list]
#1) kit-internal scriptlib - not overridable externally
set has_zipfs_command [expr {[info commands ::tcl::zipfs::root] ne ""}]
set kit_base ""
if {$has_zipfs_command && [file exists [tcl::zipfs::root]]} {
set kit_base [tcl::zipfs::root]
} elseif {[file type $exepath] eq "directory"} {
set kit_base $exepath
}
set kit_libdir ""
if {$has_zipfs_command && $kit_base ne "" && [file exists $kit_base/app/scriptlib]} {
set kit_libdir $kit_base/app/scriptlib
} elseif {[file exists $exepath/scriptlib]} {
set kit_libdir $exepath/scriptlib
}
if {$kit_libdir ne ""} {
lappend candidates $kit_libdir/$scriptname
if {[file exists $kit_libdir/$scriptname]} {
return [dict create path $kit_libdir/$scriptname scriptname $scriptname candidates $candidates]
}
}
#2,3) external scriptlib folders relative to the executable location
set exedir [file dirname $exepath]
foreach dir [list [file join $exedir scriptlib] [file join [file dirname $exedir] scriptlib]] {
lappend candidates [file join $dir $scriptname]
if {[file isdirectory $dir] && [file exists [file join $dir $scriptname]]} {
return [dict create path [file join $dir $scriptname] scriptname $scriptname candidates $candidates]
}
}
return [dict create path "" scriptname $scriptname candidates $candidates]
}
proc plain {str} {
set str [string map "\\\\ /" $str]
@ -1598,12 +1679,19 @@ namespace eval punk::path::system {
}
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
#documentation-only PUNKARGS registration - discovered lazily if/when punk::args loads
lappend ::punk::args::register::NAMESPACES ::punk::path::argdoc
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::path [namespace eval punk::path {
variable pkg punk::path
variable version
set version 0.2.1
set version 0.2.2
}]
return

9
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/shellfilter-0.2.3.tm → src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/shellfilter-0.2.4.tm

@ -2813,8 +2813,11 @@ namespace eval shellfilter {
set syslog [dict get $opts -syslog]
dict unset opts -syslog
set runtag "shellfilter-run"
set tid [::shellfilter::log::open $runtag [list -syslog 127.0.0.1:514]]
#set tid [::shellfilter::log::open $runtag [list -syslog $syslog]]
#honor the -syslog option (default empty) - the previous hardcoded 127.0.0.1:514 was a
#debug leftover. With no -syslog and no -file the runtag log worker is a noop (no thread
#is created). Syslog remains supported when explicitly configured; see G-036 for the
#Tcl 9 console+udp worker wedge that the always-on syslog worker exposed on exit/quit.
set tid [::shellfilter::log::open $runtag [list -syslog $syslog]]
log::info {::shellfilter::log::write $runtag " opts: $opts"}
log::info {::shellfilter::log::write $runtag " commandlist:'$commandlist' listlen:$listlen strlen:[string length $commandlist]"}
@ -3827,5 +3830,5 @@ namespace eval shellfilter {
package provide shellfilter [namespace eval shellfilter {
variable version
set version 0.2.3
set version 0.2.4
}]

20
src/bootsupport/modules/shellthread-1.6.2.tm → src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/shellthread-1.6.3.tm

@ -788,8 +788,12 @@ namespace eval shellthread::manager {
foreach workertid $subscriberless_workers {
if {$workertid ni $shuttingdown_workers} {
if {$workertid ni $free_threads && $workertid ne "noop"} {
#JMN
thread::send $workertid {set ::shellthread::worker::settings $::shellthread::worker::settings_defaults}
#Must be async: unsubscribe is on the exit/quit teardown path and a worker whose
#event loop has stopped servicing events (G-036: Tcl 9 console+udp worker wedge)
#would block a synchronous send forever, freezing the shell. Async is safe -
#sends to a thread are processed FIFO, so a later reuse via new_worker sees the
#settings reset applied before anything it sends.
thread::send -async $workertid {set ::shellthread::worker::settings $::shellthread::worker::settings_defaults}
#todo - log freeing up of thread
lappend free_threads $workertid
}
@ -812,7 +816,10 @@ namespace eval shellthread::manager {
}
proc get_tag_config {tag} {
#review
#review - bare synchronous thread::send: blocks forever if the worker's event loop is
#wedged (G-036 hazard class). Reached from new_worker when a tag already has a live
#worker. Needs a result so can't simply go async - convert to async + vwait-with-timeout
#if this path shows up in a hang.
variable workers
if {![dict exists $workers $tag]} {
error "shellthread::manager::get_tag_config error no existing tag $tag"
@ -858,10 +865,13 @@ namespace eval shellthread::manager {
set timedout 1
break
} else {
after cancel $timeout_timer
#Do not cancel the timeout timer until all awaited workers have responded -
#cancelling on the first response left later vwait iterations unbounded, so a
#wedged worker (G-036) after a healthy one hung shutdown forever.
lappend ended $::shellthread::waitfor
}
}
after cancel $timeout_timer
}
set free_threads [list]
return [dict create existed $waiting_for ended $ended timedout $timedout allthreads [thread::names]]
@ -963,7 +973,7 @@ namespace eval shellthread::manager {
package provide shellthread [namespace eval shellthread {
variable version
set version 1.6.2
set version 1.6.3
}]

200
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/tomlish-1.1.8.tm → src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/tomlish-1.1.10.tm

@ -7,7 +7,7 @@
# (C) 2024
#
# @@ Meta Begin
# Application tomlish 1.1.8
# Application tomlish 1.1.10
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -17,7 +17,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin tomlish_module_tomlish 0 1.1.8]
#[manpage_begin tomlish_module_tomlish 0 1.1.10]
#[copyright "2024"]
#[titledesc {tomlish toml parser}] [comment {-- Name section and table of contents description --}]
#[moddesc {tomlish}] [comment {-- Description at end of page heading --}]
@ -385,6 +385,45 @@ namespace eval tomlish {
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::to_dict
@cmd -name "tomlish::to_dict"\
-summary\
"Convert a tomlish structure to a Tcl dict with typed leaf values"\
-help\
"Converts tomlish (the tagged-list representation produced
by tomlish::from_toml) to a Tcl dict datastructure.
Toml tables map to nested dict keys. Each leaf value is a
two-element dict of the form {type <TYPE> value <value>}
where <TYPE> is a toml/tomlish type such as INT, FLOAT,
BOOL, STRING, LITERAL, MULTISTRING, MULTILITERAL, DATETIME
or ARRAY (an ARRAY value is a list of typed elements).
Escape sequences in quoted strings are substituted during
this conversion.
Whitespace and comments are not represented in the result,
so a dict alone cannot round-trip formatting - use
tomlish::update_tomlish_from_dict to write dict values back
into an existing tomlish structure when preservation
matters.
Toml validity rules that require whole-document knowledge
(e.g 'You cannot define any key or table more than once')
are enforced here and raise errors.
Returns the dict, or with returnextra true a dict with keys
'datastructure' (the converted dict) and 'tablenames_info'
(per-tablename creation/definition metadata)."
@leaders
tomlish -type list -optional 0 -help\
"tomlish tagged list (e.g from tomlish::from_toml)"
returnextra -type boolean -optional 1 -default 0 -help\
"when true, return a dict of keys 'datastructure' and
'tablenames_info' instead of the datastructure alone"
}]
}
proc to_dict {tomlish {returnextra 0}} {
tomlish::dict::from_tomlish $tomlish $returnextra
}
@ -708,6 +747,31 @@ namespace eval tomlish {
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::from_dict
@cmd -name "tomlish::from_dict"\
-summary\
"Convert a dict with typed leaf values to a tomlish structure"\
-help\
"Converts a Tcl dict whose leaf values are typed
({type <TYPE> value <value>} - the form produced by
tomlish::to_dict) into a new tomlish tagged-list structure,
which tomlish::to_toml can serialise to toml text.
The dict must be a full typed representation - plain
untyped leaf values are not accepted. As a dict carries no
whitespace/comment information, the generated tomlish (and
any toml produced from it) uses generated formatting; to
preserve the formatting of an existing document, write
values back with tomlish::update_tomlish_from_dict instead.
Returns the tomlish list."
@leaders
d -type dict -optional 0 -help\
"dict with typed leaf values (e.g from tomlish::to_dict)"
}]
}
proc from_dict {d} {
#consider:
# t1={a=1,b=2}
@ -906,6 +970,33 @@ namespace eval tomlish {
# For this reason, we also do absolutely no line-ending transformations based on platform.
# All line-endings are maintained as is, and even a file with mixed lf crlf line-endings will be correctly interpreted and can be 'roundtripped'
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::from_toml
@cmd -name "tomlish::from_toml"\
-summary\
"Parse toml text into a tomlish tagged-list structure"\
-help\
"Parses toml source text into 'tomlish' - the intermediate
tagged-list representation used by the tomlish package.
tomlish is whitespace and comment preserving: serialising
the result with tomlish::to_toml reproduces the input byte
for byte (lossless round-trip). No escape sequences in
quoted strings are processed at this stage and no
line-ending transformations are performed - that occurs in
datastructure conversions such as tomlish::to_dict.
Returns the tomlish list: first element is the tag TOMLISH,
remaining elements are tagged records such as TABLE,
TABLEARRAY, DOTTEDKEY, WS, COMMENT, NEWLINE.
Raises an error for invalid toml."
@values -min 1 -max -1
toml -type string -optional 0 -multiple 1 -help\
"toml source text. Multiple values are joined with newline
characters before parsing."
}]
}
proc from_toml {args} {
namespace upvar ::tomlish::parse s s
@ -1764,6 +1855,34 @@ namespace eval tomlish {
# updating from a subset dict (reduces processing - and more flexible to supply only paths to leaves requiring update?)
#
#todo - allow adding extra leaves e.g keys in tables,tablearrays, itables, arrays
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::update_tomlish_from_dict
@cmd -name "tomlish::update_tomlish_from_dict"\
-summary\
"Update leaf values in a tomlish structure from a typed dict, preserving formatting"\
-help\
"Merges values from dict d into an existing tomlish
structure and returns the updated tomlish, in which
whitespace, comments and key ordering are preserved.
This is the formatting-preserving write path: parse a
document with tomlish::from_toml, convert with
tomlish::to_dict, modify values in the dict, apply them
with this command, then serialise with tomlish::to_toml.
d must be a full typed representation of the datastructure
(as produced by tomlish::to_dict). The initial
implementation updates leaf values only - adding or pruning
keys/branches is not yet supported."
@leaders
tomlish -type list -optional 0 -help\
"existing tomlish tagged list (e.g from tomlish::from_toml)"
d -type dict -optional 0 -help\
"full typed-dict representation carrying the updated leaf
values"
}]
}
proc update_tomlish_from_dict {tomlish d} {
set returnextra true
#validate supplied tomlish and keep tablenames_info (review - validate structure only - allow invalid values to be overwritten from dict?)
@ -2441,6 +2560,34 @@ namespace eval tomlish::encode {
#fish toml from tomlish
#(encode tomlish as toml)
namespace eval ::tomlish::argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::to_toml
@cmd -name "tomlish::to_toml"\
-summary\
"Serialise a tomlish structure to toml text"\
-help\
"Encodes tomlish (the tagged-list representation produced by
tomlish::from_toml or tomlish::from_dict) as toml text.
For tomlish obtained from tomlish::from_toml this reproduces
the original document byte for byte, including whitespace and
comments (lossless round-trip).
Validation here is structural only - toml validity rules that
need whole-document knowledge (e.g duplicate keys/tables) are
not detected; they are the role of the dict conversion pair
tomlish::to_dict / tomlish::from_dict.
tomlish::to_toml is an alias of tomlish::encode::tomlish.
Returns the toml text."
@leaders
list -type list -optional 0 -help\
"tomlish tagged list"
context -type string -optional 1 -default "" -help\
"internal recursion context tag - omit in normal use"
}]
}
interp alias {} tomlish::to_toml {} tomlish::encode::tomlish
#
@ -9408,12 +9555,48 @@ namespace eval tomlish::system {
#[list_end] [comment {--- end definitions namespace tomlish::system ---}]
}
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
#documentation-only PUNKARGS registration - discovered lazily if/when punk::args is loaded;
#adds no punk::args dependency to the tomlish library itself.
lappend ::punk::args::register::NAMESPACES ::tomlish::argdoc
}
# if {[info exists ::argc] && $::argc > 0} {} ;#not a valid way to test if main script
if {[tomlish::system::is_main_script]} {
#puts stderr "argc: $::argc args: $::argv"
set arglist $::argv
namespace eval tomlish {
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::cmdline_main
@cmd -name "tomlish::cmdline_main"\
-summary\
"Run the tomlish command-line application on an argument list"\
-help\
"Explicit entry point for the tomlish command-line app
(usage display and -app dispatch to the tomlish::app::*
applications such as decode_to_typedjson,
encode_from_typedjson, test).
Called automatically with \$::argv when the tomlish module
file is the main script (tclsh tomlish.tcl ...). Launchers
such as a wrapped tomlish executable's app package must
call this explicitly after package require tomlish - since
the tomlish::system::is_main_script gate (1.1.8) the app
no longer runs as a load-time side effect of ::argc/::argv
being set.
Zeroes the global ::argv/::argc before loading dependent
packages (argument hygiene) and terminates the process via
exit on every path: 0 for success/help, 1 for usage or
application errors."
@leaders
arglist -type list -optional 0 -help\
"command-line argument list (typically \$::argv)"
}]
}
}
proc ::tomlish::cmdline_main {arglist} {
# --------------
#make sure any dependant packages that are sourced don't get any commandline args
set ::argv {}
@ -9476,11 +9659,16 @@ if {[tomlish::system::is_main_script]} {
}
}
if {[tomlish::system::is_main_script]} {
#puts stderr "argc: $::argc args: $::argv"
tomlish::cmdline_main $::argv
}
## Ready
package provide tomlish [namespace eval tomlish {
variable pkg tomlish
variable version
set version 1.1.8
set version 1.1.10
}]
return

1002
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk-0.1.1.tm → src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk-0.2.0.tm

File diff suppressed because it is too large Load Diff

50
src/vfs/_vfscommon.vfs/modules/punk/args-0.2.1.tm → src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/args-0.2.3.tm

@ -8,7 +8,7 @@
# (C) 2024
#
# @@ Meta Begin
# Application punk::args 0.2.1
# Application punk::args 0.2.3
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -18,7 +18,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::args 0 0.2.1]
#[manpage_begin punkshell_module_punk::args 0 0.2.3]
#[copyright "2024"]
#[titledesc {args parsing}] [comment {-- Name section and table of contents description --}]
#[moddesc {args to nested dict of opts and values}] [comment {-- Description at end of page heading --}]
@ -871,19 +871,46 @@ tcl::namespace::eval punk::args {
-choicerestricted <bool>
Whether values not specified in -choices or -choicegroups are
allowed. Defaults to true.
When false, an input that matches no choice - including an
ambiguous prefix, a prefix of a -choiceprefixdenylist entry,
or a -choiceprefixreservelist word - is accepted unchanged as
an ordinary value (subject to -type validation) instead of
raising an error. This passthrough is the pattern for
arguments that mix a known choice set with free-form values
(e.g. a help topic word falling through to command lookup).
-choiceprefix <bool>
This specifies whether unique prefixes are able to be used
instead of the complete string. This is calculated using
tcl::prefix::match - and will display in the autogenerated
usage output. Defaults to true.
A matching prefix is normalized: the parse result contains
the full choice string, never the typed prefix - so callers
switch on canonical choice values only. The usage display
highlights each choice's minimal accepted prefix (a choice
in -choiceprefixdenylist displays fully highlighted - the
whole word is required).
-choiceprefixdenylist {<choices>}
These choices should match exactly a choice entry in one of
the settings -choices or -choicegroups.
These will still be used in prefix calculation - but the full
choice argument must be entered to select the choice.
A shorter prefix of a denied choice is an error when
-choicerestricted is true, and passes through as an ordinary
(non-choice) value when -choicerestricted is false - use this
to keep short words available for other purposes (e.g. with
'help' denied, h/he/hel remain free-form values).
-choiceprefixreservelist {<choices>}
These choices are additional values used in prefix calculation.
The values will not be added to the list of available choices.
A reserved word never matches: entered exactly it is an error
when -choicerestricted is true and passes through when false,
as do any shorter words it shadows into ambiguity. This gives
per-choice control of the minimum accepted prefix by reserving
phantom entries: e.g. -choices {environment}
-choiceprefixreservelist {en} means e/en do not match while
env, envi, ... environment all normalize to environment.
(To require a longer minimum, reserve each shorter form:
reserving {en env} raises the minimum to envi.)
-choicegroups {<dict>}
Generally this would be used instead of -choices to allow
usage display of choices grouped by some name (or the empty
@ -6156,7 +6183,7 @@ tcl::namespace::eval punk::args {
#puts stderr ">>>_get_dict_can_assign_value idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
set d [dict create consumed $alloc_count resultlist $resultlist typelist $newtypelist]
} else {
puts stderr ">>>_get_dict_can_assign_value NOT alloc_ok: idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
#puts stderr ">>>_get_dict_can_assign_value NOT alloc_ok: idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
set d [dict create consumed 0 resultlist {} typelist $thistype]
}
#puts ">>>> _get_dict_can_assign_value $d"
@ -9835,7 +9862,10 @@ tcl::namespace::eval punk::args {
set argname [dict get $lookup_optset $fullflag]
#idents should already have correct parsekey
} else {
puts stderr "punk::args::get_dict unable to find $fullflag in $lookup_optset (parsekey:$parsekey) (value_group: $value_group)"
#adhoc option (allowed via "@opts -any|-arbitrary true") - not in lookup_optset.
#argstate/arg_checks were populated for it under its raw supplied name at scan time.
set argname $fullflag
#puts stderr "punk::args::get_dict unable to find $fullflag in $lookup_optset (parsekey:$parsekey) (value_group: $value_group)"
}
} else {
if {[dict exists $lookup_optset $argname_or_ident]} {
@ -9850,7 +9880,15 @@ tcl::namespace::eval punk::args {
set parsekey [string trimright [lindex [split $argname |] end] =]
}
} else {
puts stderr "punk::args::get_dict unable to find $argname_or_ident in $lookup_optset (value_group: $value_group)"
#adhoc option (allowed via "@opts -any|-arbitrary true") - not in lookup_optset.
#argstate/arg_checks were populated for it under its raw supplied name at scan time.
set argname $argname_or_ident
if {$pkoverride ne ""} {
set parsekey $pkoverride
} else {
set parsekey [string trimright [lindex [split $argname |] end] =]
}
#puts stderr "punk::args::get_dict unable to find $argname_or_ident in $lookup_optset (value_group: $value_group)"
}
}
} else {
@ -12357,7 +12395,7 @@ package provide punk::args [tcl::namespace::eval punk::args {
tcl::namespace::path {::punk::args::lib ::punk::args::system}
variable pkg punk::args
variable version
set version 0.2.1
set version 0.2.3
}]
return

14
src/bootsupport/modules/punk/ns-0.1.0.tm → src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ns-0.1.1.tm

@ -7,7 +7,7 @@
# (C) 2023
#
# @@ Meta Begin
# Application punk::ns 0.1.0
# Application punk::ns 0.1.1
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -4633,7 +4633,7 @@ y" {return quirkykeyscript}
set vline [punk::args::ensemble_subcommands_definition -columns 2 $origin]
set autoid "(autodef)$origin"
puts "ENSEMBLE auto def $autoid (generate_autodef)"
#puts "ENSEMBLE auto def $autoid (generate_autodef)"
#A namespace can contain spaces, so an ensemble command can contain spaces. We must quote the -id value in the autodef
set argdef [punk::lib::tstr -return string {
@id -id "${$autoid}"
@ -4699,7 +4699,7 @@ y" {return quirkykeyscript}
append argdef \n "@formdisplay -body {$tepamhelp}"
punk::args::define $argdef
} else {
puts "PROC auto def $autoid (generate_autodef)"
#puts "PROC auto def $autoid (generate_autodef)"
#to handle procs like ":" (eg used by colin's bytecode based expr replacement) or other names of the form ":xyz"
#we can't use 'info args :::' - tcl won't find it
set ns [nsprefix $origin]
@ -5026,7 +5026,7 @@ y" {return quirkykeyscript}
if {[punk::args::id_exists "$origin [lindex $args $i]"]} {
set a [lindex $args $i]
#review - tests?
puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'"
#puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'"
#we can only seek beyond an undocumented subcommand level via a space delimited path, as we can make no assumption about the actual location of a subcommand relative to its parent
#There could be a different command at for example "${origin}::$a" which is unrelated to the actual resolution path.
set docid_exists 1
@ -5120,7 +5120,7 @@ y" {return quirkykeyscript}
lappend resolvedargs $q
lpop queryargs_untested 0
lappend eparams $q
puts stderr "---> cmd_traverse ensembleparam $q ($lname)"
#puts stderr "---> cmd_traverse ensembleparam $q ($lname)"
#puts stderr "arginfo: $arginfo"
#puts stderr "---> eparams: $eparams"
#puts stderr "---> existing args: $args"
@ -5304,7 +5304,7 @@ y" {return quirkykeyscript}
}
}
#REVIEW!!!
puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
#puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
return [list 10 $origin $resolvedargs $queryargs_untested $docid]
}
@ -7591,6 +7591,6 @@ namespace eval ::punk::args::register {
## Ready
package provide punk::ns [tcl::namespace::eval punk::ns {
variable version
set version 0.1.0
set version 0.1.1
}]
return

10
src/bootsupport/modules/punk/packagepreference-0.1.0.tm → src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/packagepreference-0.1.1.tm

@ -8,7 +8,7 @@
# (C) 2024
#
# @@ Meta Begin
# Application punk::packagepreference 0.1.0
# Application punk::packagepreference 0.1.1
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -18,7 +18,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::packagepreference 0 0.1.0]
#[manpage_begin punkshell_module_punk::packagepreference 0 0.1.1]
#[copyright "2024"]
#[titledesc {punkshell package/module loading}] [comment {-- Name section and table of contents description --}]
#[moddesc {package/module load}] [comment {-- Description at end of page heading --}]
@ -321,7 +321,9 @@ tcl::namespace::eval punk::packagepreference {
if {[catch {thread::id} threadid]} {
set threadid "unknown-threadid"
}
puts stdout "punk::packagepreference overloaded 'package require': Loaded punk::args::moduledoc::$dp for package '$pkg' threadid: $threadid"
#notice goes to stderr: stdout must stay clean for script/exec contexts
#(e.g the punk executable's 'script' subcommand - machine-consumed output)
puts stderr "punk::packagepreference overloaded 'package require': Loaded punk::args::moduledoc::$dp for package '$pkg' threadid: $threadid"
}
}
#---------------------------------------------------------------
@ -487,7 +489,7 @@ namespace eval ::punk::args::register {
package provide punk::packagepreference [tcl::namespace::eval punk::packagepreference {
variable pkg punk::packagepreference
variable version
set version 0.1.0
set version 0.1.1
}]
return

94
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.2.1.tm → src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.2.2.tm

@ -7,7 +7,7 @@
# (C) 2023
#
# @@ Meta Begin
# Application punk::path 0.2.1
# Application punk::path 0.2.2
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -17,7 +17,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::path 0 0.2.1]
#[manpage_begin punkshell_module_punk::path 0 0.2.2]
#[copyright "2023"]
#[titledesc {Filesystem path utilities}] [comment {-- Name section and table of contents description --}]
#[moddesc {punk path filesystem utils}] [comment {-- Description at end of page heading --}]
@ -485,6 +485,87 @@ namespace eval punk::path {
return relative
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::punk::path::scriptlib_resolve
@cmd -name "punk::path::scriptlib_resolve"\
-summary\
"Resolve a scriptlib script name to a path using the punk kit search policy"\
-help\
"Resolves a relative script name (the part after a 'lib:' prefix
in punk executable launch arguments) against the scriptlib
locations, in the same order the punk shell uses:
1. the kit vfs internal scriptlib (<zipfs-root>/app/scriptlib,
or <exedir>/scriptlib for an unwrapped kit directory).
Internal scripts are deliberately NOT overridable by
external files (integrity and performance).
2. <exedir-parent>/scriptlib - e.g <projectroot>/scriptlib for
an executable in <projectroot>/bin.
3. <exedir-grandparent>/scriptlib.
If the name's extension (lowercased) is not one of the known
scriptlib extensions (.tcl .py .pl .ps1 .sh), '.tcl' is
appended - only .tcl scripts may be named extensionlessly.
Returns a dict with keys:
path - resolved absolute path, or empty string if not found
scriptname - the name searched for (extension applied)
candidates - the locations that were (or would be) checked,
for use in error messages.
Raises an error if name is not a relative path."
@leaders
name -type string -optional 0 -help\
"relative script name, with or without a known extension
(any leading lib: prefix should already be stripped)"
}]
}
proc scriptlib_resolve {name} {
#shared resolution policy for the 'lib:' script prefix - used by the punk
#executable 'script' subcommand (app-punkscript); app-punkshell's shell
#subcommand encodes the same policy (todo: refactor it onto this proc).
if {[lindex [pathtype $name] 0] ne "relative"} {
error "punk::path::scriptlib_resolve name must be a relative path (got '$name')"
}
set known_extensions [list .tcl .py .pl .ps1 .sh]
if {[string tolower [file extension $name]] ni $known_extensions} {
#only .tcl scripts allowed to be called extensionlessly
set scriptname $name.tcl
} else {
set scriptname $name
}
set exepath [file dirname [file normalize [file join [info nameofexecutable] ___]]] ;#symlink resolve
set candidates [list]
#1) kit-internal scriptlib - not overridable externally
set has_zipfs_command [expr {[info commands ::tcl::zipfs::root] ne ""}]
set kit_base ""
if {$has_zipfs_command && [file exists [tcl::zipfs::root]]} {
set kit_base [tcl::zipfs::root]
} elseif {[file type $exepath] eq "directory"} {
set kit_base $exepath
}
set kit_libdir ""
if {$has_zipfs_command && $kit_base ne "" && [file exists $kit_base/app/scriptlib]} {
set kit_libdir $kit_base/app/scriptlib
} elseif {[file exists $exepath/scriptlib]} {
set kit_libdir $exepath/scriptlib
}
if {$kit_libdir ne ""} {
lappend candidates $kit_libdir/$scriptname
if {[file exists $kit_libdir/$scriptname]} {
return [dict create path $kit_libdir/$scriptname scriptname $scriptname candidates $candidates]
}
}
#2,3) external scriptlib folders relative to the executable location
set exedir [file dirname $exepath]
foreach dir [list [file join $exedir scriptlib] [file join [file dirname $exedir] scriptlib]] {
lappend candidates [file join $dir $scriptname]
if {[file isdirectory $dir] && [file exists [file join $dir $scriptname]]} {
return [dict create path [file join $dir $scriptname] scriptname $scriptname candidates $candidates]
}
}
return [dict create path "" scriptname $scriptname candidates $candidates]
}
proc plain {str} {
set str [string map "\\\\ /" $str]
@ -1598,12 +1679,19 @@ namespace eval punk::path::system {
}
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
#documentation-only PUNKARGS registration - discovered lazily if/when punk::args loads
lappend ::punk::args::register::NAMESPACES ::punk::path::argdoc
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
package provide punk::path [namespace eval punk::path {
variable pkg punk::path
variable version
set version 0.2.1
set version 0.2.2
}]
return

9
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/shellfilter-0.2.3.tm → src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/shellfilter-0.2.4.tm

@ -2813,8 +2813,11 @@ namespace eval shellfilter {
set syslog [dict get $opts -syslog]
dict unset opts -syslog
set runtag "shellfilter-run"
set tid [::shellfilter::log::open $runtag [list -syslog 127.0.0.1:514]]
#set tid [::shellfilter::log::open $runtag [list -syslog $syslog]]
#honor the -syslog option (default empty) - the previous hardcoded 127.0.0.1:514 was a
#debug leftover. With no -syslog and no -file the runtag log worker is a noop (no thread
#is created). Syslog remains supported when explicitly configured; see G-036 for the
#Tcl 9 console+udp worker wedge that the always-on syslog worker exposed on exit/quit.
set tid [::shellfilter::log::open $runtag [list -syslog $syslog]]
log::info {::shellfilter::log::write $runtag " opts: $opts"}
log::info {::shellfilter::log::write $runtag " commandlist:'$commandlist' listlen:$listlen strlen:[string length $commandlist]"}
@ -3827,5 +3830,5 @@ namespace eval shellfilter {
package provide shellfilter [namespace eval shellfilter {
variable version
set version 0.2.3
set version 0.2.4
}]

20
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/shellthread-1.6.2.tm → src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/shellthread-1.6.3.tm

@ -788,8 +788,12 @@ namespace eval shellthread::manager {
foreach workertid $subscriberless_workers {
if {$workertid ni $shuttingdown_workers} {
if {$workertid ni $free_threads && $workertid ne "noop"} {
#JMN
thread::send $workertid {set ::shellthread::worker::settings $::shellthread::worker::settings_defaults}
#Must be async: unsubscribe is on the exit/quit teardown path and a worker whose
#event loop has stopped servicing events (G-036: Tcl 9 console+udp worker wedge)
#would block a synchronous send forever, freezing the shell. Async is safe -
#sends to a thread are processed FIFO, so a later reuse via new_worker sees the
#settings reset applied before anything it sends.
thread::send -async $workertid {set ::shellthread::worker::settings $::shellthread::worker::settings_defaults}
#todo - log freeing up of thread
lappend free_threads $workertid
}
@ -812,7 +816,10 @@ namespace eval shellthread::manager {
}
proc get_tag_config {tag} {
#review
#review - bare synchronous thread::send: blocks forever if the worker's event loop is
#wedged (G-036 hazard class). Reached from new_worker when a tag already has a live
#worker. Needs a result so can't simply go async - convert to async + vwait-with-timeout
#if this path shows up in a hang.
variable workers
if {![dict exists $workers $tag]} {
error "shellthread::manager::get_tag_config error no existing tag $tag"
@ -858,10 +865,13 @@ namespace eval shellthread::manager {
set timedout 1
break
} else {
after cancel $timeout_timer
#Do not cancel the timeout timer until all awaited workers have responded -
#cancelling on the first response left later vwait iterations unbounded, so a
#wedged worker (G-036) after a healthy one hung shutdown forever.
lappend ended $::shellthread::waitfor
}
}
after cancel $timeout_timer
}
set free_threads [list]
return [dict create existed $waiting_for ended $ended timedout $timedout allthreads [thread::names]]
@ -963,7 +973,7 @@ namespace eval shellthread::manager {
package provide shellthread [namespace eval shellthread {
variable version
set version 1.6.2
set version 1.6.3
}]

200
src/bootsupport/modules/tomlish-1.1.8.tm → src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/tomlish-1.1.10.tm

@ -7,7 +7,7 @@
# (C) 2024
#
# @@ Meta Begin
# Application tomlish 1.1.8
# Application tomlish 1.1.10
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -17,7 +17,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin tomlish_module_tomlish 0 1.1.8]
#[manpage_begin tomlish_module_tomlish 0 1.1.10]
#[copyright "2024"]
#[titledesc {tomlish toml parser}] [comment {-- Name section and table of contents description --}]
#[moddesc {tomlish}] [comment {-- Description at end of page heading --}]
@ -385,6 +385,45 @@ namespace eval tomlish {
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::to_dict
@cmd -name "tomlish::to_dict"\
-summary\
"Convert a tomlish structure to a Tcl dict with typed leaf values"\
-help\
"Converts tomlish (the tagged-list representation produced
by tomlish::from_toml) to a Tcl dict datastructure.
Toml tables map to nested dict keys. Each leaf value is a
two-element dict of the form {type <TYPE> value <value>}
where <TYPE> is a toml/tomlish type such as INT, FLOAT,
BOOL, STRING, LITERAL, MULTISTRING, MULTILITERAL, DATETIME
or ARRAY (an ARRAY value is a list of typed elements).
Escape sequences in quoted strings are substituted during
this conversion.
Whitespace and comments are not represented in the result,
so a dict alone cannot round-trip formatting - use
tomlish::update_tomlish_from_dict to write dict values back
into an existing tomlish structure when preservation
matters.
Toml validity rules that require whole-document knowledge
(e.g 'You cannot define any key or table more than once')
are enforced here and raise errors.
Returns the dict, or with returnextra true a dict with keys
'datastructure' (the converted dict) and 'tablenames_info'
(per-tablename creation/definition metadata)."
@leaders
tomlish -type list -optional 0 -help\
"tomlish tagged list (e.g from tomlish::from_toml)"
returnextra -type boolean -optional 1 -default 0 -help\
"when true, return a dict of keys 'datastructure' and
'tablenames_info' instead of the datastructure alone"
}]
}
proc to_dict {tomlish {returnextra 0}} {
tomlish::dict::from_tomlish $tomlish $returnextra
}
@ -708,6 +747,31 @@ namespace eval tomlish {
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::from_dict
@cmd -name "tomlish::from_dict"\
-summary\
"Convert a dict with typed leaf values to a tomlish structure"\
-help\
"Converts a Tcl dict whose leaf values are typed
({type <TYPE> value <value>} - the form produced by
tomlish::to_dict) into a new tomlish tagged-list structure,
which tomlish::to_toml can serialise to toml text.
The dict must be a full typed representation - plain
untyped leaf values are not accepted. As a dict carries no
whitespace/comment information, the generated tomlish (and
any toml produced from it) uses generated formatting; to
preserve the formatting of an existing document, write
values back with tomlish::update_tomlish_from_dict instead.
Returns the tomlish list."
@leaders
d -type dict -optional 0 -help\
"dict with typed leaf values (e.g from tomlish::to_dict)"
}]
}
proc from_dict {d} {
#consider:
# t1={a=1,b=2}
@ -906,6 +970,33 @@ namespace eval tomlish {
# For this reason, we also do absolutely no line-ending transformations based on platform.
# All line-endings are maintained as is, and even a file with mixed lf crlf line-endings will be correctly interpreted and can be 'roundtripped'
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::from_toml
@cmd -name "tomlish::from_toml"\
-summary\
"Parse toml text into a tomlish tagged-list structure"\
-help\
"Parses toml source text into 'tomlish' - the intermediate
tagged-list representation used by the tomlish package.
tomlish is whitespace and comment preserving: serialising
the result with tomlish::to_toml reproduces the input byte
for byte (lossless round-trip). No escape sequences in
quoted strings are processed at this stage and no
line-ending transformations are performed - that occurs in
datastructure conversions such as tomlish::to_dict.
Returns the tomlish list: first element is the tag TOMLISH,
remaining elements are tagged records such as TABLE,
TABLEARRAY, DOTTEDKEY, WS, COMMENT, NEWLINE.
Raises an error for invalid toml."
@values -min 1 -max -1
toml -type string -optional 0 -multiple 1 -help\
"toml source text. Multiple values are joined with newline
characters before parsing."
}]
}
proc from_toml {args} {
namespace upvar ::tomlish::parse s s
@ -1764,6 +1855,34 @@ namespace eval tomlish {
# updating from a subset dict (reduces processing - and more flexible to supply only paths to leaves requiring update?)
#
#todo - allow adding extra leaves e.g keys in tables,tablearrays, itables, arrays
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::update_tomlish_from_dict
@cmd -name "tomlish::update_tomlish_from_dict"\
-summary\
"Update leaf values in a tomlish structure from a typed dict, preserving formatting"\
-help\
"Merges values from dict d into an existing tomlish
structure and returns the updated tomlish, in which
whitespace, comments and key ordering are preserved.
This is the formatting-preserving write path: parse a
document with tomlish::from_toml, convert with
tomlish::to_dict, modify values in the dict, apply them
with this command, then serialise with tomlish::to_toml.
d must be a full typed representation of the datastructure
(as produced by tomlish::to_dict). The initial
implementation updates leaf values only - adding or pruning
keys/branches is not yet supported."
@leaders
tomlish -type list -optional 0 -help\
"existing tomlish tagged list (e.g from tomlish::from_toml)"
d -type dict -optional 0 -help\
"full typed-dict representation carrying the updated leaf
values"
}]
}
proc update_tomlish_from_dict {tomlish d} {
set returnextra true
#validate supplied tomlish and keep tablenames_info (review - validate structure only - allow invalid values to be overwritten from dict?)
@ -2441,6 +2560,34 @@ namespace eval tomlish::encode {
#fish toml from tomlish
#(encode tomlish as toml)
namespace eval ::tomlish::argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::to_toml
@cmd -name "tomlish::to_toml"\
-summary\
"Serialise a tomlish structure to toml text"\
-help\
"Encodes tomlish (the tagged-list representation produced by
tomlish::from_toml or tomlish::from_dict) as toml text.
For tomlish obtained from tomlish::from_toml this reproduces
the original document byte for byte, including whitespace and
comments (lossless round-trip).
Validation here is structural only - toml validity rules that
need whole-document knowledge (e.g duplicate keys/tables) are
not detected; they are the role of the dict conversion pair
tomlish::to_dict / tomlish::from_dict.
tomlish::to_toml is an alias of tomlish::encode::tomlish.
Returns the toml text."
@leaders
list -type list -optional 0 -help\
"tomlish tagged list"
context -type string -optional 1 -default "" -help\
"internal recursion context tag - omit in normal use"
}]
}
interp alias {} tomlish::to_toml {} tomlish::encode::tomlish
#
@ -9408,12 +9555,48 @@ namespace eval tomlish::system {
#[list_end] [comment {--- end definitions namespace tomlish::system ---}]
}
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
#documentation-only PUNKARGS registration - discovered lazily if/when punk::args is loaded;
#adds no punk::args dependency to the tomlish library itself.
lappend ::punk::args::register::NAMESPACES ::tomlish::argdoc
}
# if {[info exists ::argc] && $::argc > 0} {} ;#not a valid way to test if main script
if {[tomlish::system::is_main_script]} {
#puts stderr "argc: $::argc args: $::argv"
set arglist $::argv
namespace eval tomlish {
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::tomlish::cmdline_main
@cmd -name "tomlish::cmdline_main"\
-summary\
"Run the tomlish command-line application on an argument list"\
-help\
"Explicit entry point for the tomlish command-line app
(usage display and -app dispatch to the tomlish::app::*
applications such as decode_to_typedjson,
encode_from_typedjson, test).
Called automatically with \$::argv when the tomlish module
file is the main script (tclsh tomlish.tcl ...). Launchers
such as a wrapped tomlish executable's app package must
call this explicitly after package require tomlish - since
the tomlish::system::is_main_script gate (1.1.8) the app
no longer runs as a load-time side effect of ::argc/::argv
being set.
Zeroes the global ::argv/::argc before loading dependent
packages (argument hygiene) and terminates the process via
exit on every path: 0 for success/help, 1 for usage or
application errors."
@leaders
arglist -type list -optional 0 -help\
"command-line argument list (typically \$::argv)"
}]
}
}
proc ::tomlish::cmdline_main {arglist} {
# --------------
#make sure any dependant packages that are sourced don't get any commandline args
set ::argv {}
@ -9476,11 +9659,16 @@ if {[tomlish::system::is_main_script]} {
}
}
if {[tomlish::system::is_main_script]} {
#puts stderr "argc: $::argc args: $::argv"
tomlish::cmdline_main $::argv
}
## Ready
package provide tomlish [namespace eval tomlish {
variable pkg tomlish
variable version
set version 1.1.8
set version 1.1.10
}]
return

1002
src/vfs/_vfscommon.vfs/modules/punk-0.1.1.tm → src/vfs/_vfscommon.vfs/modules/punk-0.2.0.tm

File diff suppressed because it is too large Load Diff

50
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/args-0.2.1.tm → src/vfs/_vfscommon.vfs/modules/punk/args-0.2.3.tm

@ -8,7 +8,7 @@
# (C) 2024
#
# @@ Meta Begin
# Application punk::args 0.2.1
# Application punk::args 0.2.3
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -18,7 +18,7 @@
# doctools header
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#*** !doctools
#[manpage_begin punkshell_module_punk::args 0 0.2.1]
#[manpage_begin punkshell_module_punk::args 0 0.2.3]
#[copyright "2024"]
#[titledesc {args parsing}] [comment {-- Name section and table of contents description --}]
#[moddesc {args to nested dict of opts and values}] [comment {-- Description at end of page heading --}]
@ -871,19 +871,46 @@ tcl::namespace::eval punk::args {
-choicerestricted <bool>
Whether values not specified in -choices or -choicegroups are
allowed. Defaults to true.
When false, an input that matches no choice - including an
ambiguous prefix, a prefix of a -choiceprefixdenylist entry,
or a -choiceprefixreservelist word - is accepted unchanged as
an ordinary value (subject to -type validation) instead of
raising an error. This passthrough is the pattern for
arguments that mix a known choice set with free-form values
(e.g. a help topic word falling through to command lookup).
-choiceprefix <bool>
This specifies whether unique prefixes are able to be used
instead of the complete string. This is calculated using
tcl::prefix::match - and will display in the autogenerated
usage output. Defaults to true.
A matching prefix is normalized: the parse result contains
the full choice string, never the typed prefix - so callers
switch on canonical choice values only. The usage display
highlights each choice's minimal accepted prefix (a choice
in -choiceprefixdenylist displays fully highlighted - the
whole word is required).
-choiceprefixdenylist {<choices>}
These choices should match exactly a choice entry in one of
the settings -choices or -choicegroups.
These will still be used in prefix calculation - but the full
choice argument must be entered to select the choice.
A shorter prefix of a denied choice is an error when
-choicerestricted is true, and passes through as an ordinary
(non-choice) value when -choicerestricted is false - use this
to keep short words available for other purposes (e.g. with
'help' denied, h/he/hel remain free-form values).
-choiceprefixreservelist {<choices>}
These choices are additional values used in prefix calculation.
The values will not be added to the list of available choices.
A reserved word never matches: entered exactly it is an error
when -choicerestricted is true and passes through when false,
as do any shorter words it shadows into ambiguity. This gives
per-choice control of the minimum accepted prefix by reserving
phantom entries: e.g. -choices {environment}
-choiceprefixreservelist {en} means e/en do not match while
env, envi, ... environment all normalize to environment.
(To require a longer minimum, reserve each shorter form:
reserving {en env} raises the minimum to envi.)
-choicegroups {<dict>}
Generally this would be used instead of -choices to allow
usage display of choices grouped by some name (or the empty
@ -6156,7 +6183,7 @@ tcl::namespace::eval punk::args {
#puts stderr ">>>_get_dict_can_assign_value idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
set d [dict create consumed $alloc_count resultlist $resultlist typelist $newtypelist]
} else {
puts stderr ">>>_get_dict_can_assign_value NOT alloc_ok: idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
#puts stderr ">>>_get_dict_can_assign_value NOT alloc_ok: idx:$idx v:[lindex $values $idx] consumed:$alloc_count thistype:$thistype"
set d [dict create consumed 0 resultlist {} typelist $thistype]
}
#puts ">>>> _get_dict_can_assign_value $d"
@ -9835,7 +9862,10 @@ tcl::namespace::eval punk::args {
set argname [dict get $lookup_optset $fullflag]
#idents should already have correct parsekey
} else {
puts stderr "punk::args::get_dict unable to find $fullflag in $lookup_optset (parsekey:$parsekey) (value_group: $value_group)"
#adhoc option (allowed via "@opts -any|-arbitrary true") - not in lookup_optset.
#argstate/arg_checks were populated for it under its raw supplied name at scan time.
set argname $fullflag
#puts stderr "punk::args::get_dict unable to find $fullflag in $lookup_optset (parsekey:$parsekey) (value_group: $value_group)"
}
} else {
if {[dict exists $lookup_optset $argname_or_ident]} {
@ -9850,7 +9880,15 @@ tcl::namespace::eval punk::args {
set parsekey [string trimright [lindex [split $argname |] end] =]
}
} else {
puts stderr "punk::args::get_dict unable to find $argname_or_ident in $lookup_optset (value_group: $value_group)"
#adhoc option (allowed via "@opts -any|-arbitrary true") - not in lookup_optset.
#argstate/arg_checks were populated for it under its raw supplied name at scan time.
set argname $argname_or_ident
if {$pkoverride ne ""} {
set parsekey $pkoverride
} else {
set parsekey [string trimright [lindex [split $argname |] end] =]
}
#puts stderr "punk::args::get_dict unable to find $argname_or_ident in $lookup_optset (value_group: $value_group)"
}
}
} else {
@ -12357,7 +12395,7 @@ package provide punk::args [tcl::namespace::eval punk::args {
tcl::namespace::path {::punk::args::lib ::punk::args::system}
variable pkg punk::args
variable version
set version 0.2.1
set version 0.2.3
}]
return

14
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ns-0.1.0.tm → src/vfs/_vfscommon.vfs/modules/punk/ns-0.1.1.tm

@ -7,7 +7,7 @@
# (C) 2023
#
# @@ Meta Begin
# Application punk::ns 0.1.0
# Application punk::ns 0.1.1
# Meta platform tcl
# Meta license <unspecified>
# @@ Meta End
@ -4633,7 +4633,7 @@ y" {return quirkykeyscript}
set vline [punk::args::ensemble_subcommands_definition -columns 2 $origin]
set autoid "(autodef)$origin"
puts "ENSEMBLE auto def $autoid (generate_autodef)"
#puts "ENSEMBLE auto def $autoid (generate_autodef)"
#A namespace can contain spaces, so an ensemble command can contain spaces. We must quote the -id value in the autodef
set argdef [punk::lib::tstr -return string {
@id -id "${$autoid}"
@ -4699,7 +4699,7 @@ y" {return quirkykeyscript}
append argdef \n "@formdisplay -body {$tepamhelp}"
punk::args::define $argdef
} else {
puts "PROC auto def $autoid (generate_autodef)"
#puts "PROC auto def $autoid (generate_autodef)"
#to handle procs like ":" (eg used by colin's bytecode based expr replacement) or other names of the form ":xyz"
#we can't use 'info args :::' - tcl won't find it
set ns [nsprefix $origin]
@ -5026,7 +5026,7 @@ y" {return quirkykeyscript}
if {[punk::args::id_exists "$origin [lindex $args $i]"]} {
set a [lindex $args $i]
#review - tests?
puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'"
#puts stderr "cmd_traverse - skipping to documented subcommand '$origin $a'"
#we can only seek beyond an undocumented subcommand level via a space delimited path, as we can make no assumption about the actual location of a subcommand relative to its parent
#There could be a different command at for example "${origin}::$a" which is unrelated to the actual resolution path.
set docid_exists 1
@ -5120,7 +5120,7 @@ y" {return quirkykeyscript}
lappend resolvedargs $q
lpop queryargs_untested 0
lappend eparams $q
puts stderr "---> cmd_traverse ensembleparam $q ($lname)"
#puts stderr "---> cmd_traverse ensembleparam $q ($lname)"
#puts stderr "arginfo: $arginfo"
#puts stderr "---> eparams: $eparams"
#puts stderr "---> existing args: $args"
@ -5304,7 +5304,7 @@ y" {return quirkykeyscript}
}
}
#REVIEW!!!
puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
#puts stderr "cmd_traverse 10 $origin $resolvedargs $queryargs_untested $docid - review"
return [list 10 $origin $resolvedargs $queryargs_untested $docid]
}
@ -7591,6 +7591,6 @@ namespace eval ::punk::args::register {
## Ready
package provide punk::ns [tcl::namespace::eval punk::ns {
variable version
set version 0.1.0
set version 0.1.1
}]
return
Loading…
Cancel
Save