-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathrun.sh
executable file
·146 lines (129 loc) · 4.25 KB
/
run.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/bin/bash
# Copyright 2022 Mitchell Kember. Subject to the MIT License.
set -eufo pipefail
main="src/main.ss"
usage() {
cat <<EOS
Usage: $0 [-hdp] {all,chez,guile,racket} ARG ...
Run $main using the given Scheme implementation
Commands:
all Run with all Schemes in parallel
chez Run with Chez Scheme
guile Run with Guile
racket Run with Racket
Arguments:
ARG Forwarded to $main
Options:
-h, --help Show this help message
-d, --debug Enter debugger on uncaught exception
-p, --plain Use plain output for 'all'
EOS
}
debug=false
plain=false
num_schemes=3
# Assuming the cursor is below $num_schemes lines of output, moves up to the
# ${1}th line and replaces its contents with $2, truncating with an ellipsis if
# necessary to fit. Then restores the cursor to its original position.
update() {
n=$1
line=$2
stripped=$(sed -E 's/\x1b\[[0-9;]+m//g' <<< "$line")
cols=$(tput cols)
if [[ ${#stripped} -gt $cols ]]; then
# Just ditch color since it's too hard to calculate the right size and
# we might truncate in the middle of an escape code otherwise.
line="${stripped::$((cols - 3))}..."
fi
# shellcheck disable=SC2059
printf "\x1b[${n}A\r\x1b[2K${line}\x1b[0m\x1b[${n}B\r"
}
# Runs ${@:3} and prints output prefixed with $2 on the ${1}th line. But if
# $plain is true, just prints output without moving the cursor.
monitor() {
if [[ $plain = true ]]; then
"${@:3}" 2>&1 | sed "s/^/$2/;s/$/\x1b[0m/"
return
fi
n=$(( num_schemes + 1 - $1 ))
update "$n" "$2"
prev=
# Use a pipe instead of process substitution to propagate the exit status.
"${@:3}" 2>&1 | while read -r line; do
# Guile logs compilation info to stderr prefixed with ";;;". Sometimes
# the order gets messed up with 2>&1 so that one of these logs comes
# last instead of the main.ss output. To avoid that, we skip printing
# a log line if it comes after a non-log line.
[[ "$prev" != ';;;'* && "$line" = ';;;'* ]] && continue
update "$n" "$2$line"
prev=$line
done
}
run_all() {
# Print blank lines so that every call to `update` can reset the old output
# instead of having a special case for the first time.
[[ $plain = false ]] && head -c $num_schemes /dev/zero | tr '\0' $'\n'
pids=()
monitor 1 "Chez ... " run_chez "$@" & pids+=($!)
monitor 2 "Guile ... " run_guile "$@" & pids+=($!)
monitor 3 "Racket ... " run_racket "$@" & pids+=($!)
status=0
for pid in "${pids[@]}"; do
wait "$pid" || status=$?
done
return $status
}
run_chez() {
flag=
[[ $debug = true ]] && flag=--debug-on-exception
chez --libdirs .:src/compat/chez --compile-imported-libraries $flag \
--program "$main" "$@"
}
run_guile() {
compat=src/compat/guile
cmd=(guile -q --r6rs -L . -L "$compat" -x .ss -l "$compat/src/init.ss")
if [[ $debug = true ]]; then
"${cmd[@]}" -l "$compat/src/debug.ss" -- "$@"
else
"${cmd[@]}" -s "$main" "$@"
fi
}
run_racket() {
if [[ $debug = true ]]; then
echo "$0: debugging not supported for racket" >&2
exit 1
fi
racket -q --search . --search src/compat/racket --make "$main" "$@"
}
# This logic is a bit complicated so that we can recognize the run.sh options
# anywhere, while passing everything else on to main.ss, unless there is a "--"
# argument that explicitly divides run.sh options from main.ss options.
ours=true
scheme=
fwd=()
for arg; do
if [[ $ours = true ]]; then
case $arg in
-d|--debug) debug=true; continue ;;
-p|--plain) plain=true; continue ;;
--) ours=false; continue ;;
*)
if [[ -z "$scheme" ]]; then
case $arg in
-h|--help|help) usage; exit ;;
*) scheme=$arg; continue ;;
esac
fi
;;
esac
fi
fwd+=("$arg")
done
# Detect whether to enable/disable color here since it's easier than in Scheme.
if ! [[ -t 1 ]] || [[ -n ${NO_COLOR+x} ]]; then
fwd+=(--no-color)
fi
case $scheme in
all|chez|guile|racket) "run_$scheme" "${fwd[@]+"${fwd[@]}"}" ;;
*) usage >&2; exit 1 ;;
esac