Browse Source

fix 2>@1 etc redirections, sh_runXXX procs for sh -c to allow * expansion by shell

master
Julian Noble 2 years ago
parent
commit
ca6273b44a
  1. 6
      src/modules/punk-0.1.tm
  2. 31
      src/modules/shellfilter-0.1.8.tm
  3. 135
      src/modules/shellrun-0.1.tm
  4. 5
      src/punk86.vfs/lib/app-punk/repl.tcl

6
src/modules/punk-0.1.tm

@ -495,11 +495,7 @@ namespace eval punk {
interp alias {} ECHO {} punk::sh_ECHO interp alias {} ECHO {} punk::sh_ECHO
interp alias {} c {} clear interp alias {} c {} clear
interp alias {} a+ {} shellfilter::ansi::+
interp alias {} run {} shellrun::run
interp alias {} runout {} shellrun::runout
interp alias {} runerr {} shellrun::runerr
interp alias {} runx {} shellrun::runx
interp alias {} help {} punk help interp alias {} help {} punk help
interp alias {} aliases {} punk aliases interp alias {} aliases {} punk aliases

31
src/modules/shellfilter-0.1.8.tm

@ -1996,6 +1996,7 @@ namespace eval shellfilter {
chan configure $wrerr -blocking 0 chan configure $wrerr -blocking 0
set lastitem [lindex $commandlist end] set lastitem [lindex $commandlist end]
#todo - ensure we can handle 2> file (space after >)
if {[string trim [lindex $commandlist end]] eq "&"} { if {[string trim [lindex $commandlist end]] eq "&"} {
set name [lindex $commandlist 0] set name [lindex $commandlist 0]
@ -2006,10 +2007,24 @@ namespace eval shellfilter {
return [list pids $pidlist] return [list pids $pidlist]
} }
#review - reconsider the handling of redirections such that tcl-style are handled totally separately to other shell syntaxes!
#
#note 2>@1 must ocur as last word for tcl - but 2@stdout can occur elsewhere
#(2>@stdout echoes to main stdout - not into pipeline)
#To properly do pipelines it looks like we will have to split on | and call this proc multiple times and wire it up accordingly (presumably in separate threads)
set custom_stderr "" set custom_stderr ""
if {[string trim $lastitem] in [list {2>&1} {2>@1}]} { if {[string trim $lastitem] in [list {2>&1} {2>@1}]} {
set custom_stderr {2>@1} ;#use the tcl style set custom_stderr {2>@1} ;#use the tcl style
set commandlist [lrange $commandlist 0 end-1] set commandlist [lrange $commandlist 0 end-1]
} else {
# 2> filename
# 2>> filename
# 2>@ openfileid
set redir2test [string range $lastitem 0 1]
if {$redir2test eq "2>"} {
set custom_stderr $lastitem
set commandlist [lrange $commandlist 0 end-1]
}
} }
set lastitem [lindex $commandlist end] set lastitem [lindex $commandlist end]
@ -2177,8 +2192,11 @@ namespace eval shellfilter {
} }
#todo - handle custom redirection of stderr to a file? #todo - handle custom redirection of stderr to a file?
if {[string length $custom_stderr]} { if {[string length $custom_stderr]} {
::shellfilter::log::write "LAUNCH open |[concat $commandlist $custom_stderr] a+" #::shellfilter::log::write $runtag "LAUNCH open |[concat $commandlist $custom_stderr] a+"
set rdout [open |[concat $commandlist $custom_stderr] a+] #set rdout [open |[concat $commandlist $custom_stderr] a+]
::shellfilter::log::write $runtag "LAUNCH open |[concat $commandlist [list $custom_stderr <@$inchan]] [list RDONLY]"
set rdout [open |[concat $commandlist [list <@$inchan $custom_stderr]] [list RDONLY]]
set rderr "bogus" ;#so we don't wait for it
} else { } else {
::shellfilter::log::write $runtag "LAUNCH open |[concat $commandlist [list 2>@$wrerr <@$inchan]] [list RDONLY]" ::shellfilter::log::write $runtag "LAUNCH open |[concat $commandlist [list 2>@$wrerr <@$inchan]] [list RDONLY]"
#set rdout [open |[concat $commandlist [list 2>@$wrerr]] a+] #set rdout [open |[concat $commandlist [list 2>@$wrerr]] a+]
@ -2192,7 +2210,13 @@ namespace eval shellfilter {
set rdout [open |[concat $commandlist [list 2>@$wrerr <@$inchan]] [list RDONLY]] set rdout [open |[concat $commandlist [list 2>@$wrerr <@$inchan]] [list RDONLY]]
chan configure $rderr -buffering $errbuffering -blocking 0
chan configure $rderr -translation $readprocesstranslation
} }
set command_pids [pid $rdout] set command_pids [pid $rdout]
#puts stderr "command_pids: $command_pids" #puts stderr "command_pids: $command_pids"
#tcl::process ensemble only available in 8.7+ - and it didn't prove useful here anyway #tcl::process ensemble only available in 8.7+ - and it didn't prove useful here anyway
@ -2214,9 +2238,8 @@ namespace eval shellfilter {
#jjj #jjj
chan configure $rderr -buffering $errbuffering -blocking 0
chan configure $rdout -buffering $outbuffering -blocking 0 chan configure $rdout -buffering $outbuffering -blocking 0
chan configure $rderr -translation $readprocesstranslation
chan configure $rdout -translation $readprocesstranslation chan configure $rdout -translation $readprocesstranslation
if {![string length $custom_stderr]} { if {![string length $custom_stderr]} {

135
src/modules/shellrun-0.1.tm

@ -19,23 +19,40 @@ namespace eval shellrun {
variable runerr variable runerr
proc run {args} { proc get_run_opts {arglist} {
set ::punk::last_run_display [list] if {[catch {
#we provide -nonewline for 'run' even though run doesn't deliver stderr or stdout to the tcl return value 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. #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"] set known_runopts [list "-echo" "-e" "-nonewline" "-n"]
set aliases [list "-e" "-echo" "-echo" "-echo" "-n" "-nonewline" "-nonewline" "-nonewline"] ;#include map to self set aliases [list "-e" "-echo" "-echo" "-echo" "-n" "-nonewline" "-nonewline" "-nonewline"] ;#include map to self
set runopts [list] set runopts [list]
set cmdargs [list] set cmdargs [list]
set idx_first_cmdarg [lsearch -not $args "-*"] set idx_first_cmdarg [lsearch -not $arglist "-*"]
set runopts [lrange $args 0 $idx_first_cmdarg-1] set runopts [lrange $arglist 0 $idx_first_cmdarg-1]
set cmdargs [lrange $args $idx_first_cmdarg end] set cmdargs [lrange $arglist $idx_first_cmdarg end]
foreach o $runopts { foreach o $runopts {
if {$o ni $known_runopts} { if {$o ni $known_runopts} {
error "run: Unknown runoption $o" error "$caller: Unknown runoption $o - known options $known_runopts"
} }
} }
set runopts [lmap o $runopts {dict get $aliases $o}] set runopts [lmap o $runopts {dict get $aliases $o}]
return [list runopts $runopts cmdargs $cmdargs]
}
proc run {args} {
set ::punk::last_run_display [list]
set splitargs [get_run_opts $args]
set runopts [dict get $splitargs runopts]
set cmdargs [dict get $splitargs cmdargs]
if {"-nonewline" in $runopts} { if {"-nonewline" in $runopts} {
set nonewline 1 set nonewline 1
} else { } else {
@ -52,7 +69,7 @@ namespace eval shellrun {
set c [shellfilter::ansi::+ green] set c [shellfilter::ansi::+ green]
set n [shellfilter::ansi::+] set n [shellfilter::ansi::+]
if {[dict exists $exitinfo error]} { if {[dict exists $exitinfo error]} {
error [dict get $exitinfo error] error "[dict get $exitinfo error]\n$exitinfo"
} }
return $exitinfo return $exitinfo
@ -65,19 +82,10 @@ namespace eval shellrun {
set runout "" set runout ""
set runerr "" set runerr ""
set known_runopts [list "-echo" "-e" "-nonewline" "-n"] set splitargs [get_run_opts $args]
set aliases [list "-e" "-echo" "-echo" "-echo" "-n" "-nonewline" "-nonewline" "-nonewline"] ;#include map to self set runopts [dict get $splitargs runopts]
set runopts [list] set cmdargs [dict get $splitargs cmdargs]
set cmdargs [list]
set idx_first_cmdarg [lsearch -not $args "-*"]
set runopts [lrange $args 0 $idx_first_cmdarg-1]
set cmdargs [lrange $args $idx_first_cmdarg end]
foreach o $runopts {
if {$o ni $known_runopts} {
error "runout: Unknown runoption $o"
}
}
set runopts [lmap o $runopts {dict get $aliases $o}]
if {"-nonewline" in $runopts} { if {"-nonewline" in $runopts} {
set nonewline 1 set nonewline 1
} else { } else {
@ -177,19 +185,11 @@ namespace eval shellrun {
variable runerr variable runerr
set runout "" set runout ""
set runerr "" set runerr ""
set known_runopts [list "-echo" "-e" "-nonewline" "-n"]
set aliases [list "-e" "-echo" "-echo" "-echo" "-n" "-nonewline" "-nonewline" "-nonewline"] ;#include map to self set splitargs [get_run_opts $args]
set runopts [list] set runopts [dict get $splitargs runopts]
set cmdargs [list] set cmdargs [dict get $splitargs cmdargs]
set idx_first_cmdarg [lsearch -not $args "-*"]
set runopts [lrange $args 0 $idx_first_cmdarg-1]
set cmdargs [lrange $args $idx_first_cmdarg end]
foreach o $runopts {
if {$o ni $known_runopts} {
error "runerr: Unknown runoption $o"
}
}
set runopts [lmap o $runopts {dict get $aliases $o}]
if {"-nonewline" in $runopts} { if {"-nonewline" in $runopts} {
set nonewline 1 set nonewline 1
} else { } else {
@ -272,6 +272,7 @@ namespace eval shellrun {
return $::shellrun::runerr return $::shellrun::runerr
} }
proc runx {args} { proc runx {args} {
set ::punk::last_run_display [list] set ::punk::last_run_display [list]
variable last_run_display variable last_run_display
@ -280,32 +281,22 @@ namespace eval shellrun {
set runout "" set runout ""
set runerr "" set runerr ""
set known_runopts [list "-echo" "-e" "-nonewline" "-n"] set splitargs [get_run_opts $args]
set aliases [list "-e" "-echo" "-echo" "-echo" "-n" "-nonewline" "-nonewline" "-nonewline"] ;#include map to self set runopts [dict get $splitargs runopts]
set runopts [list] set cmdargs [dict get $splitargs cmdargs]
set cmdargs [list]
set idx_first_cmdarg [lsearch -not $args "-*"]
set runopts [lrange $args 0 $idx_first_cmdarg-1]
set cmdargs [lrange $args $idx_first_cmdarg end]
foreach o $runopts {
if {$o ni $known_runopts} {
error "runx: Unknown runoption $o - known options $known_runopts"
}
}
set runopts [lmap o $runopts {dict get $aliases $o}]
if {"-nonewline" in $runopts} { if {"-nonewline" in $runopts} {
set nonewline 1 set nonewline 1
} else { } else {
set nonewline 0 set nonewline 0
} }
#shellfilter::stack::remove stdout $::repl::id_outstack #shellfilter::stack::remove stdout $::repl::id_outstack
if {"-echo" in $runopts} { if {"-echo" in $runopts} {
set stderr_stackid [shellfilter::stack::add stderr tee_to_var -action sink-locked -settings {-varname ::shellrun::runerr}] #float to ensure repl transform doesn't interfere with the output data
set stdout_stackid [shellfilter::stack::add stdout tee_to_var -action sink-locked -settings {-varname ::shellrun::runout}] 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}]
} else { } else {
#set stderr_stackid [shellfilter::stack::add stderr var -action sink-locked -settings {-varname ::shellrun::runerr}] #set stderr_stackid [shellfilter::stack::add stderr var -action sink-locked -settings {-varname ::shellrun::runerr}]
#set stdout_stackid [shellfilter::stack::add stdout var -action sink-locked -settings {-varname ::shellrun::runout}] #set stdout_stackid [shellfilter::stack::add stdout var -action sink-locked -settings {-varname ::shellrun::runout}]
@ -385,4 +376,46 @@ namespace eval shellrun {
#always return exitinfo $code at beginning of dict (so that punk unknown can interpret the exit code as a unix-style bool if double evaluated) #always return exitinfo $code at beginning of dict (so that punk unknown can interpret the exit code as a unix-style bool if double evaluated)
return [list {*}$exitinfo stdout $::shellrun::runout stderr $::shellrun::runerr] return [list {*}$exitinfo stdout $::shellrun::runout stderr $::shellrun::runerr]
} }
proc sh_run {args} {
set splitargs [get_run_opts $args]
set runopts [dict get $splitargs runopts]
set cmdargs [dict get $splitargs cmdargs]
#e.g sh -c "ls -l *"
#we pass cmdargs to sh -c as a list, not individually
tailcall shellrun::run {*}$runopts sh -c $cmdargs
}
proc sh_runout {args} {
set splitargs [get_run_opts $args]
set runopts [dict get $splitargs runopts]
set cmdargs [dict get $splitargs cmdargs]
tailcall shellrun::runout {*}$runopts sh -c $cmdargs
}
proc sh_runerr {args} {
set splitargs [get_run_opts $args]
set runopts [dict get $splitargs runopts]
set cmdargs [dict get $splitargs cmdargs]
tailcall shellrun::runerr {*}$runopts sh -c $cmdargs
}
proc sh_runx {args} {
set splitargs [get_run_opts $args]
set runopts [dict get $splitargs runopts]
set cmdargs [dict get $splitargs cmdargs]
tailcall shellrun::runx {*}$runopts sh -c $cmdargs
}
} }
namespace eval shellrun {
interp alias {} a+ {} shellfilter::ansi::+
interp alias {} run {} shellrun::run
interp alias {} sh_run {} shellrun::sh_run
interp alias {} runout {} shellrun::runout
interp alias {} sh_runout {} shellrun::sh_runout
interp alias {} runerr {} shellrun::runerr
interp alias {} sh_runerr {} shellrun::sh_runerr
interp alias {} runx {} shellrun::runx
interp alias {} sh_runx {} shellrun::sh_runx
}

5
src/punk86.vfs/lib/app-punk/repl.tcl

@ -724,8 +724,11 @@ proc repl::repl_handler {chan} {
[string equal -length [string length "../ "] "../ " $command] || \ [string equal -length [string length "../ "] "../ " $command] || \
[string equal "../" $command] || \ [string equal "../" $command] || \
[string equal -length [string length "runx "] "runx " $command] || \ [string equal -length [string length "runx "] "runx " $command] || \
[string equal -length [string length "sh_runx "] "sh_runx " $command] || \
[string equal -length [string length "runout "] "runout " $command] || \ [string equal -length [string length "runout "] "runout " $command] || \
[string equal -length [string length "runerr "] "runerr " $command] [string equal -length [string length "sh_runout "] "sh_runout " $command] || \
[string equal -length [string length "runerr "] "runerr " $command] || \
[string equal -length [string length "sh_runerr "] "sh_runerr " $command]
} { } {
if {[llength $last_run_display]} { if {[llength $last_run_display]} {

Loading…
Cancel
Save