Browse Source

vendor tomlish 1.1.10 (G-014 argdoc precondition met); vfscommon refresh

vendorupdate pulls tomlish 1.1.10 from a clean tomlish checkout: the
library API punk::config will consume now carries punk::args (PUNKARGS)
documentation - from_toml, to_dict, from_dict, to_toml,
update_tomlish_from_dict - completing the G-014 precondition
(documentation added upstream in the tomlish project, landed here by
re-vendoring, never by editing src/vendormodules copies). 1.1.10 also
carries the explicit tomlish::cmdline_main entry point (wrapped-exe
startup fix; the load-time argv side effect is gone).

vfscommonupdate refreshes the punkshell kit payload to the current built
modules: shellfilter 0.2.3 (channel-restoration try/finally), shellrun
0.1.4, punkboot::utils 0.1.1, punk::console 0.7.1 content catch-up, and
tomlish 1.1.10.

Project version 0.2.7.

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 2 weeks ago
parent
commit
b1fc3929dc
  1. 5
      CHANGELOG.md
  2. 2
      punkproject.toml
  3. 9677
      src/vendormodules/tomlish-1.1.10.tm
  4. 27
      src/vfs/_vfscommon.vfs/modules/punk/console-0.7.1.tm
  5. 214
      src/vfs/_vfscommon.vfs/modules/punkboot/utils-0.1.1.tm
  6. 42
      src/vfs/_vfscommon.vfs/modules/shellfilter-0.2.3.tm
  7. 421
      src/vfs/_vfscommon.vfs/modules/shellrun-0.1.4.tm
  8. 9677
      src/vfs/_vfscommon.vfs/modules/tomlish-1.1.10.tm

5
CHANGELOG.md

@ -5,6 +5,11 @@ The latest `## [X.Y.Z]` header must match the `version` field in `punkproject.to
Entries are newest-first; one bullet per notable change. See the root `AGENTS.md`
"Project Versioning" section for the bump policy.
## [0.2.7] - 2026-07-07
- vendored tomlish 1.1.10: the library API now carries punk::args (PUNKARGS) documentation (from_toml, to_dict, from_dict, to_toml, update_tomlish_from_dict) — the G-014 tomlish precondition is met (documented upstream, re-vendored from a clean checkout); plus the explicit `tomlish::cmdline_main` entry point.
- `_vfscommon.vfs` kit payload refreshed to the current built modules: shellfilter 0.2.3, shellrun 0.1.4, punkboot::utils 0.1.1, punk::console 0.7.1 content catch-up, tomlish 1.1.10.
## [0.2.6] - 2026-07-06
- shellfilter 0.2.3: `shellfilter::run` now guarantees tee-stack removal (stdout/stderr restoration) via try/finally even when its body errors, and the decorative stack-status table rendering in `log::critical` blocks is catch-guarded. Previously an error there (observed: a stale same-version textblock snapshot calling the new punk::ansi `sgr_merge_singles` with old option syntax) aborted the run between channel diversion and restoration, leaving the process's stdout/stderr broken and all subsequent output silently lost.

2
punkproject.toml

@ -1,3 +1,3 @@
[project]
name = "punkshell"
version = "0.2.6"
version = "0.2.7"

9677
src/vendormodules/tomlish-1.1.10.tm

File diff suppressed because it is too large Load Diff

27
src/vfs/_vfscommon.vfs/modules/punk/console-0.7.1.tm

@ -581,7 +581,10 @@ namespace eval punk::console {
try {
return [thread::send $route_owner [list ::punk::console::internal::get_ansi_response_payload -console $inoutchannels -expected_ms $expected -ignoreok $ignoreok -return $returntype -passthrough $passthrough $query $capturingendregex]]
} on error {errM erropts} {
return -code error "get_ansi_response_payload query routed to console-owning thread $route_owner failed: $errM"
#preserve the owner-side errorcode (where the transport propagates it) so
#callers can discriminate, e.g. {PUNK CONSOLE QUERY HOSTAGE_COOKED_READ}
#from the idle-reader guard
return -code error -errorcode [dict get $erropts -errorcode] "get_ansi_response_payload query routed to console-owning thread $route_owner failed: $errM"
}
}
@ -611,6 +614,28 @@ namespace eval punk::console {
error "punk::console::get_ansi_response_payload input channel '$input' is closed or at eof - cannot receive terminal response"
}
#tcl 8.6 windows console idle-reader hostage guard (fail fast, no emission).
#With the console in cooked (line) mode and a readable handler armed on the input
#channel, the 8.6 channel driver has a blocking cooked-mode ReadConsole parked
#(arming is what posts it), and driver reads sample the console mode at issue time -
#the raw cycle below cannot rescue it. Any response would be swallowed by that read
#until the user presses Enter, then leak to the line reader as phantom input
#(~500ms timeout now, input corruption later). This is the idle-at-a-line-mode-prompt
#condition: the repl disarms its reader during command dispatch, so mid-command
#queries are unaffected, and raw mode reads cooperatively and is exempt. Typical
#trigger: a query from an after-script or worker thread firing while the shell sits
#at a line-mode prompt. Best-effort by design: a parked read can outlive a removed
#handler, so this catches the systematic case, not every conceivable one.
if {![tsv::get punk_console is_raw] && $input eq "stdin" && $::punk::console::has_twapi} {
set guard_conf [chan configure $input]
if {![dict exists $guard_conf -inputmode] && ![dict exists $guard_conf -mode]
&& [chan event $input readable] ne ""
&& ![catch {twapi::get_console_handle stdin}]} {
return -code error -errorcode [list PUNK CONSOLE QUERY HOSTAGE_COOKED_READ]\
"punk::console::get_ansi_response_payload refusing to emit query on '$input': tcl 8.6 console is in cooked (line) mode with an armed readable handler - the driver's parked cooked read would swallow the response until Enter (query issued from an idle line-mode prompt?). Use raw mode, or issue queries while the reader is disarmed (e.g. during repl command evaluation)."
}
}
#chunks from input that need to be handled by readers
upvar ::punk::console::input_chunks_waiting input_chunks_waiting

214
src/vfs/_vfscommon.vfs/modules/punkboot/utils-0.1.1.tm

@ -0,0 +1,214 @@
# -*- tcl -*-
# Maintenance Instruction: leave the 999999.xxx.x as is and use 'pmix make' or src/make.tcl to update from <pkg>-buildversion.txt
#
# Please consider using a BSD or MIT style license for greatest compatibility with the Tcl ecosystem.
# Code using preferred Tcl licenses can be eligible for inclusion in Tcllib, Tklib and the punk package repository.
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# (C) 2023
#
# @@ Meta Begin
# Application punkboot::utils 0.1.1
# Meta platform tcl
# Meta license BSD
# @@ Meta End
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Requirements
##e.g package require frobz
package require Tcl 8.6-
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval punkboot::utils {
variable version 0.1.0
namespace export parse_punkproject_version read_punkproject_version read_changelog_latest_version vcs_dirty_warnings
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::punkboot::utils::parse_punkproject_version
@cmd -name "::punkboot::utils::parse_punkproject_version"\
-summary\
"Parse the [project] version from TOML content string"\
-help\
"Scans TOML content for the [project] section and returns
the value of the version key as a string. Returns an empty
string if the section or key is not found."
@leaders
content -type string -optional 0 -help\
"TOML content string to parse"
}]
}
proc parse_punkproject_version {content} {
set in_project 0
foreach line [split $content \n] {
set trimmed [string trim $line]
if {[string index $trimmed 0] eq {[} && [string index $trimmed end] eq {]}} {
set in_project [expr {$trimmed eq "\[project\]"}]
continue
}
if {$in_project && [regexp {^version\s*=\s*"([^"]+)"} $trimmed _ v]} {
return $v
}
}
return ""
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::punkboot::utils::read_punkproject_version
@cmd -name "::punkboot::utils::read_punkproject_version"\
-summary\
"Read the [project] version from a TOML file"\
-help\
"Reads the file at tomlfile and returns the [project]
version value as a string. Returns an empty string if the
file does not exist or the version is not found."
@leaders
tomlfile -type string -optional 0 -help\
"Path to the TOML file to read"
}]
}
proc read_punkproject_version {tomlfile} {
if {![file exists $tomlfile]} {return ""}
set fh [open $tomlfile r]
try {
set content [read $fh]
} finally {
close $fh
}
return [::punkboot::utils::parse_punkproject_version $content]
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::punkboot::utils::read_changelog_latest_version
@cmd -name "::punkboot::utils::read_changelog_latest_version"\
-summary\
"Read the latest ## [X.Y.Z] version header from a changelog file"\
-help\
"Scans the changelog file from the top and returns the
version string from the first '## [X.Y.Z]' header line.
Returns an empty string if the file does not exist or no
matching header is found."
@leaders
changelogfile -type string -optional 0 -help\
"Path to the changelog file to read"
}]
}
proc read_changelog_latest_version {changelogfile} {
if {![file exists $changelogfile]} {return ""}
set fh [open $changelogfile r]
try {
set content [read $fh]
} finally {
close $fh
}
foreach line [split $content \n] {
if {[regexp {^##\s*\[([0-9][^\]]*)\]} $line _ v]} {
return $v
}
}
return ""
}
namespace eval argdoc {
lappend PUNKARGS [list {
@id -id ::punkboot::utils::vcs_dirty_warnings
@cmd -name "::punkboot::utils::vcs_dirty_warnings"\
-summary\
"Warning lines for uncommitted VCS changes above a path"\
-help\
"Walks up from path to the nearest fossil and/or git root and
returns warning lines describing uncommitted changes.
Artifacts built from a dirty source tree have no committed
provenance - callers such as make.tcl vendorupdate use this
to flag source projects that should be committed first.
checkedrootsvar names a dict variable in the caller's scope
used to report each VCS root at most once across calls.
label, if supplied, is prefixed into each warning to name
the calling operation (e.g. 'vendorupdate').
Returns an empty list if the path is clean, unversioned,
missing, already reported, or state cannot be determined."
@leaders
path -type string -optional 0 -help\
"Path to check; the nearest enclosing fossil/git root is examined"
checkedrootsvar -type string -optional 0 -help\
"Name of a dict variable in the caller's scope for dedupe across calls"
label -type string -optional 1 -default "" -help\
"Operation name prefixed into warnings"
}]
}
proc vcs_dirty_warnings {path checkedrootsvar {label ""}} {
upvar 1 $checkedrootsvar checkedroots
if {![info exists checkedroots]} {set checkedroots [dict create]}
if {$label ne ""} {set label "$label "}
set warnings [list]
set dir [file normalize $path]
if {![file isdirectory $dir]} {
return $warnings ;#missing path - not this proc's business to report
}
set fossilroot ""
set gitroot ""
while {1} {
if {$fossilroot eq "" && ([file exists [file join $dir .fslckout]] || [file exists [file join $dir _FOSSIL_]])} {
set fossilroot $dir
}
if {$gitroot eq "" && [file exists [file join $dir .git]]} {
set gitroot $dir
}
if {$fossilroot ne "" || $gitroot ne ""} {
break ;#report at the nearest VCS root(s); a dual git+fossil root is caught in one pass
}
set parent [file dirname $dir]
if {$parent eq $dir} { break }
set dir $parent
}
if {$fossilroot ne "" && ![dict exists $checkedroots fossil,$fossilroot] && [llength [auto_execok fossil]]} {
dict set checkedroots fossil,$fossilroot 1
#fossil changes must run from within the checkout
set original_cwd [pwd]
if {[catch {
cd $fossilroot
set fchanges [string trim [exec {*}[auto_execok fossil] changes]]
} errM]} {
lappend warnings "WARNING: ${label}could not determine fossil state of source project at $fossilroot ($errM)"
} elseif {$fchanges ne ""} {
lappend warnings "WARNING: ${label}source project at $fossilroot has uncommitted fossil changes ([llength [split $fchanges \n]] file(s)) - artifacts built from a dirty tree have no committed provenance"
}
cd $original_cwd
}
if {$gitroot ne "" && ![dict exists $checkedroots git,$gitroot] && [llength [auto_execok git]]} {
dict set checkedroots git,$gitroot 1
if {[catch {
set gchanges [string trim [exec {*}[auto_execok git] -C $gitroot status --porcelain]]
} errM]} {
lappend warnings "WARNING: ${label}could not determine git state of source project at $gitroot ($errM)"
} elseif {$gchanges ne ""} {
lappend warnings "WARNING: ${label}source project at $gitroot has uncommitted git changes ([llength [split $gchanges \n]] file(s)) - artifacts built from a dirty tree have no committed provenance"
}
}
return $warnings
}
}
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punkboot::utils ::punkboot::utils::argdoc
}
## Ready
package provide punkboot::utils [tcl::namespace::eval punkboot::utils {
variable version
#- this version number, exactly 0.1.1, is a literal used in src module folders
#- we refer to this sometimes as the magic version number
set version 0.1.1
}]
return

42
src/vfs/_vfscommon.vfs/modules/shellfilter-0.2.2.tm → src/vfs/_vfscommon.vfs/modules/shellfilter-0.2.3.tm

@ -2849,9 +2849,19 @@ namespace eval shellfilter {
set id_out [shellfilter::stack::add $outchan tee_to_pipe -action sink-aside -settings [list -tag $teehandle_out -pipechan $outpipechan]]
set id_err [shellfilter::stack::add $errchan tee_to_pipe -action sink-aside -settings [list -tag $teehandle_err -pipechan $errpipechan]]
#From here to the stack::remove calls the caller's channels are diverted:
#any error escaping this region would leave stdout/stderr broken for the rest of the
#process with all subsequent output silently lost - hence the try/finally below, and
#catch-guards on decorative logging (stack-status table rendering runs punk::ansi/textblock
#code that can fail e.g when mismatched module snapshots are loaded - a rendering failure
#must degrade to a log note, never abort the run).
log::critical {
::shellfilter::log::write $runtag "[punk::ansi::ansistrip [shellfilter::stack status]]\nchan names:[chan names]"
if {[catch {punk::ansi::ansistrip [shellfilter::stack status]} stackstatus]} {
set stackstatus "(shellfilter::stack status unavailable: $stackstatus)"
}
::shellfilter::log::write $runtag "$stackstatus\nchan names:[chan names]"
}
try {
# need to use os level channel handle for stdin - try named pipes (or even sockets) instead of fifo2 for this
# If non os-level channel - the command can't be run with the redirection
# stderr/stdout can be run with non-os handles in the call -
@ -2919,22 +2929,28 @@ namespace eval shellfilter {
#----------------------------------------------------------------------------------------------
#todo - change to log::debug
log::critical {
if {![catch {package require punk::ansi}]} {
set stackstatus [punk::ansi::ansistrip [shellfilter::stack status]]
} else {
set stackstatus [shellfilter::stack status]
if {[catch {
if {![catch {package require punk::ansi}]} {
set stackstatus [punk::ansi::ansistrip [shellfilter::stack status]]
} else {
set stackstatus [shellfilter::stack status]
}
} errstatus]} {
set stackstatus "(shellfilter::stack status unavailable: $errstatus)"
}
::shellfilter::log::write $runtag "shellfilter::stack status after execution: \n$stackstatus\nchan:names [chan names]"
}
#----------------------------------------------------------------------------------------------
#the previous redirections on the underlying inchan/outchan/errchan items will be restored from the -aside setting during removal
#Remove execution-time Tees from stack
log::debug {::shellfilter::log::write $runtag "removing $id_out from stdout stack"}
shellfilter::stack::remove $outchan $id_out
log::debug {::shellfilter::log::write $runtag "removing $id_err from stderr stack"}
shellfilter::stack::remove $errchan $id_err
} finally {
#the previous redirections on the underlying inchan/outchan/errchan items will be restored from the -aside setting during removal
#Remove execution-time Tees from stack - must happen even if the body above errored,
#or the caller's stdout/stderr stay diverted and all subsequent process output is silently lost.
log::debug {::shellfilter::log::write $runtag "removing $id_out from stdout stack"}
shellfilter::stack::remove $outchan $id_out
log::debug {::shellfilter::log::write $runtag "removing $id_err from stderr stack"}
shellfilter::stack::remove $errchan $id_err
}
log::info {::shellfilter::log::write $runtag " return '$exitinfo'"}
@ -3811,5 +3827,5 @@ namespace eval shellfilter {
package provide shellfilter [namespace eval shellfilter {
variable version
set version 0.2.2
set version 0.2.3
}]

421
src/vfs/_vfscommon.vfs/modules/shellrun-0.1.2.tm → src/vfs/_vfscommon.vfs/modules/shellrun-0.1.4.tm

@ -5,6 +5,7 @@
package require shellfilter
package require punk::ansi
package require punk::args
#NOTE: the run,runout,runerr,runx commands only produce an error if the command didn't run.
# - If it did run, but there was a non-zero exitcode it is up to the application to check that.
@ -79,76 +80,45 @@ namespace eval shellrun {
#maintenance: similar used in punk::ns & punk::winrun
#todo - take runopts + aliases as args
#longopts must be passed as a single item ie --timeout=100 not --timeout 100
proc get_run_opts {arglist} {
if {[catch {
set callerinfo [info level -1]
} errM]} {
set caller ""
} else {
set caller [lindex $callerinfo 0]
}
#we provide -nonewline even for 'run' even though run doesn't deliver stderr or stdout to the tcl return value
#This is for compatibility with other runX commands, and the difference is also visible when calling from repl.
set known_runopts [list "-echo" "-e" "-nonewline" "-n" "-tcl" "-debug"]
set known_longopts [list "--timeout"]
set known_longopts_msg ""
foreach lng $known_longopts {
append known_longopts_msg "${lng}=val "
}
set aliases [list "-e" "-echo" "-echo" "-echo" "-n" "-nonewline" "-nonewline" "-nonewline" "-tcl" "-tcl" "-debug" "-debug"] ;#include map to self
set runopts [list]
set runoptslong [list]
set cmdargs [list]
set idx_first_cmdarg [lsearch -not $arglist "-*"]
set allopts [lrange $arglist 0 $idx_first_cmdarg-1]
set cmdargs [lrange $arglist $idx_first_cmdarg end]
foreach o $allopts {
if {[string match --* $o]} {
lassign [split $o =] flagpart valpart
if {$valpart eq ""} {
error "$caller: longopt $o seems to be missing a value - must be of form --option=value"
}
if {$flagpart ni $known_longopts} {
error "$caller: Unknown runoption $o - known options $known_runopts $known_longopts_msg"
}
lappend runoptslong $flagpart $valpart
} else {
if {$o ni $known_runopts} {
error "$caller: Unknown runoption $o - known options $known_runopts $known_longopts_msg"
}
lappend runopts [dict get $aliases $o]
}
}
return [list runopts $runopts runoptslong $runoptslong cmdargs $cmdargs]
}
#todo - investigate cause of punk86 run hanging sometimes. An 'after 500' before exit in the called script fixes the issue. punk87 doesn't seem to be affected.
lappend PUNKARGS [list {
@id -id ::shellrun::run
@cmd -name "shellrun::run"\
-summary "Run an external command, streaming stdout/stderr to the console in real-time"\
-help\
"Run an external command and return the shellfilter exitinfo dict.
stdout and stderr are written to the console as they arrive;
nothing is captured for the return value. The exitcode is
part of the returned dict — a non-zero exitcode is NOT raised
as a Tcl error, the caller must check it explicitly.
Use -tcl to run a Tcl script/command instead of an external
process; in that case the returned dict carries a 'result'
key (or error/errorCode/errorInfo on failure) instead of an
exitcode."
@leaders -min 0 -max 0
@opts
-nonewline -type none
-tcl -type none -default 0
-debug -type none -default 0
--timeout= -type integer
-nonewline -type none -help\
"Accepted for compatibility with runout/runerr/runx. Has no
effect on run because run does not capture or return stdout."
-tcl -type none -default 0 -help\
"Interpret cmdname (and cmdarg) as a Tcl command/script rather
than an external process."
-debug -type none -default 0 -help\
"Enable debug diagnostics from shellfilter::run."
--timeout= -type integer -help\
"Timeout in milliseconds for the external process."
@values -min 1 -max -1
cmdname -type string
cmdarg -type any -multiple 1 -optional 1
cmdname -type string -help\
"Name of the external command (or Tcl command when -tcl is
given)."
cmdarg -type any -multiple 1 -optional 1 -help\
"Additional arguments passed through to the command."
}]
proc run {args} {
#set_last_run_display [list]
#set splitargs [get_run_opts $args]
#set runopts [dict get $splitargs runopts]
#set runoptslong [dict get $splitargs runoptslong]
#set cmdargs [dict get $splitargs cmdargs]
set argd [punk::args::parse $args withid ::shellrun::run]
lassign [dict values $argd] leaders opts values received
@ -206,11 +176,25 @@ namespace eval shellrun {
lappend PUNKARGS [list {
@id -id ::shellrun::runconsole
@cmd -name "shellrun::runconsole"\
-summary "Run a command via exec with stdout/stderr directed to the console, mimicking Tcl's unknown handler"\
-help\
"Resolve cmdname via auto_execok and exec it with stdout
and stderr redirected to the active console. The result is
returned via uplevel with the exec result/options dict,
mirroring the way Tcl's unknown proc handles external
commands.
Unlike run, this uses exec semantics — there is no
exitcode in the return value and stdout/stderr are not
captured separately."
@leaders -min 0 -max 0
@opts
@values -min 1 -max -1
cmdname -type string
cmdarg -type any -multiple 1 -optional 1
cmdname -type string -help\
"Name of the command to resolve via auto_execok and run."
cmdarg -type any -multiple 1 -optional 1 -help\
"Additional arguments passed to the resolved command."
}]
#run in the way tcl unknown does - but without regard to auto_noexec
proc runconsole {args} {
@ -256,16 +240,42 @@ namespace eval shellrun {
}
lappend PUNKARGS [list {
@id -id ::shellrun::runout
@cmd -name "shellrun::runout"\
-summary "Run an external command and return its stdout"\
-help\
"Run an external command, capture stdout and stderr, and
return stdout as the result. stderr and the exitcode are
emitted via repl telemetry chunks but are not part of the
return value.
By default no console output is produced while the command
runs; use -echo to tee stdout and stderr to the console in
real-time. Use -nonewline to strip a trailing newline from
the returned stdout.
Use -tcl to run a Tcl script/command instead of an external
process."
@leaders -min 0 -max 0
@opts
-echo -type none
-nonewline -type none
-tcl -type none -default 0
-debug -type none -default 0
--timeout= -type integer
-echo -type none -help\
"Tee stdout and stderr to the console in real-time while still
capturing them for the return value."
-nonewline -type none -help\
"Strip a trailing newline (\\r\\n or \\n) from the returned
stdout."
-tcl -type none -default 0 -help\
"Interpret cmdname (and cmdarg) as a Tcl command/script rather
than an external process."
-debug -type none -default 0 -help\
"Enable debug diagnostics from shellfilter::run."
--timeout= -type integer -help\
"Timeout in milliseconds for the external process."
@values -min 1 -max -1
cmdname -type string
cmdarg -type any -multiple 1 -optional 1
cmdname -type string -help\
"Name of the external command (or Tcl command when -tcl is
given)."
cmdarg -type any -multiple 1 -optional 1 -help\
"Additional arguments passed through to the command."
}]
proc runout {args} {
set argd [punk::args::parse $args withid ::shellrun::runout]
@ -284,11 +294,6 @@ namespace eval shellrun {
set runerr ""
set RST [a]
#set splitargs [get_run_opts $args]
#set runopts [dict get $splitargs runopts]
#set cmdargs [dict get $splitargs cmdargs]
#puts stdout "RUNOUT cmdargs: $cmdargs"
#todo add -data boolean and -data lastwrite to -settings with default being -data all
@ -422,16 +427,42 @@ namespace eval shellrun {
lappend PUNKARGS [list {
@id -id ::shellrun::runerr
@cmd -name "shellrun::runerr"\
-summary "Run an external command and return its stderr"\
-help\
"Run an external command, capture stdout and stderr, and
return stderr as the result. stdout and the exitcode are
emitted via repl telemetry chunks but are not part of the
return value.
By default no console output is produced while the command
runs; use -echo to tee stdout and stderr to the console in
real-time. Use -nonewline to strip a trailing newline from
the returned stderr.
Use -tcl to run a Tcl script/command instead of an external
process."
@leaders -min 0 -max 0
@opts
-echo -type none
-nonewline -type none
-tcl -type none -default 0
-debug -type none -default 0
--timeout= -type integer
-echo -type none -help\
"Tee stdout and stderr to the console in real-time while still
capturing them for the return value."
-nonewline -type none -help\
"Strip a trailing newline (\\r\\n or \\n) from the returned
stderr."
-tcl -type none -default 0 -help\
"Interpret cmdname (and cmdarg) as a Tcl command/script rather
than an external process."
-debug -type none -default 0 -help\
"Enable debug diagnostics from shellfilter::run."
--timeout= -type integer -help\
"Timeout in milliseconds for the external process."
@values -min 1 -max -1
cmdname -type string
cmdarg -type any -multiple 1 -optional 1
cmdname -type string -help\
"Name of the external command (or Tcl command when -tcl is
given)."
cmdarg -type any -multiple 1 -optional 1 -help\
"Additional arguments passed through to the command."
}]
proc runerr {args} {
set argd [punk::args::parse $args withid ::shellrun::runerr]
@ -449,10 +480,6 @@ namespace eval shellrun {
set runout ""
set runerr ""
#set splitargs [get_run_opts $args]
#set runopts [dict get $splitargs runopts]
#set cmdargs [dict get $splitargs cmdargs]
set callopts [dict create]
if {[dict exists $received "-tcl"]} {
dict set callopts -tclscript 1
@ -567,6 +594,43 @@ namespace eval shellrun {
}
lappend PUNKARGS [list {
@id -id ::shellrun::runx
@cmd -name "shellrun::runx"\
-summary "Run an external command and return a dict of stdout, stderr, and exitcode"\
-help\
"Run an external command, capture stdout and stderr, and
return a dict containing stdout, stderr, and exitcode (or
result/error/errorCode/errorInfo for -tcl calls).
No console output is produced unless -echo is given. Use
-nonewline to strip trailing newlines from captured stdout
and stderr before returning.
Use -tcl to run a Tcl script/command instead of an external
process."
@leaders -min 0 -max 0
@opts
-echo -type none -help\
"Tee stdout and stderr to the console in real-time while still
capturing them for the return dict."
-nonewline -type none -help\
"Strip a trailing newline (\\r\\n or \\n) from captured stdout
and stderr in the returned dict."
-tcl -type none -default 0 -help\
"Interpret cmdname (and cmdarg) as a Tcl command/script rather
than an external process."
-debug -type none -default 0 -help\
"Enable debug diagnostics from shellfilter::run."
--timeout= -type integer -help\
"Timeout in milliseconds for the external process."
@values -min 1 -max -1
cmdname -type string -help\
"Name of the external command (or Tcl command when -tcl is
given)."
cmdarg -type any -multiple 1 -optional 1 -help\
"Additional arguments passed through to the command."
}]
proc runx {args} {
#set_last_run_display [list]
variable runout
@ -574,11 +638,10 @@ namespace eval shellrun {
set runout ""
set runerr ""
set splitargs [get_run_opts $args]
set runopts [dict get $splitargs runopts]
set cmdargs [dict get $splitargs cmdargs]
set argd [punk::args::parse $args withid ::shellrun::runx]
lassign [dict values $argd] leaders opts values received
if {"-nonewline" in $runopts} {
if {[dict exists $received "-nonewline"]} {
set nonewline 1
} else {
set nonewline 0
@ -586,7 +649,7 @@ namespace eval shellrun {
#shellfilter::stack::remove stdout $::repl::id_outstack
if {"-echo" in $runopts} {
if {[dict exists $received "-echo"]} {
#float to ensure repl transform doesn't interfere with the output data
set stderr_stackid [shellfilter::stack::add stderr tee_to_var -action float -settings {-varname ::shellrun::runerr}]
set stdout_stackid [shellfilter::stack::add stdout tee_to_var -action float -settings {-varname ::shellrun::runout}]
@ -601,10 +664,23 @@ namespace eval shellrun {
set stdout_stackid [shellfilter::stack::add stdout var -action float-locked -junction 1 -settings {-varname ::shellrun::runout}]
}
set callopts ""
if {"-tcl" in $runopts} {
append callopts " -tclscript 1"
set callopts [dict create]
if {[dict exists $received "-tcl"]} {
dict set callopts -tclscript 1
}
if {[dict exists $received "-debug"]} {
dict set callopts -debug 1
}
if {[dict exists $received --timeout]} {
dict set callopts -timeout [dict get $opts --timeout]
}
set cmdname [dict get $values cmdname]
if {[dict exists $received cmdarg]} {
set cmdarglist [dict get $values cmdarg]
} else {
set cmdarglist {}
}
set cmdargs [concat $cmdname $cmdarglist]
#set exitinfo [shellfilter::run $cmdargs -teehandle punksh -inbuffering none -outbuffering none -stdinhandler ::repl::repl_handler]
set exitinfo [shellfilter::run $cmdargs {*}$callopts -teehandle punksh -inbuffering none -outbuffering none]
@ -616,7 +692,7 @@ namespace eval shellrun {
flush stdout
if {[dict exists $exitinfo error]} {
if {"-tcl" in $runopts} {
if {[dict exists $received "-tcl"]} {
} else {
#todo - check errorInfo makes sense.. return -code? tailcall?
@ -826,30 +902,161 @@ namespace eval shellrun {
return $exitinfo
}
lappend PUNKARGS [list {
@id -id ::shellrun::sh_run
@cmd -name "shellrun::sh_run"\
-summary "Run a command line via sh -c, streaming stdout/stderr to the console"\
-help\
"Wrapper around shellrun::run that invokes the command line
via sh -c. The entire command line after options is passed
as a single argument to sh -c.
Accepts the same options as shellrun::run except -tcl,
which is not meaningful for the sh_* wrappers because they
always invoke an external shell."
@leaders -min 0 -max 0
@opts
-nonewline -type none -help\
"Accepted for compatibility. Has no effect on run-based
commands because run does not capture output."
-debug -type none -default 0 -help\
"Enable debug diagnostics from shellfilter::run."
--timeout= -type integer -help\
"Timeout in milliseconds for the external process."
@values -min 1 -max -1
cmdargs -type any -multiple 1 -help\
"Command line to pass to sh -c as a single string argument."
}]
proc sh_run {args} {
set splitargs [get_run_opts $args]
set runopts [dict get $splitargs runopts]
set cmdargs [dict get $splitargs cmdargs]
set argd [punk::args::parse $args withid ::shellrun::sh_run]
lassign [dict values $argd] leaders opts values received
set cmdargs [dict get $values cmdargs]
set runopts [list]
if {[dict exists $received -nonewline]} { lappend runopts -nonewline }
if {[dict exists $received -debug]} { lappend runopts -debug }
if {[dict exists $received --timeout]} { lappend runopts --timeout=[dict get $opts --timeout] }
#e.g sh -c "ls -l *"
#we pass cmdargs to sh -c as a list, not individually
tailcall shellrun::run {*}$runopts sh -c $cmdargs
}
lappend PUNKARGS [list {
@id -id ::shellrun::sh_runout
@cmd -name "shellrun::sh_runout"\
-summary "Run a command line via sh -c and return its stdout"\
-help\
"Wrapper around shellrun::runout that invokes the command
line via sh -c. The entire command line after options is
passed as a single argument to sh -c.
Accepts the same options as shellrun::runout except -tcl,
which is not meaningful for the sh_* wrappers because they
always invoke an external shell."
@leaders -min 0 -max 0
@opts
-echo -type none -help\
"Tee stdout and stderr to the console in real-time while still
capturing them for the return value."
-nonewline -type none -help\
"Strip a trailing newline (\\r\\n or \\n) from the returned
stdout."
-debug -type none -default 0 -help\
"Enable debug diagnostics from shellfilter::run."
--timeout= -type integer -help\
"Timeout in milliseconds for the external process."
@values -min 1 -max -1
cmdargs -type any -multiple 1 -help\
"Command line to pass to sh -c as a single string argument."
}]
proc sh_runout {args} {
set splitargs [get_run_opts $args]
set runopts [dict get $splitargs runopts]
set cmdargs [dict get $splitargs cmdargs]
set argd [punk::args::parse $args withid ::shellrun::sh_runout]
lassign [dict values $argd] leaders opts values received
set cmdargs [dict get $values cmdargs]
set runopts [list]
if {[dict exists $received -echo]} { lappend runopts -echo }
if {[dict exists $received -nonewline]} { lappend runopts -nonewline }
if {[dict exists $received -debug]} { lappend runopts -debug }
if {[dict exists $received --timeout]} { lappend runopts --timeout=[dict get $opts --timeout] }
tailcall shellrun::runout {*}$runopts sh -c $cmdargs
}
lappend PUNKARGS [list {
@id -id ::shellrun::sh_runerr
@cmd -name "shellrun::sh_runerr"\
-summary "Run a command line via sh -c and return its stderr"\
-help\
"Wrapper around shellrun::runerr that invokes the command
line via sh -c. The entire command line after options is
passed as a single argument to sh -c.
Accepts the same options as shellrun::runerr except -tcl,
which is not meaningful for the sh_* wrappers because they
always invoke an external shell."
@leaders -min 0 -max 0
@opts
-echo -type none -help\
"Tee stdout and stderr to the console in real-time while still
capturing them for the return value."
-nonewline -type none -help\
"Strip a trailing newline (\\r\\n or \\n) from the returned
stderr."
-debug -type none -default 0 -help\
"Enable debug diagnostics from shellfilter::run."
--timeout= -type integer -help\
"Timeout in milliseconds for the external process."
@values -min 1 -max -1
cmdargs -type any -multiple 1 -help\
"Command line to pass to sh -c as a single string argument."
}]
proc sh_runerr {args} {
set splitargs [get_run_opts $args]
set runopts [dict get $splitargs runopts]
set cmdargs [dict get $splitargs cmdargs]
set argd [punk::args::parse $args withid ::shellrun::sh_runerr]
lassign [dict values $argd] leaders opts values received
set cmdargs [dict get $values cmdargs]
set runopts [list]
if {[dict exists $received -echo]} { lappend runopts -echo }
if {[dict exists $received -nonewline]} { lappend runopts -nonewline }
if {[dict exists $received -debug]} { lappend runopts -debug }
if {[dict exists $received --timeout]} { lappend runopts --timeout=[dict get $opts --timeout] }
tailcall shellrun::runerr {*}$runopts sh -c $cmdargs
}
lappend PUNKARGS [list {
@id -id ::shellrun::sh_runx
@cmd -name "shellrun::sh_runx"\
-summary "Run a command line via sh -c and return a dict of stdout, stderr, and exitcode"\
-help\
"Wrapper around shellrun::runx that invokes the command
line via sh -c. The entire command line after options is
passed as a single argument to sh -c.
Accepts the same options as shellrun::runx except -tcl,
which is not meaningful for the sh_* wrappers because they
always invoke an external shell."
@leaders -min 0 -max 0
@opts
-echo -type none -help\
"Tee stdout and stderr to the console in real-time while still
capturing them for the return dict."
-nonewline -type none -help\
"Strip a trailing newline (\\r\\n or \\n) from captured stdout
and stderr in the returned dict."
-debug -type none -default 0 -help\
"Enable debug diagnostics from shellfilter::run."
--timeout= -type integer -help\
"Timeout in milliseconds for the external process."
@values -min 1 -max -1
cmdargs -type any -multiple 1 -help\
"Command line to pass to sh -c as a single string argument."
}]
proc sh_runx {args} {
set splitargs [get_run_opts $args]
set runopts [dict get $splitargs runopts]
set cmdargs [dict get $splitargs cmdargs]
set argd [punk::args::parse $args withid ::shellrun::sh_runx]
lassign [dict values $argd] leaders opts values received
set cmdargs [dict get $values cmdargs]
set runopts [list]
if {[dict exists $received -echo]} { lappend runopts -echo }
if {[dict exists $received -nonewline]} { lappend runopts -nonewline }
if {[dict exists $received -debug]} { lappend runopts -debug }
if {[dict exists $received --timeout]} { lappend runopts --timeout=[dict get $opts --timeout] }
tailcall shellrun::runx {*}$runopts sh -c $cmdargs
}
}
@ -895,5 +1102,5 @@ namespace eval ::punk::args::register {
package provide shellrun [namespace eval shellrun {
variable version
set version 0.1.2
set version 0.1.4
}]

9677
src/vfs/_vfscommon.vfs/modules/tomlish-1.1.10.tm

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save