Last active
January 22, 2023 00:46
-
-
Save perpen/aaf607e5472642ac352d98813dc34afc to your computer and use it in GitHub Desktop.
Plan 9: An rc approximation of rsc's https://pkg.go.dev/9fans.net/go/acme/Watch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/rc | |
# An rc approximation of rsc's https://pkg.go.dev/9fans.net/go/acme/Watch | |
# | |
# Usage: Watch [-r | -n] [-d DIR] [CMD] | |
# -s starts command immediately | |
# -r listen for Put on subdirs recursively. | |
# -n only run the commands when Get is run | |
# -d cd to given dir, and listen for Put on files under it | |
# Flags taking no param may be combined eg: -sr | |
# | |
# You can add any number of commands in the +Watch window, prefixed | |
# with '% '. | |
# The +Watch window is marked as dirty while the commands are running. | |
# If a command fails, the subsequent commands are not run. | |
# | |
# Bugs: | |
# - If Kill is used, the commands not yet run are forgotten. | |
# - Tabs in command lines are replaced with spaces. | |
# - No attempt is made to quote params with spaces, semicolon, etc. | |
rfork en | |
fn log{ | |
#echo $* >[1=2] | |
} | |
name='+Watch' | |
dumpcmd='Watch '^$"* | |
dir=`{pwd} | |
start=n | |
recursive=n | |
nowatch=n | |
while(~ $1 -*){ | |
log flag: $1 | |
if(~ $1 *s*) start=y | |
if(~ $1 *r*) { | |
recursive=y | |
name='+Watch-r' | |
} | |
if(~ $1 *n*){ | |
nowatch=y | |
name='+Watch-n' | |
} | |
if(~ $1 -d){ | |
dir=$2 | |
shift | |
} | |
shift | |
} | |
cd $dir | |
~ $dir */ || dir=$dir/ | |
rx=$dir ^ '[^/]+$' | |
if(~ $nowatch y) | |
rx=nevermatch | |
if not | |
if(~ $recursive y) rx=$dir | |
log rx: $rx | |
args=$"* | |
win=`{cat /mnt/acme/new/ctl | awk '{print $1}'} | |
w=/mnt/acme/$win | |
cmdpidfile=/tmp/Watch.cmdpid.$pid | |
fn ctl{ echo $* >$w/ctl } | |
fn tag{ echo -n $* >$w/tag } | |
fn body{ echo -n $* >$w/body } | |
fn data{ echo $* >$w/data } | |
fn addr{ echo -n $* >$w/addr } | |
log 'win:' $win | |
ctl 'name ' ^ $dir ^ $name | |
ctl dumpdir $dir | |
ctl dump $dumpcmd | |
ctl cleartag | |
tag ' Look Get Kill' | |
body '% ' ^ $"args | |
ctl clean | |
fn sigint{ | |
log sigint | |
if(test -f $cmdpidfile) | |
killcmd | |
ctl delete | |
exit | |
} | |
fn killcmd{ | |
log killcmd | |
cmdpid=`{cat $cmdpidfile} | |
echo kill >/proc/$cmdpid/notepg | |
sleep .3 | |
addr '$'; ctl 'dot=addr' | |
data Watch: killed | |
ctl clean | |
} | |
@{ | |
rfork s | |
if(~ $start y && ! ~ $"args '') echo Get | |
# listen to Put on any window | |
cat /mnt/acme/log | grep ' put '$rx | awk '{print "put" }' & | |
# capture any pid in this process group | |
xpid=$apid | |
# filter/transform events | |
cat $w/event >[2=1] | | |
awk '/^Mx.* (Get|Kill|Del)/ {print $5; next} | |
/^M[Xx][0-9]+ +[0-9]+ +[0-9]+ +0 *$/ {next} | |
/^M[LlXx]/ {print $1 " " $2}' | |
# kill our process group | |
echo kill >/proc/$xpid/notepg | |
} >[2]/dev/null | | |
while(){ | |
msg=`{read} | |
log msg: $msg | |
switch($msg){ | |
case put Get | |
if(! test -f $cmdpidfile){ | |
{ | |
log running | |
prevstatus='' | |
addr , | |
grep '^% ' $w/body | | |
while(line=`{read | sed 's/^[% ]+//' | grep -v '^$'}){ | |
echo '%' $line | |
status=$prevstatus | |
if(~ $"prevstatus ''){ | |
rc -c $"line >[2=1] | |
prevstatus=$status | |
if(! ~ $"prevstatus '') echo '# status:' $prevstatus | |
} | |
if not{ | |
echo '# not run' | |
} | |
} >>$w/data & | |
cmdpid=$apid | |
log cmdpid: $cmdpid | |
echo $cmdpid >$cmdpidfile | |
wait $cmdpid | |
log exited | |
ctl clean | |
sleep .1 # give the kill commands time to write where they want | |
addr 0; ctl 'dot=addr'; ctl show | |
rm $cmdpidfile | |
}& | |
} | |
case Kill | |
if(test -f $cmdpidfile) | |
killcmd $msg | |
case Del | |
sigint | |
case * | |
log forwarding $msg | |
echo $msg >$w/event | |
} | |
} | |
sleep .1 | |
exit '' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment