Skip to content

Instantly share code, notes, and snippets.

@perpen
Last active January 22, 2023 00:46
Show Gist options
  • Save perpen/aaf607e5472642ac352d98813dc34afc to your computer and use it in GitHub Desktop.
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
#!/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