-
Notifications
You must be signed in to change notification settings - Fork 0
/
repoint
executable file
·213 lines (187 loc) · 5.76 KB
/
repoint
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#!/bin/bash
# Disable shellcheck warnings for useless-use-of-cat. UUOC is good
# practice, not bad: clearer, safer, less error-prone.
# shellcheck disable=SC2002
# User configuration for preferred SML implementation (polyml, mlton,
# mlkit, smlnj)
sml="$REPOINT_SML"
set -eu
# Avoid gussying up output
export HGPLAIN=true
mydir=$(dirname "$0")
program="$mydir/repoint.sml"
lockfile="$mydir/.repoint.pid"
waitcount=0
while ! ( set -o noclobber ; echo $$ > "$lockfile" ) 2>/dev/null ; do
other=$(cat "$lockfile")
case "$waitcount" in
*0) echo 1>&2
echo "Repoint (pid $other) is already running here, waiting for it to complete" 1>&2
echo "(^C to abandon, or delete $lockfile if there is no such process)" 1>&2;;
179) echo "ERROR: Waited too long, giving up" 1>&2
exit 1;;
*) ;;
esac
sleep 1
echo -n . 1>&2
waitcount=$(($waitcount + 1))
done
cleanup_lockfile() {
rm -f "$lockfile"
}
hasher=
local_install=
inhibit_local="$mydir/.repoint-inhibit-local-install"
if [ -w "$mydir" ]; then
if [ -f "$inhibit_local" ]; then
:
elif echo | sha256sum >/dev/null 2>&1 ; then
hasher=sha256sum
local_install=true
elif echo | shasum >/dev/null 2>&1 ; then
hasher=shasum
local_install=true
else
echo "WARNING: sha256sum or shasum program not found" 1>&2
fi
fi
gen_sml=
gen_out_local=
gen_out_global=
gen_out_exec=
if [ -n "$local_install" ]; then
hash=$(echo "$sml" | cat "$program" - | $hasher | cut -c1-16)
gen_sml="$mydir/.repoint-$hash.sml"
gen_out_local="$mydir/.repoint-$hash.bin"
gen_out_exec="$gen_out_local"
else
gen_sml=$(mktemp /tmp/repoint-XXXXXXXX.sml)
gen_out_global=$(mktemp /tmp/repoint-XXXXXXXX.bin)
gen_out_exec="$gen_out_global"
fi
cleanup() {
if [ -n "$gen_sml" ]; then rm -f "$gen_sml"; fi
if [ -n "$gen_out_global" ]; then rm -f "$gen_out_global"; fi
cleanup_lockfile
}
trap cleanup 0
if [ -x "$gen_out_exec" ]; then
"$gen_out_exec" "$@"
exit $?
fi
# We need one of Poly/ML, SML/NJ, MLton, or MLKit. Since we're running
# a single-file SML program as if it were a script, our order of
# preference is usually based on startup speed. An exception is the
# local_install case, where we retain a persistent binary
if [ -z "$sml" ]; then
if [ -n "$local_install" ] && mlton 2>&1 | grep -q 'MLton'; then
sml="mlton"
elif sml -h 2>&1 | grep -q 'Standard ML of New Jersey'; then
sml="smlnj"
# We would prefer Poly/ML to SML/NJ, except that Poly v5.7 has a
# nasty bug that occasionally causes it to deadlock on startup.
# That is fixed in v5.7.1, so we could promote it up the order
# again at some point in future
elif echo | poly -v 2>/dev/null | grep -q 'Poly/ML'; then
sml="polyml"
elif mlton 2>&1 | grep -q 'MLton'; then
sml="mlton"
# MLKit is at the bottom because it leaves compiled files around
# in an MLB subdir in the current directory
elif mlkit 2>&1 | grep -q 'MLKit'; then
sml="mlkit"
else cat 1>&2 <<EOF
ERROR: No supported SML compiler or interpreter found
EOF
cat 1>&2 <<EOF
The Repoint external source code manager needs a Standard ML (SML)
compiler or interpreter to run.
Please ensure you have one of the following SML implementations
installed and present in your PATH, and try again.
1. Standard ML of New Jersey
- may be found in a distribution package called: smlnj
- executable name: sml
2. Poly/ML
- may be found in a distribution package called: polyml
- executable name: poly
3. MLton
- may be found in a distribution package called: mlton
- executable name: mlton
4. MLKit
- may be found in a distribution package called: mlkit
- executable name: mlkit
EOF
exit 2
fi
fi
arglist=""
for arg in "$@"; do
if [ -n "$arglist" ]; then arglist="$arglist,"; fi
if echo "$arg" | grep -q '["'"'"']' ; then
arglist="$arglist\"usage\""
else
arglist="$arglist\"$arg\""
fi
done
case "$sml" in
polyml)
interpret=true
if [ -n "$local_install" ] && polyc --help >/dev/null 2>&1 ; then
if [ -x "$gen_out_exec" ]; then
"$gen_out_exec" "$@"
interpret=""
elif polyc -o "$gen_out_exec" "$program"; then
"$gen_out_exec" "$@"
interpret=""
else
touch "$inhibit_local"
fi
fi
if [ -n "$interpret" ]; then
echo 'use "'"$program"'"; repoint ['"$arglist"'];' |
poly -q --error-exit
fi ;;
mlton)
if [ ! -x "$gen_out_exec" ]; then
echo "[Precompiling Repoint binary...]" 1>&2
echo "val _ = main ()" | cat "$program" - > "$gen_sml"
mlton -output "$gen_out_exec" "$gen_sml"
fi
"$gen_out_exec" "$@" ;;
mlkit)
if [ ! -x "$gen_out_exec" ]; then
echo "[Precompiling Repoint binary...]" 1>&2
echo "val _ = main ()" | cat "$program" - > "$gen_sml"
mlkit -output "$gen_out_exec" "$gen_sml"
fi
"$gen_out_exec" "$@" ;;
smlnj)
cat "$program" | (
cat <<EOF
val smlrun__cp =
let val x = !Control.Print.out in
Control.Print.out := { say = fn _ => (), flush = fn () => () };
x
end;
val smlrun__prev = ref "";
Control.Print.out := {
say = fn s =>
(if String.isSubstring " Error" s
then (Control.Print.out := smlrun__cp;
(#say smlrun__cp) (!smlrun__prev);
(#say smlrun__cp) s)
else (smlrun__prev := s; ())),
flush = fn s => ()
};
EOF
cat -
cat <<EOF
val _ = repoint [$arglist];
val _ = OS.Process.exit (OS.Process.success);
EOF
) > "$gen_sml"
CM_VERBOSE=false sml "$gen_sml" ;;
*)
echo "ERROR: Unknown SML implementation name: $sml" 1>&2;
exit 2 ;;
esac