-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathscala-runner
executable file
·236 lines (207 loc) · 9.03 KB
/
scala-runner
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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#!/usr/bin/env bash
#
# A dynamic scala runner, using coursier's app launch capabilities.
# Author: Dale Wijnand <[email protected]>
# https://github.com/dwijnand/scala-runners
shopt -s extglob # for extended pattern matching operators, like `+([0-9])`
app_name=$(basename "$0")
declare app_name
declare scala_version=latest.stable
declare -a java_args residual_args
declare verbose print_scala_version
declare -r scala_ea_builds_url=https://scala-ci.typesafe.com/artifactory/scala-integration
declare -r scala_pr_builds_url=https://scala-ci.typesafe.com/artifactory/scala-pr-validation-snapshots
echoerr() { echo >&2 "$@"; }
vlog() { [[ -n "$verbose" ]] && echoerr "$@"; }
die() { echo "$*"; exit 1; }
dropR() { echo "${1:0:$((${#1} - $2))}"; } # https://superuser.com/q/1033273 ${1:0:-5} (bash 4.2+)
checkExec() { type -f "$1" &> /dev/null || die "$1 command required"; }
checkHub() {
checkExec hub
if [ ! -f "${HOME}/.config/hub" ]; then
echo "No hub config found (at ~/.config/hub). Triggering hub to prompt you for credentials."
hub api
fi
}
curl() { checkExec curl && command curl "$@"; }
cs() { checkExec cs && command cs "$@"; }
jq() { checkExec jq && command jq "$@"; }
hub() { checkHub && command hub "$@"; }
addJava() { vlog "[addJava] arg = '$1'"; java_args+=("--java-opt" "$1"); }
addCoursier() { vlog "[addCoursier] arg = '$1'"; coursier_args+=("$1"); }
getScalaBaseVersion() {
vlog "[getScalaBaseVersion] arg = '$1'"
local build_sbt base_version cross
build_sbt=$(hub api -H "Accept: application/vnd.github.v3.raw" "repos/scala/scala/contents/build.sbt?ref=$1")
[ $? -eq 0 ] || die "$build_sbt"
base_version=$(grep -E '(baseVersion in Global|Global / baseVersion\b)' <<< "$build_sbt" | sed 's/.*"\(.*\)".*/\1/')
cross=$(grep -q -E '\d+\.\d+.0' <<< "$base_version" && echo "-pre" || echo "-bin")
echo "$base_version$cross"
}
getScalaHead() {
vlog "[getScalaHead] arg = '$1'"
if [[ "$1" = 3* ]]; then
echo "3+" # Using 3+ will find the latest NIGHTLY, which is the closest to Scala 2's merglies
else
local base_version refInfo sha
base_version=$(getScalaBaseVersion "heads/$1")
[ $? -eq 0 ] || die "$base_version"
refInfo=$(hub api "repos/scala/scala/git/ref/heads/$1")
[ $? -eq 0 ] || die "$refInfo"
sha=$(jq -r '.object.sha' <<< "$refInfo")
[ $? -eq 0 ] || die "$sha"
echo "$base_version-${sha:0:7}"
fi
}
getScalaNext() {
vlog "[getScalaNext] arg = '$1'"
if [[ "$1" = 3* ]]; then
# this is likely fragile and will need to be refined in the future.
# assumptions we are making include:
# * tag name doesn't start with `v`
# * releases are ordered such that latest RC comes last;
# this assumption breaks if e.g. the Scala 3 team releases 3.0.6 after 3.1.0-RC1;
# which is a plausible scenario, but maybe not worth accounting for? shrug, for now
hub api "repos/lampepfl/dotty/releases?per_page=1" | jq -r .[0].tag_name
else
curl -Ls "https://raw.github.com/scala/community-build/$1/nightly.properties" \
| sed -n 's/nightly=\(.*\)/\1/p'
fi
}
setCoursierOptionsForSv() {
case "$scala_version" in
*-@(bin|pre)-*SNAPSHOT) addCoursier "-r=$scala_pr_builds_url" ;;
*-@(bin|pre)-*) addCoursier "-r=$scala_ea_builds_url" ;;
*+) addCoursier "--no-default" && addCoursier "-r=central" ;;
esac
case "$scala_version" in
*-SNAPSHOT) addCoursier "--ttl=24h" ;;
*+) addCoursier "--ttl=24h" ;;
latest.*) addCoursier "--ttl=24h" ;; # latest.stable, latest.release, latest.integration
esac
}
setScalaVersion() {
vlog "[setScalaVersion] arg = '$1'"
[[ "$1" = 3* ]] && case "$app_name" in
scalac) app_name="scala3-compiler" ;;
scala) app_name="scala3" ;;
scaladoc) app_name="scala3-doc" ;;
scalap) app_name="scala3-decompiler" ;;
esac
case "$1" in
*.head) scala_version=$(getScalaHead "$(dropR "$1" 5).x") ;;
*.next) scala_version=$(getScalaNext "$(dropR "$1" 5).x") ;;
3+) scala_version=latest.stable ;; # Using "3+" makes cs pick the latest NIGHTLY
*) scala_version="$1" ;;
esac
[ $? -eq 0 ] || die "Failed to set scala version given the argument '$1', cause: $scala_version"
}
setScalaPrVersion() {
vlog "[setScalaPrVersion] arg = '$1'"
local base_version prInfo sha
base_version=$(getScalaBaseVersion "pull/$1/head")
[ $? -eq 0 ] || die "Failed to get scala base version for PR $1, cause: $base_version"
prInfo=$(hub api "repos/scala/scala/pulls/$1")
[ $? -eq 0 ] || die "$prInfo"
sha=$(jq -r '.head.sha' <<< "$prInfo")
[ $? -eq 0 ] || die "$sha"
setScalaVersion "$base_version-${sha:0:7}-SNAPSHOT"
}
usage() {
cat <<EOM
Usage: \$script_name [options]
Where, "script_name" is scala, scalac, scaladoc, or scalap.
All options not specified below are passed through.
-h | -help print this message (only when script_name is scala-runner)
-v verbose operation (this runner is chattier)
# scala version (default: latest.stable, resolved by Couriser)
-28 use the latest 2.8.x release
-29 use the latest 2.9.x release
-210 use the latest 2.10.x release
-211 use the latest 2.11.x release
-212 use the latest 2.12.x release
-213 use the latest 2.13.x release
-3 use the latest 3.x release
-2.12.next use the latest 2.12.x release candidate (from the community build)
-2.13.next use the latest 2.13.x release candidate
-3.next use the latest 3.x release candidate
-2.12.head use the latest 2.12.x branch HEAD build (latest "merge-ly")
-2.13.head use the latest 2.13.x branch HEAD build
-3.head use the latest 3.x nightly release
-<version> use the specified scala version, e.g. -2.13.6 or -3.0.1
--scala-version <version> use the specified scala version, e.g. --scala-version 3.1-my-test
--scala-pr <PR number> use the version of scala built from the specified PR
# passing options to the jvm
-Dkey=val pass -Dkey=val directly to the jvm
-J-X pass option -X directly to the jvm
# passing options to coursier
-C-X pass option -X directly to coursier (-C is stripped)
--print-scala-version prints the resolved scala version
EOM
exit 0
}
require_arg() {
local type="$1"
local opt="$2"
local arg="$3"
if [[ -z "$arg" ]] || [[ "${arg:0:1}" == "-" ]]; then
die "$opt requires <$type> argument"
fi
}
while [[ $# -gt 0 ]]; do
case "$1" in
-h | -help) [[ "$app_name" == "scala-runner" ]] && usage || residual_args+=("$1") && shift ;;
-v) verbose=true && shift ;;
-28) setScalaVersion "2.8+" && shift ;;
-29) setScalaVersion "2.9+" && shift ;;
-210) setScalaVersion "2.10+" && shift ;;
-211) setScalaVersion "2.11+" && shift ;;
-212) setScalaVersion "2.12+" && shift ;;
-213) setScalaVersion "2.13+" && shift ;;
-3) setScalaVersion "3+" && shift ;;
-@(2.1[2-4]|3).@(head|next)) setScalaVersion "${1:1}" && shift ;;
-[2-3].+([0-9]).+([0-9])*) setScalaVersion "${1:1}" && shift ;;
--scala-version) require_arg version "$1" "$2" && setScalaVersion "$2" && shift 2 ;;
--scala-pr) require_arg "PR number" "$1" "$2" && setScalaPrVersion "$2" && shift 2 ;;
-C*) addCoursier "${1:2}" && shift ;;
-D*) addJava "$1" && shift ;;
-J*) addJava "${1:2}" && shift ;;
--print-scala-version) print_scala_version=1 && shift ;;
*) residual_args+=("$1") && shift ;;
esac
[ $? -eq 0 ] || die "Failed to process arg '$1'"
done
setCoursierOptionsForSv
execRunner() {
# print the arguments one to a line, quoting any containing spaces
vlog "# Executing command line:" && {
for arg; do
if [[ -n "$arg" ]]; then
if printf "%s\n" "$arg" | grep -q ' '; then
printf >&2 "\"%s\"\n" "$arg"
else
printf >&2 "%s\n" "$arg"
fi
fi
done
vlog ""
}
"$@"
}
if [[ -n "$print_scala_version" ]]; then
case "$scala_version" in
*.*.*) echo "$scala_version" ;;
*)
json_file="$(mktemp -t scala-runner.cs-fetch.XXXXXX.json)"
execRunner cs fetch -j "$json_file" "$app_name:$scala_version" "${coursier_args[@]}" >/dev/null 2>&1
[ $? -eq 0 ] || die "Failed to run cs fetch: exit code $?, json_file=$json_file"
jq -r <"$json_file" '[.[]] | .[0] | [.[]] | .[0]' | cut -d: -f3
;;
esac
exit
fi
execRunner cs launch \
"$app_name:$scala_version" \
"${java_args[@]}" \
"${coursier_args[@]}" \
-- "${residual_args[@]}"