1#!/bin/sh 2 3# Copyright (c) 2016-2018 Jade Allen 4# Copyright (c) 2011, 2012 Spawngrid, Inc 5# Copyright (c) 2011 Evax Software <contact(at)evax(dot)org> 6# 7# Permission is hereby granted, free of charge, to any person obtaining a copy 8# of this software and associated documentation files (the "Software"), to deal 9# in the Software without restriction, including without limitation the rights 10# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11# copies of the Software, and to permit persons to whom the Software is 12# furnished to do so, subject to the following conditions: 13# 14# The above copyright notice and this permission notice shall be included in 15# all copies or substantial portions of the Software. 16# 17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23# THE SOFTWARE. 24 25unset ERL_TOP 26 27# Make sure CDPATH doesn't affect cd in case path is relative. 28unset CDPATH 29 30KERL_VERSION='2.2.2' 31 32DOCSH_GITHUB_URL='https://github.com/erszcz/docsh.git' 33ERLANG_DOWNLOAD_URL='https://erlang.org/download' 34KERL_CONFIG_STORAGE_FILENAME='.kerl_config' 35 36TMP_DIR=${TMP_DIR:-'/tmp'} 37if [ -z "$HOME" ]; then 38 # shellcheck disable=SC2016 39 echo 'Error: $HOME is empty or not set.' 1>&2 40 exit 1 41fi 42 43# Default values 44OTP_GITHUB_URL=${OTP_GITHUB_URL:='https://github.com/erlang/otp'} 45KERL_BASE_DIR=${KERL_BASE_DIR:="$HOME"/.kerl} 46KERL_CONFIG=${KERL_CONFIG:="$HOME"/.kerlrc} 47KERL_DOWNLOAD_DIR=${KERL_DOWNLOAD_DIR:="${KERL_BASE_DIR:?}"/archives} 48KERL_BUILD_DIR=${KERL_BUILD_DIR:="${KERL_BASE_DIR:?}"/builds} 49KERL_GIT_DIR=${KERL_GIT_DIR:="${KERL_BASE_DIR:?}"/gits} 50KERL_DOC_TARGETS=${KERL_DOC_TARGETS:="chunks"} 51 52if [ -n "$OTP_GITHUB_URL" ]; then 53 _OGU="$OTP_GITHUB_URL" 54fi 55if [ -n "$KERL_CONFIGURE_OPTIONS" ]; then 56 _KCO="$KERL_CONFIGURE_OPTIONS" 57fi 58if [ -n "$KERL_CONFIGURE_APPLICATIONS" ]; then 59 _KCA="$KERL_CONFIGURE_APPLICATIONS" 60fi 61if [ -n "$KERL_CONFIGURE_DISABLE_APPLICATIONS" ]; then 62 _KCDA="$KERL_CONFIGURE_DISABLE_APPLICATIONS" 63fi 64if [ -n "$KERL_SASL_STARTUP" ]; then 65 _KSS="$KERL_SASL_STARTUP" 66fi 67if [ -n "$KERL_DEPLOY_SSH_OPTIONS" ]; then 68 _KDSSH="$KERL_DEPLOY_SSH_OPTIONS" 69fi 70if [ -n "$KERL_DEPLOY_RSYNC_OPTIONS" ]; then 71 _KDRSYNC="$KERL_DEPLOY_RSYNC_OPTIONS" 72fi 73if [ -n "$KERL_INSTALL_MANPAGES" ]; then 74 _KIM="$KERL_INSTALL_MANPAGES" 75fi 76if [ -n "$KERL_INSTALL_HTMLDOCS" ]; then 77 _KIHD="$KERL_INSTALL_HTMLDOCS" 78fi 79if [ -n "$KERL_BUILD_PLT" ]; then 80 _KBPLT="$KERL_BUILD_PLT" 81fi 82if [ -n "$KERL_BUILD_DOCS" ]; then 83 _KBD="$KERL_BUILD_DOCS" 84fi 85if [ -n "$KERL_DOC_TARGETS" ]; then 86 _KDT="$KERL_DOC_TARGETS" 87fi 88if [ -n "$KERL_BUILD_BACKEND" ]; then 89 _KBB="$KERL_BUILD_BACKEND" 90fi 91 92OTP_GITHUB_URL= 93KERL_CONFIGURE_OPTIONS= 94KERL_CONFIGURE_APPLICATIONS= 95KERL_CONFIGURE_DISABLE_APPLICATIONS= 96KERL_SASL_STARTUP= 97KERL_DEPLOY_SSH_OPTIONS= 98KERL_DEPLOY_RSYNC_OPTIONS= 99KERL_INSTALL_MANPAGES= 100KERL_INSTALL_HTMLDOCS= 101KERL_BUILD_PLT= 102KERL_BUILD_DOCS= 103KERL_DOC_TARGETS= 104KERL_BUILD_BACKEND= 105 106# ensure the base dir exists 107mkdir -p "$KERL_BASE_DIR" || exit 1 108 109# source the config file if available 110if [ -f "$KERL_CONFIG" ]; then 111 # shellcheck source=/dev/null 112 . "$KERL_CONFIG" 113fi 114 115if [ -n "$_OGU" ]; then 116 OTP_GITHUB_URL="$_OGU" 117fi 118if [ -n "$_KCO" ]; then 119 KERL_CONFIGURE_OPTIONS="$_KCO" 120fi 121if [ -n "$_KCA" ]; then 122 KERL_CONFIGURE_APPLICATIONS="$_KCA" 123fi 124if [ -n "$_KCDA" ]; then 125 KERL_CONFIGURE_DISABLE_APPLICATIONS="$_KCDA" 126fi 127if [ -n "$_KSS" ]; then 128 KERL_SASL_STARTUP="$_KSS" 129fi 130if [ -n "$_KDSSH" ]; then 131 KERL_DEPLOY_SSH_OPTIONS="$_KDSSH" 132fi 133if [ -n "$_KDRSYNC" ]; then 134 KERL_DEPLOY_RSYNC_OPTIONS="$_KDRSYNC" 135fi 136if [ -n "$_KIM" ]; then 137 KERL_INSTALL_MANPAGES="$_KIM" 138fi 139if [ -n "$_KIHD" ]; then 140 KERL_INSTALL_HTMLDOCS="$_KIHD" 141fi 142if [ -n "$_KBPLT" ]; then 143 KERL_BUILD_PLT="$_KBPLT" 144fi 145if [ -n "$_KBD" ]; then 146 KERL_BUILD_DOCS="$_KBD" 147fi 148if [ -n "$_KDT" ]; then 149 KERL_DOC_TARGETS="$_KDT" 150fi 151if [ -n "$_KBB" ]; then 152 KERL_BUILD_BACKEND="$_KBB" 153fi 154 155if [ -z "$KERL_SASL_STARTUP" ]; then 156 INSTALL_OPT='-minimal' 157else 158 INSTALL_OPT='-sasl' 159fi 160 161if [ -z "$KERL_BUILD_BACKEND" ]; then 162 KERL_BUILD_BACKEND='git' 163fi 164if [ "$KERL_BUILD_BACKEND" = 'git' ]; then 165 KERL_USE_AUTOCONF=1 166elif [ "$KERL_BUILD_BACKEND" != 'tarball' ]; then 167 echo "Unhandled value KERL_BUILD_BACKEND='${KERL_BUILD_BACKEND}'" 168 echo "KERL_BUILD_BACKEND must be one of 'git' (default) or 'tarball'" 169 exit 1 170fi 171 172KERL_SYSTEM=$(uname -s) 173case "$KERL_SYSTEM" in 174 Darwin|FreeBSD|OpenBSD) 175 MD5SUM='openssl md5' 176 MD5SUM_FIELD=2 177 SED_OPT=-E 178 CP_OPT=-a 179 ;; 180 *) 181 MD5SUM=md5sum 182 MD5SUM_FIELD=1 183 SED_OPT=-r 184 CP_OPT=-pr 185 ;; 186esac 187 188 189usage() { 190 echo 'kerl: build and install Erlang/OTP' 191 echo "usage: $0 <command> [options ...]" 192 printf '\n <command> Command to be executed\n\n' 193 echo 'Valid commands are:' 194 echo ' build Build specified release or git repository' 195 echo ' install Install the specified release at the given location' 196 echo ' deploy Deploy the specified installation to the given host and location' 197 echo ' update Update the list of available releases from your source provider' 198 echo ' list List releases, builds and installations' 199 echo ' delete Delete builds and installations' 200 echo ' install-docsh Install erl shell documentation access extension - docsh' 201 echo ' path Print the path of a given installation' 202 echo ' active Print the path of the active installation' 203 echo ' plt Print Dialyzer PLT path for the active installation' 204 echo ' status Print available builds and installations' 205 echo ' prompt Print a string suitable for insertion in prompt' 206 echo ' cleanup Remove compilation artifacts (use after installation)' 207 echo " version Print current version (current: $KERL_VERSION)" 208 exit 1 209} 210 211if [ $# -eq 0 ]; then usage; fi 212 213get_releases() { 214 if [ "$KERL_BUILD_BACKEND" = 'git' ]; then 215 get_git_releases 216 else 217 get_tarball_releases 218 fi 219} 220 221get_git_releases() { 222 git ls-remote --tags --refs "$OTP_GITHUB_URL" \ 223 | cut -f2 \ 224 | cut -d'/' -f3- \ 225 | sed $SED_OPT \ 226 -e '# Delete all tags starting with ":" as to not mix' \ 227 -e '# them with the prefixed lines we`re generating next.' \ 228 -e '/^:/d' \ 229 \ 230 -e '# Prefix "OTP*" release lines with the crux of their versions.' \ 231 -e '# - "OTP_R16B01_RC1" => ":16B01_RC1 OTP_R16B01_RC1"' \ 232 -e '# - "OTP_R16B03" => ":16B03 OTP_R16B03"' \ 233 -e '# - "OTP-17.0" => ":17.0 OTP-17.0"' \ 234 -e '# - "OTP-17.3.1" => ":17.3.1 OTP-17.3.1"' \ 235 -e '# - "OTP-19.0-rc1" => ":19.0-rc1 OTP-19.0-rc1"' \ 236 -e '# - "OTP-19.0-rc2" => ":19.0-rc2 OTP-19.0-rc2"' \ 237 -e 's/^(OTP[-_](R?([0-9][^ :]*).*))/:\3 \2/' \ 238 \ 239 -e '# Delete all lines that didn`t get prefixed above.' \ 240 -e '/^[^:]/d' \ 241 \ 242 -e '# Move the colon markers preceding each version prefix' \ 243 -e '# as to preceed the tag suffix instead, which will make' \ 244 -e '# throwing the version prefixes easier later on.' \ 245 -e '# - ":16B01_RC1 OTP_R16B03" => "16B01_RC1 :OTP_R16B01_RC1"' \ 246 -e '# - ":16B03 OTP_R16B03" => "16B03 :OTP_R16B03"' \ 247 -e '# - ":17.0 OTP_R16B03" => "17.0 :OTP-17.0"' \ 248 -e '# - ":17.3.1 OTP_R16B03" => "17.3.1 :OTP-17.3.1"' \ 249 -e '# - ":19.0-rc1 OTP_R16B03" => "19.0-rc1 :OTP-19.0-rc1"' \ 250 -e '# - ":19.0-rc2 OTP_R16B03" => "19.0-rc2 :OTP-19.0-rc2"' \ 251 -e 's/^:([^ ]+) /\1 :/' \ 252 \ 253 -e '# Repeatedly replace sequences of one or more dots, dashes' \ 254 -e '# or underscores, within each version prefix, with single' \ 255 -e '# space characters.' \ 256 -e '# - "16B01_RC1 :OTP_R16B01_RC1" => "16B01 RC1 :OTP_R16B01_RC1"' \ 257 -e '# - "16B03 :OTP_R16B03" => "16B03 :OTP_R16B03"' \ 258 -e '# - "17.0 :OTP-17.0" => "17 0 :OTP-17.0"' \ 259 -e '# - "17.3.1 :OTP-17.3.1" => "17 3 1 :OTP-17.3.1"' \ 260 -e '# - "19.0-rc1 :OTP-19.0-rc1" => "19 0 rc1 :OTP-19.0-rc1"' \ 261 -e '# - "19.0-rc2 :OTP-19.0-rc2" => "19 0 rc2 :OTP-19.0-rc2"' \ 262 -e ':loop' \ 263 -e 's/^([^:]*)[.-]+([^:]*) :/\1 \2 :/' \ 264 -e 't loop' \ 265 \ 266 -e '# Repeatedly replace "A", "B", or "C" separators, within each' \ 267 -e '# version prefix, with " 0 ", " 1 " and " 2 ", respectively.' \ 268 -e '# - "16B01 RC1 :OTP_R16B01_RC1" => "16 1 01 RC1 :OTP_R16B01_RC1"' \ 269 -e '# - "16B03 :OTP_R16B03" => "16 1 03 :OTP_R16B03"' \ 270 -e ':loop2' \ 271 -e 's/^(.*[0-9]+)A([^:]*) :/\1 0 \2 :/' \ 272 -e 's/^(.*[0-9]+)B([^:]*) :/\1 1 \2 :/' \ 273 -e 's/^(.*[0-9]+)C([^:]*) :/\1 2 \2 :/' \ 274 -e 't loop2' \ 275 \ 276 -e '# Repeatedly replace space-release candidate infixes, within' \ 277 -e '# each version prefix, with a leading zero followed by' \ 278 -e '# the candidate number.' \ 279 -e '# - "16 1 01 RC1 :OTP_R16B01_RC1" => "16 1 01 0 1 :OTP_R16B01_RC1"' \ 280 -e '# - "19 0 rc1 :OTP-19.0-rc1" => "19 0 0 1 :OTP-19.0-rc1"' \ 281 -e '# - "19 0 rc2 :OTP-19.0-rc2" => "19 0 0 2 :OTP-19.0-rc2"' \ 282 -e ':loop3' \ 283 -e 's/^([^:]* )(rc|RC)([0-9]+)(( [^:]*)?) :/\10 \3\4 :/' \ 284 -e 't loop3' \ 285 \ 286 -e '# Repeatedly prefix single digits, within each version prefix,' \ 287 -e '# with leading zeroes.' \ 288 -e '# - "16 1 01 0 1 :OTP_R16B01_RC1" => "16 01 01 00 01 :OTP_R16B01_RC1"' \ 289 -e '# - "16 1 03 :OTP_R16B03" => "16 01 03 :OTP_R16B03"' \ 290 -e '# - "17 0 :OTP-17.0" => "17 00 :OTP-17.0"' \ 291 -e '# - "17 3 1 :OTP-17.3.1" => "17 03 01 :OTP-17.3.1"' \ 292 -e '# - "19 0 0 1 :OTP-19.0-rc1" => "19 00 00 01 :OTP-19.0-rc.1"' \ 293 -e '# - "19 0 0 2 :OTP-19.0-rc2" => "19 00 00 02 :OTP-19.0-rc.2"' \ 294 -e ':loop4' \ 295 -e 's/^([^:]*[^0-9:])([0-9])(([^0-9][^:]*)?) :/\10\2\3 :/' \ 296 -e 't loop4' \ 297 \ 298 -e '# Suffix each version prefix with 00 as to not compare ':' with a number.' \ 299 -e '# - "16 01 01 00 01 :OTP_R16B01_RC1" => "16 01 01 00 01 00 :OTP_R16B01_RC1"' \ 300 -e '# - "16 01 03 :OTP_R16B03" => "16 01 03 00 :OTP_R16B03"' \ 301 -e '# - "17 00 :OTP-17.0"" => "17 00 00 :OTP-17.0"' \ 302 -e '# - "17 03 01 :OTP-17.3.1" => "17 03 01 00 :OTP-17.3.1"' \ 303 -e '# - "19 00 00 01 :OTP-19.0-rc.1" => "19 00 00 01 00 :OTP-19.0-rc.1"' \ 304 -e '# - "19 00 00 02 :OTP-19.0-rc.2" => "19 00 00 02 00 :OTP-19.0-rc.2"' \ 305 -e 's/^([^:]+) :/\1 00 :/' \ 306 \ 307 | LC_ALL=C sort -n \ 308 | cut -d':' -f2- 309} 310 311get_tarball_releases() { 312 tmp="$(mktemp "$TMP_DIR"/kerl.XXXXXX)" 313 if [ 200 = "$(\curl -qsL --output "$tmp" --write-out '%{http_code}' $ERLANG_DOWNLOAD_URL/)" ]; then 314 sed $SED_OPT \ 315 -e 's/^.*<[aA] [hH][rR][eE][fF]=\"otp_src_([-0-9A-Za-z_.]+)\.tar\.gz\">.*$/\1/' \ 316 -e '/^R1|^[0-9]/!d' "$tmp" \ 317 | sed -e 's/^R\(.*\)/\1:R\1/' \ 318 | sed -e 's/^\([^\:]*\)$/\1-z:\1/' \ 319 | sort | cut -d: -f2 320 rm "$tmp" 321 return 0 322 fi 323 rm "$tmp" 324 exit 1 325} 326 327update_checksum_file() { 328 if [ "$KERL_BUILD_BACKEND" = 'git' ]; then 329 return 0 330 else 331 echo 'Getting checksum file from erlang.org...' 332 curl -f -L -o "$KERL_DOWNLOAD_DIR"/MD5 "$ERLANG_DOWNLOAD_URL"/MD5 || exit 1 333 fi 334} 335 336ensure_checksum_file() { 337 if [ ! -s "$KERL_DOWNLOAD_DIR"/MD5 ]; then 338 update_checksum_file 339 fi 340} 341 342check_releases() { 343 if [ ! -f "$KERL_BASE_DIR"/otp_releases ]; then 344 get_releases >"$KERL_BASE_DIR"/otp_releases 345 fi 346} 347 348is_valid_release() { 349 check_releases 350 while read -r rel; do 351 if [ "$1" = "$rel" ]; then 352 return 0 353 fi 354 done <"$KERL_BASE_DIR"/otp_releases 355 return 1 356} 357 358assert_valid_release() { 359 if ! is_valid_release "$1"; then 360 echo "$1 is not a valid Erlang/OTP release" 361 exit 1 362 fi 363 return 0 364} 365 366get_release_from_name() { 367 if [ -f "$KERL_BASE_DIR"/otp_builds ]; then 368 while read -r l; do 369 rel=$(echo "$l" | cut -d, -f1) 370 name=$(echo "$l" | cut -d, -f2) 371 if [ "$name" = "$1" ]; then 372 echo "$rel" 373 return 0 374 fi 375 done <"$KERL_BASE_DIR"/otp_builds 376 fi 377 return 1 378} 379 380get_newest_valid_release() { 381 check_releases 382 383 rel=$(tail -1 "$KERL_BASE_DIR"/otp_releases) 384 385 if [ -n "$rel" ]; then 386 echo "$rel" 387 return 0 388 fi 389 390 return 1 391} 392 393is_valid_installation() { 394 if [ -f "$KERL_BASE_DIR"/otp_installations ]; then 395 while read -r l; do 396 name=$(echo "$l" | cut -d' ' -f1) 397 path=$(echo "$l" | cut -d' ' -f2) 398 if [ "$name" = "$1" ] || [ "$path" = "$1" ]; then 399 if [ -f "$path"/activate ]; then 400 return 0 401 fi 402 fi 403 done <"$KERL_BASE_DIR"/otp_installations 404 fi 405 return 1 406} 407 408assert_valid_installation() { 409 if ! is_valid_installation "$1"; then 410 echo "$1 is not a kerl-managed Erlang/OTP installation" 411 exit 1 412 fi 413 return 0 414} 415 416assert_build_name_unused() { 417 if [ -f "$KERL_BASE_DIR"/otp_builds ]; then 418 while read -r l; do 419 name=$(echo "$l" | cut -d, -f2) 420 if [ "$name" = "$1" ]; then 421 echo "There's already a build named $1" 422 exit 1 423 fi 424 done <"$KERL_BASE_DIR"/otp_builds 425 fi 426} 427 428_check_required_pkgs() { 429 has_dpkg=$(command -v dpkg) 430 has_rpm=$(command -v rpm) 431 if [ -n "$has_dpkg" ] || [ -n "$has_rpm" ]; then 432 # found either dpkg or rpm (or maybe even both!) 433 if [ -n "$has_dpkg" ] && [ -n "$has_rpm" ]; then 434 echo 'WARNING: You appear to have BOTH rpm and dpkg. This is very strange. No package checks done.' 435 elif [ -n "$has_dpkg" ]; then 436 _check_dpkg 437 elif [ -n "$has_rpm" ]; then 438 _check_rpm 439 fi 440 fi 441} 442 443_dpkg_is_installed() { 444 # gratefully stolen from 445 # https://superuser.com/questions/427318/test-if-a-package-is-installed-in-apt 446 # returns 0 (true) if found, 1 otherwise 447 dpkg-query -Wf'${db:Status-abbrev}' "$1" 2>/dev/null | \grep -q '^i' 448} 449 450_check_dpkg() { 451 required=' 452libssl-dev 453make 454automake 455autoconf 456libncurses5-dev 457gcc 458' 459 for pkg in $required; do 460 if ! _dpkg_is_installed "$pkg"; then 461 echo "WARNING: It appears that a required development package '$pkg' is not installed." 462 fi 463 done 464} 465 466_rpm_is_installed() { 467 rpm --quiet -q "$1" >/dev/null 2>&1 468} 469 470_check_rpm() { 471 required=' 472openssl-devel 473make 474automake 475autoconf 476ncurses-devel 477gcc 478' 479 for pkg in $required; do 480 if ! _rpm_is_installed "$pkg"; then 481 echo "WARNING: It appears a required development package '$pkg' is not installed." 482 fi 483 done 484} 485 486do_git_build() { 487 assert_build_name_unused "$3" 488 489 GIT=$(printf '%s' "$1" | $MD5SUM | cut -d ' ' -f $MD5SUM_FIELD) 490 mkdir -p "$KERL_GIT_DIR" || exit 1 491 cd "$KERL_GIT_DIR" || exit 1 492 echo "Checking out Erlang/OTP git repository from $1..." 493 if [ ! -d "$GIT" ]; then 494 if ! git clone -q --mirror "$1" "$GIT" >/dev/null 2>&1; then 495 echo 'Error mirroring remote git repository' 496 exit 1 497 fi 498 fi 499 cd "$GIT" || exit 1 500 if ! git remote update --prune >/dev/null 2>&1; then 501 echo 'Error updating remote git repository' 502 exit 1 503 fi 504 505 rm -Rf "${KERL_BUILD_DIR:?}/$3" 506 mkdir -p "$KERL_BUILD_DIR/$3" || exit 1 507 cd "$KERL_BUILD_DIR/$3" || exit 1 508 if ! git clone -l "$KERL_GIT_DIR/$GIT" otp_src_git >/dev/null 2>&1; then 509 echo 'Error cloning local git repository' 510 exit 1 511 fi 512 cd otp_src_git || exit 1 513 if ! git checkout "$2" >/dev/null 2>&1; then 514 if ! git checkout -b "$2" "$2" >/dev/null 2>&1; then 515 echo 'Could not checkout specified version' 516 rm -Rf "${KERL_BUILD_DIR:?}/$3" 517 exit 1 518 fi 519 fi 520 if [ ! -x otp_build ]; then 521 echo 'Not a valid Erlang/OTP repository' 522 rm -Rf "${KERL_BUILD_DIR:?}/$3" 523 exit 1 524 fi 525 echo "Building Erlang/OTP $3 from git, please wait..." 526 if [ -z "$KERL_BUILD_AUTOCONF" ]; then 527 KERL_USE_AUTOCONF=1 528 fi 529 _do_build 'git' "$3" 530 echo "Erlang/OTP $3 from git has been successfully built" 531 list_add builds git,"$3" 532} 533 534get_otp_version() { 535 echo "$1" | sed $SED_OPT -e 's/R?([0-9]{1,2}).+/\1/' 536} 537 538get_perl_version() { 539 if assert_perl; then 540 # This is really evil but it's portable and it works. Don't @ me bro 541 perl -e 'print int(($] - 5)*1000)' 542 else 543 echo 'FATAL: could not find perl which is required to compile Erlang.' 544 exit 1 545 fi 546} 547 548assert_perl() { 549 perl_loc=$(command -v perl) 550 if [ -z "$perl_loc" ]; then 551 return 1 552 else 553 # 0 to bash is "true" because of Unix exit code conventions 554 return 0 555 fi 556} 557 558get_javac_version() { 559 java_loc=$(command -v javac) 560 if [ -z "$java_loc" ]; then 561 # Java's not installed, so just return 0 562 0 563 else 564 javaout=$(javac -version 2>&1) 565 echo "$javaout" | cut -d' ' -f2 | cut -d. -f2 566 fi 567} 568 569show_configuration_warnings() { 570 # $1 is logfile 571 # $2 is section header (E.g. "APPLICATIONS DISABLED") 572 # Find the row number for the section we are looking for 573 INDEX=$(\grep -n -m1 "$2" "$1" | cut -d: -f1) 574 575 # If there are no warnings, the section won't appear in the log 576 if [ -n "$INDEX" ]; then 577 # Skip the section header, find the end line and skip it 578 # then print the results indented 579 tail -n +$((INDEX+3)) "$1" | \ 580 sed -n '1,/\*/p' | \ 581 awk -F: -v logfile="$1" -v section="$2" \ 582 'BEGIN { printf "%s (See: %s)\n", section, logfile } 583 /^[^\*]/ { print " *", $0 } 584 END { print "" } ' 585 fi 586} 587 588show_logfile() { 589 echo "$1" 590 tail "$2" 591 echo 592 echo "Please see $2 for full details." 593} 594 595maybe_patch() { 596 # $1 = OS platform e.g., Darwin, etc 597 # $2 = OTP release 598 599 release=$(get_otp_version "$2") 600 case "$1" in 601 Darwin) 602 maybe_patch_darwin "$release" 603 # Catalina and clang require a "no-weaks-import" flag during build 604 maybe_patch_catalina "$release" "$2" 605 maybe_patch_bigsur "$release" 606 ;; 607 SunOS) 608 maybe_patch_sunos "$release" 609 ;; 610 *) 611 ;; 612 esac 613 614 maybe_patch_all "$release" 615} 616 617maybe_patch_all() { 618 perlver=$(get_perl_version) 619 if [ "$perlver" -ge 22 ]; then 620 case "$1" in 621 14) 622 apply_r14_beam_makeops_patch >>"$LOGFILE" 623 ;; 624 15) 625 apply_r15_beam_makeops_patch >>"$LOGFILE" 626 ;; 627 *) 628 ;; 629 esac 630 fi 631 632 # Are we building docs? 633 if [ -n "$KERL_BUILD_DOCS" ]; then 634 if [ "$1" -le 16 ]; then 635 javaver=$(get_javac_version) 636 if [ "$javaver" -ge 8 ]; then 637 apply_javadoc_linting_patch >>"$LOGFILE" 638 fi 639 fi 640 fi 641 642 # Maybe apply zlib patch 643 if [ "$1" -ge 17 ] && [ "$1" -le 19 ]; then 644 apply_zlib_patch >> "$LOGFILE" 645 fi 646} 647 648maybe_patch_darwin() { 649 # Reminder: $1 = OTP release version 650 if [ "$1" -le 14 ]; then 651 CFLAGS='-DERTS_DO_INCL_GLB_INLINE_FUNC_DEF' 652 apply_darwin_compiler_patch >>"$LOGFILE" 653 elif [ "$1" -eq 16 ]; then 654 apply_r16_wx_ptr_patch >>"$LOGFILE" 655 elif [ "$1" -ge 17 ] && [ "$1" -le 19 ]; then 656 apply_wx_ptr_patch >>"$LOGFILE" 657 elif [ "$1" -ge 21 ] && [ "$1" -le 23 ]; then 658 apply_in6addr_test_patch >> "$LOGFILE" 659 KERL_USE_AUTOCONF=1 660 fi 661} 662 663maybe_patch_catalina() { 664 clang_version=$(/usr/bin/clang --version | head -1 | awk '{print $4}') 665 command_line_tools_version=$(xcode-select -v | awk '{print $3}' | sed 's/.$//') 666 release="$1" 667 otp_version="$2" 668 669 if is_osx_catalina && \ 670 [[ "$release" -lt 23 ]] && \ 671 compare_sem_version $otp_version "<" "22.3.1" && \ 672 compare_sem_version $clang_version ">" "11.4" && \ 673 [[ "$command_line_tools_version" -le 2373 ]]; then 674 apply_catalina_no_weak_imports_patch >>"$LOGFILE" 675 KERL_USE_AUTOCONF=1 676 fi 677} 678 679is_osx_catalina() { 680 [[ $(uname -r) == "19"* ]] 681} 682 683compare_sem_version() { 684 version=$1 685 operator=$2 686 baseline=$3 687 688 case $operator in 689 '<') 690 [[ $(printf "$version\n$baseline" | sort --version-sort | head -n 1) != "$baseline" ]] 691 ;; 692 ('>' | "==") 693 [[ $(printf "$version\n$baseline" | sort --version-sort | head -n 1) == "$baseline" ]] 694 ;; 695 esac 696} 697 698apply_catalina_no_weak_imports_patch() { 699 patch -p1 <<'_END_PATCH' 700diff --git a/erts/configure.in b/erts/configure.in 701index 3ba8216a19..d7cebc5ebc 100644 702--- a/erts/configure.in 703+++ b/erts/configure.in 704@@ -926,20 +926,16 @@ dnl for now that is the way we do it. 705 USER_LD=$LD 706 USER_LDFLAGS="$LDFLAGS" 707 LD='$(CC)' 708+ 709 case $host_os in 710- darwin*) 711- saved_LDFLAGS="$LDFLAGS" 712- LDFLAGS="$LDFLAGS -Wl,-no_weak_imports" 713- AC_TRY_LINK([],[], 714- [ 715- LD_MAY_BE_WEAK=no 716- ], 717- [ 718- LD_MAY_BE_WEAK=yes 719- LDFLAGS="$saved_LDFLAGS" 720- ]);; 721- *) 722- LD_MAY_BE_WEAK=no;; 723+ darwin19*) 724+ # Disable stack checking to avoid crashing with a segment fault 725+ # in macOS Catalina. 726+ AC_MSG_NOTICE([Turning off stack check on macOS 10.15 (Catalina)]) 727+ CFLAGS="-Wno-error=implicit-function-declaration -fno-stack-check $CFLAGS" 728+ ;; 729+ *) 730+ ;; 731 esac 732 733 AC_SUBST(LD) 734_END_PATCH 735} 736 737# https://github.com/erlang/otp/commit/f1044ef9e35da26f276b8127640e177d67aade6a.diff 738maybe_patch_bigsur() { 739 release="$1" 740 if is_osx_bigsur && \ 741 [[ "$release" -lt 24 ]]; then 742 apply_bigsur_bypass_version_check >>"$LOGFILE" 743 KERL_USE_AUTOCONF=1 744 fi 745} 746 747is_osx_bigsur() { 748 [[ $(uname -r) == "20"* ]] 749} 750 751apply_bigsur_bypass_version_check() { 752 if [ -f make/configure.in ]; then 753 echo "Bypassing version check in make/configure.in for Big Sur" 754 sed -i '' 's/\(#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > $int_macosx_version\)/\1 \&\& false/' make/configure.in 755 elif [ -f configure.in ]; then 756 echo "Bypassing version check in configure.in for Big Sur" 757 sed -i '' 's/\(#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > $int_macosx_version\)/\1 \&\& false/' configure.in 758 echo "Removng no_weak_imports from LDFLAGS in erts/configure.in for Big Sur" 759 sed -i '' 's/LDFLAGS="$LDFLAGS -Wl,-no_weak_imports"//' erts/configure.in 760 fi 761} 762 763maybe_patch_sunos() { 764 if [ "$1" -le 14 ]; then 765 apply_solaris_networking_patch >>"$LOGFILE" 766 fi 767} 768 769do_normal_build() { 770 assert_valid_release "$1" 771 assert_build_name_unused "$2" 772 FILENAME="" 773 download "$1" 774 mkdir -p "$KERL_BUILD_DIR/$2" || exit 1 775 if [ ! -d "$KERL_BUILD_DIR/$2/$FILENAME" ]; then 776 echo 'Extracting source code' 777 UNTARDIRNAME="$KERL_BUILD_DIR/$2/$FILENAME-kerluntar-$$" 778 rm -rf "$UNTARDIRNAME" 779 mkdir -p "$UNTARDIRNAME" || exit 1 780 # github tarballs have a directory in the form of "otp[_-]TAGNAME" 781 # Ericsson tarballs have the classic otp_src_RELEASE pattern 782 # Standardize on Ericsson format because that's what the rest of the script expects 783 (cd "$UNTARDIRNAME" && tar xzf "$KERL_DOWNLOAD_DIR/$FILENAME".tar.gz && cp -rfp ./* "$KERL_BUILD_DIR/$2/otp_src_$1") 784 rm -rf "$UNTARDIRNAME" 785 fi 786 787 echo "Building Erlang/OTP $1 ($2), please wait..." 788 _do_build "$1" "$2" 789 echo "Erlang/OTP $1 ($2) has been successfully built" 790 list_add builds "$1,$2" 791} 792 793_flags() { 794 # We used to munge the LD and DED flags for clang 9/10 shipped with 795 # High Sierra (macOS 10.13), Mojave (macOS 10.14) and Catalina 796 # (macOS 10.15) 797 # 798 # As of OTP 20.1 that is (apparently) no longer necessary and 799 # in OTP 24 breaks stuff. See thread and comment here: 800 # https://github.com/erlang/otp/issues/4821#issuecomment-845914942 801 case "$KERL_SYSTEM" in 802 Darwin) 803 # Make sure we don't overwrite stuff that someone who 804 # knows better than us set. 805 if [ -z "$CC" ]; then 806 CC='clang' 807 fi 808 809 CFLAGS="$CFLAGS" CC="$CC" "$@" 810 ;; 811 *) 812 CFLAGS="$CFLAGS" "$@" 813 ;; 814 esac 815} 816 817_do_build() { 818 case "$KERL_SYSTEM" in 819 Darwin) 820 # Ensure that the --enable-darwin-64bit flag is set on all macOS 821 # That way even on older Erlangs we get 64 bit Erlang builds 822 # macOS has been mandatory 64 bit for a while 823 if ! echo "$KERL_CONFIGURE_OPTIONS" | \grep 'darwin-64bit' >/dev/null 2>&1; then 824 KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS "--enable-darwin-64bit 825 fi 826 827 # Attempt to use brew to discover if and where openssl has been 828 # installed unless the user has already explictly set it. 829 830 if ! echo "$KERL_CONFIGURE_OPTIONS" | \grep 'with-ssl' >/dev/null 2>&1; then 831 whichbrew=$(command -v brew) 832 if [ -n "$whichbrew" ] && [ -x "$whichbrew" ]; then 833 brew_prefix=$(brew --prefix openssl@1.1) 834 if [ -n "$brew_prefix" ] && [ -d "$brew_prefix" ]; then 835 KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS "--with-ssl=$brew_prefix 836 fi 837 fi 838 fi 839 ;; 840 Linux) 841 # we are going to check here to see if the Linux uses dpkg or rpms 842 # 843 # this is a "best effort" attempt to discover if a Linux has the 844 # packages needed to build Erlang. We will always assume the user 845 # knows better than us and are going to go ahead and try to build 846 # Erlang anyway. But at least it will be a clear warning to the 847 # user if a build fails. 848 _check_required_pkgs 849 ;; 850 *) 851 ;; 852 esac 853 854 if [ -n "$KERL_BUILD_DOCS" ]; then 855 KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS --prefix=$KERL_BUILD_DIR/$2/release_$1" 856 fi 857 858 ERL_TOP="$KERL_BUILD_DIR/$2/otp_src_$1" 859 cd "$ERL_TOP" || exit 1 860 LOGFILE="$KERL_BUILD_DIR/$2/otp_build_$1.log" 861 862 # Set configuation flags given applications white/black lists 863 if [ -n "$KERL_CONFIGURE_APPLICATIONS" ]; then 864 for app in $KERL_CONFIGURE_APPLICATIONS; do 865 case "$KERL_CONFIGURE_OPTIONS" in 866 *"--with-$app"*) 867 echo "Option '--with-$app' in KERL_CONFIGURE_OPTIONS is superfluous" ;; 868 *) 869 KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS --with-$app" ;; 870 esac 871 done 872 fi 873 if [ -n "$KERL_CONFIGURE_DISABLE_APPLICATIONS" ]; then 874 for app in $KERL_CONFIGURE_DISABLE_APPLICATIONS; do 875 case "$KERL_CONFIGURE_OPTIONS" in 876 *"--without-$app"*) 877 echo "Option '--without-$app' in KERL_CONFIGURE_OPTIONS is superfluous" ;; 878 *) 879 KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS --without-$app" ;; 880 esac 881 done 882 fi 883 884 # Check to see if configuration options need to be stored or have changed 885 TMPOPT="${TMP_DIR}/kerloptions.$$" 886 echo "$CFLAGS" >"$TMPOPT" 887 echo "$KERL_CONFIGURE_OPTIONS" >>"$TMPOPT" 888 SUM=$($MD5SUM "$TMPOPT" | cut -d ' ' -f $MD5SUM_FIELD) 889 # Check for a .kerl_config.md5 file 890 if [ -e ./"$KERL_CONFIG_STORAGE_FILENAME".md5 ]; then 891 # Compare our current options to the saved ones 892 read -r OLD_SUM <./"$KERL_CONFIG_STORAGE_FILENAME".md5 893 if [ "$SUM" != "$OLD_SUM" ]; then 894 echo 'Configure options have changed. Reconfiguring...' 895 rm -f configure 896 mv "$TMPOPT" ./"$KERL_CONFIG_STORAGE_FILENAME" 897 echo "$SUM" >./"$KERL_CONFIG_STORAGE_FILENAME".md5 898 else 899 # configure options are the same 900 rm -f "$TMPOPT" 901 fi 902 else 903 # no file exists, so write one 904 mv "$TMPOPT" .kerl_config 905 echo "$SUM" >.kerl_config.md5 906 fi 907 908 # Don't apply patches to "custom" git builds. We have no idea if they will apply 909 # cleanly or not. 910 if [ "$1" != 'git' ]; then 911 maybe_patch "$KERL_SYSTEM" "$1" 912 fi 913 if [ -n "$KERL_USE_AUTOCONF" ]; then 914 # shellcheck disable=SC2086 915 ./otp_build autoconf $KERL_CONFIGURE_OPTIONS >>"$LOGFILE" 2>&1 && \ 916 _flags ./otp_build configure $KERL_CONFIGURE_OPTIONS >>"$LOGFILE" 2>&1 917 else 918 # shellcheck disable=SC2086 919 _flags ./otp_build configure $KERL_CONFIGURE_OPTIONS >>"$LOGFILE" 2>&1 920 921 fi 922 if echo "$KERL_CONFIGURE_OPTIONS" | \grep -- '--enable-native-libs' >/dev/null 2>&1; then 923 make clean >>"$LOGFILE" 2>&1 924 # shellcheck disable=SC2086 925 if ! _flags ./otp_build configure $KERL_CONFIGURE_OPTIONS >>"$LOGFILE" 2>&1; then 926 show_logfile 'Configure failed.' "$LOGFILE" 927 list_remove builds "$1 $2" 928 exit 1 929 fi 930 fi 931 932 for SECTION in 'APPLICATIONS DISABLED' \ 933 'APPLICATIONS INFORMATION' \ 934 'DOCUMENTATION INFORMATION'; do 935 show_configuration_warnings "$LOGFILE" "$SECTION" 936 done 937 938 if [ -n "$KERL_CONFIGURE_APPLICATIONS" ]; then 939 \find ./lib -maxdepth 1 -type d -exec touch -f {}/SKIP \; 940 for app in $KERL_CONFIGURE_APPLICATIONS; do 941 if ! rm ./lib/"$app"/SKIP; then 942 echo "Couldn't prepare '$app' application for building" 943 list_remove builds "$1 $2" 944 exit 1 945 fi 946 done 947 fi 948 if [ -n "$KERL_CONFIGURE_DISABLE_APPLICATIONS" ]; then 949 for app in $KERL_CONFIGURE_DISABLE_APPLICATIONS; do 950 if ! touch -f ./lib/"$app"/SKIP; then 951 echo "Couldn't disable '$app' application for building" 952 exit 1 953 fi 954 done 955 fi 956 957 # shellcheck disable=SC2086 958 if ! _flags ./otp_build boot -a $KERL_CONFIGURE_OPTIONS >>"$LOGFILE" 2>&1; then 959 show_logfile 'Build failed.' "$LOGFILE" 960 list_remove builds "$1 $2" 961 exit 1 962 fi 963 if [ -n "$KERL_BUILD_DOCS" ]; then 964 echo 'Building docs...' 965 release=$(get_otp_version "$2") 966 if ! make docs "DOC_TARGETS=$KERL_DOC_TARGETS" >>"$LOGFILE" 2>&1; then 967 show_logfile 'Building docs failed.' "$LOGFILE" 968 list_remove builds "$1 $2" 969 exit 1 970 fi 971 if ! make release_docs "DOC_TARGETS=$KERL_DOC_TARGETS" "RELEASE_ROOT=$KERL_BUILD_DIR/$2/release_$1" >>"$LOGFILE" 2>&1; then 972 show_logfile 'Release of docs failed.' "$LOGFILE" 973 list_remove builds "$1 $2" 974 exit 1 975 fi 976 fi 977 rm -f "$LOGFILE" 978 ERL_TOP="$ERL_TOP" ./otp_build release -a "$KERL_BUILD_DIR/$2/release_$1" >/dev/null 2>&1 979 cd "$KERL_BUILD_DIR/$2/release_$1" || exit 1 980 ./Install $INSTALL_OPT "$KERL_BUILD_DIR/$2/release_$1" >/dev/null 2>&1 981 if [ -n "$KERL_BUILD_DEBUG_VM" ]; then 982 echo "Also building Erlang/OTP $1 ($2) debug VM, please wait..." 983 cd $ERL_TOP/erts/emulator || exit 1 984 make debug ERL_TOP=$ERL_TOP >>"$LOGFILE" 2>&1 985 fi 986} 987 988do_install() { 989 if ! rel=$(get_release_from_name "$1"); then 990 echo "No build named $1" 991 exit 1 992 fi 993 if ! is_valid_install_path "$2"; then 994 exit 1 995 fi 996 mkdir -p "$2" || exit 1 997 absdir=$(cd "$2" && pwd) 998 echo "Installing Erlang/OTP $rel ($1) in $absdir..." 999 ERL_TOP="$KERL_BUILD_DIR/$1/otp_src_$rel" 1000 cd "$ERL_TOP" || exit 1 1001 if ! (ERL_TOP="$ERL_TOP" ./otp_build release -a "$absdir" >/dev/null 2>&1 && 1002 cd "$absdir" && ./Install $INSTALL_OPT "$absdir" >/dev/null 2>&1); then 1003 echo "Couldn't install Erlang/OTP $rel ($1) in $absdir" 1004 exit 1 1005 fi 1006 BEAM_DEBUG_SMP=$(\find . -name beam.debug.smp) 1007 if [ "$BEAM_DEBUG_SMP" != "" ]; then 1008 ERL_CHILD_SETUP_DEBUG=$(\find . -name erl_child_setup.debug) 1009 echo "Also installing Erlang/OTP $rel ($1) debug VM in $absdir..." 1010 cp $BEAM_DEBUG_SMP $absdir/erts-*/bin/ 1011 cp $ERL_CHILD_SETUP_DEBUG $absdir/erts-*/bin/ 1012 cp bin/cerl $absdir/bin 1013 fi 1014 list_add installations "$1 $absdir"; 1015 cat <<ACTIVATE >"$absdir"/activate 1016#!/bin/sh 1017# credits to virtualenv 1018kerl_deactivate() { 1019 if [ -n "\$_KERL_SAVED_ERL_AFLAGS" ]; then 1020 ERL_AFLAGS="\$_KERL_SAVED_ERL_AFLAGS" 1021 export ERL_AFLAGS 1022 unset _KERL_SAVED_ERL_AFLAGS 1023 fi 1024 if [ -n "\$_KERL_PATH_REMOVABLE" ]; then 1025 # shellcheck disable=SC2001 1026 PATH="\$(echo "\$PATH" | sed -e "s#\$_KERL_PATH_REMOVABLE:##")" 1027 export PATH 1028 unset _KERL_PATH_REMOVABLE 1029 fi 1030 if [ -n "\$_KERL_MANPATH_REMOVABLE" ]; then 1031 # shellcheck disable=SC2001 1032 MANPATH="\$(echo "\$MANPATH" | sed -e "s#\$_KERL_MANPATH_REMOVABLE:##")" 1033 export MANPATH 1034 unset _KERL_MANPATH_REMOVABLE 1035 fi 1036 if [ -n "\$_KERL_SAVED_REBAR_PLT_DIR" ]; then 1037 REBAR_PLT_DIR="\$_KERL_SAVED_REBAR_PLT_DIR" 1038 export REBAR_PLT_DIR 1039 unset _KERL_SAVED_REBAR_PLT_DIR 1040 fi 1041 if [ -n "\$_KERL_ACTIVE_DIR" ]; then 1042 unset _KERL_ACTIVE_DIR 1043 fi 1044 if [ -n "\$_KERL_SAVED_PS1" ]; then 1045 PS1="\$_KERL_SAVED_PS1" 1046 export PS1 1047 unset _KERL_SAVED_PS1 1048 fi 1049 if [ -n "\$_KERL_DOCSH_DOT_ERLANG" ]; then 1050 rm "\$HOME/.erlang" 1051 unset _KERL_DOCSH_DOT_ERLANG 1052 fi 1053 if [ -n "\$_KERL_DOCSH_USER_DEFAULT" ]; then 1054 unset DOCSH_USER_DEFAULT 1055 unset _KERL_DOCSH_USER_DEFAULT 1056 fi 1057 if [ -n "\$_KERL_ERL_CALL_REMOVABLE" ]; then 1058 # shellcheck disable=SC2001 1059 PATH="\$(echo "\$PATH" | sed -e "s#\$_KERL_ERL_CALL_REMOVABLE:##")" 1060 export PATH 1061 unset _KERL_ERL_CALL_REMOVABLE 1062 fi 1063 if [ -n "\$BASH" ] || [ -n "\$ZSH_VERSION" ]; then 1064 hash -r 1065 fi 1066 if [ ! "\$1" = "nondestructive" ]; then 1067 unset -f kerl_deactivate 1068 fi 1069 unset KERL_ENABLE_PROMPT 1070 unset KERL_PROMPT_FORMAT 1071} 1072kerl_deactivate nondestructive 1073 1074_KERL_SAVED_REBAR_PLT_DIR="\$REBAR_PLT_DIR" 1075export _KERL_SAVED_REBAR_PLT_DIR 1076_KERL_PATH_REMOVABLE="$absdir/bin" 1077PATH="\${_KERL_PATH_REMOVABLE}:\$PATH" 1078export PATH _KERL_PATH_REMOVABLE 1079_KERL_MANPATH_REMOVABLE="$absdir/lib/erlang/man:$absdir/man" 1080MANPATH="\${_KERL_MANPATH_REMOVABLE}:\$MANPATH" 1081export MANPATH _KERL_MANPATH_REMOVABLE 1082REBAR_PLT_DIR="$absdir" 1083export REBAR_PLT_DIR 1084_KERL_ACTIVE_DIR="$absdir" 1085export _KERL_ACTIVE_DIR 1086_KERL_ERL_CALL_REMOVABLE=\$(\\find $absdir -type d -wholename "*erl_interface*/bin") 1087PATH="\${_KERL_ERL_CALL_REMOVABLE}:\$PATH" 1088export PATH _KERL_ERL_CALL_REMOVABLE 1089# https://twitter.com/mononcqc/status/877544929496629248 1090export _KERL_SAVED_ERL_AFLAGS=" \$ERL_AFLAGS" 1091kernel_history=\$(echo "\$ERL_AFLAGS" | \\grep 'kernel shell_history' || true) 1092if [ -z "\$kernel_history" ]; then 1093 export ERL_AFLAGS="-kernel shell_history enabled \$ERL_AFLAGS" 1094fi 1095# shellcheck source=/dev/null 1096if [ -f "$KERL_CONFIG" ]; then . "$KERL_CONFIG"; fi 1097if [ -n "\$KERL_ENABLE_PROMPT" ]; then 1098 _KERL_SAVED_PS1="\$PS1" 1099 export _KERL_SAVED_PS1 1100 if [ -n "\$KERL_PROMPT_FORMAT" ]; then 1101 FRMT="\$KERL_PROMPT_FORMAT" 1102 else 1103 FRMT="(%BUILDNAME%)" 1104 fi 1105 PRMPT=\$(echo "\$FRMT" | sed 's^%RELEASE%^$rel^;s^%BUILDNAME%^$1^') 1106 PS1="\$PRMPT\$PS1" 1107 export PS1 1108fi 1109if [ -d "$absdir/lib/docsh" ]; then 1110 export DOCSH_USER_DEFAULT="$absdir/lib/docsh/user_default" 1111 export _KERL_DOCSH_USER_DEFAULT=yes 1112 if [ -f "\$HOME/.erlang" ]; then 1113 # shellcheck disable=SC2153 1114 if [ ! x"\$KERL_DOCSH_DOT_ERLANG" = x'exists' ]; then 1115 echo "Couldn't symlink correct \$HOME/.erlang - file exists - docsh might not work." 1116 echo "Please make sure \$HOME/.erlang contains code" 1117 echo "from $absdir/lib/docsh/dot.erlang" 1118 echo 'and export KERL_DOCSH_DOT_ERLANG=exists to suppress this warning.' 1119 fi 1120 else 1121 ln -s "$absdir/lib/docsh/dot.erlang" "\$HOME/.erlang" 1122 export _KERL_DOCSH_DOT_ERLANG=yes 1123 fi 1124fi 1125if [ -n "\$BASH" ] || [ -n "\$ZSH_VERSION" ]; then 1126 hash -r 1127fi 1128ACTIVATE 1129 1130 cat <<ACTIVATE_FISH >"$absdir"/activate.fish 1131# credits to virtualenv 1132function _kerl_remove_el --description 'remove element from array' 1133 set -l new_array 1134 for el in \$\$argv[1] 1135 if test \$el != \$argv[2] 1136 set new_array \$new_array \$el 1137 end 1138 end 1139 set -x \$argv[1] \$new_array 1140end 1141 1142function kerl_deactivate --description "deactivate erlang environment" 1143 if set --query _KERL_PATH_REMOVABLE 1144 _kerl_remove_el PATH "\$_KERL_PATH_REMOVABLE" 1145 set --erase _KERL_PATH_REMOVABLE 1146 end 1147 if set --query _KERL_MANPATH_REMOVABLE 1148 _kerl_remove_el MANPATH "\$_KERL_MANPATH_REMOVABLE" 1149 set --erase _KERL_MANPATH_REMOVABLE 1150 end 1151 if set --query _KERL_SAVED_REBAR_PLT_DIR 1152 set -x REBAR_PLT_DIR "\$_KERL_SAVED_REBAR_PLT_DIR" 1153 set --erase _KERL_SAVED_REBAR_PLT_DIR 1154 end 1155 if set --query _KERL_ACTIVE_DIR 1156 set --erase _KERL_ACTIVE_DIR 1157 end 1158 if functions --query _kerl_saved_prompt 1159 functions --erase fish_prompt 1160 # functions --copy complains about about fish_prompt already being defined 1161 # so we take a page from virtualenv's book 1162 . ( begin 1163 printf "function fish_prompt\\n\\t#" 1164 functions _kerl_saved_prompt 1165 end | psub ) 1166 functions --erase _kerl_saved_prompt 1167 end 1168 if set --query _KERL_DOCSH_DOT_ERLANG 1169 rm "\$HOME/.erlang" 1170 set --erase _KERL_DOCSH_DOT_ERLANG 1171 end 1172 if set --query _KERL_DOCSH_USER_DEFAULT 1173 set --erase DOCSH_USER_DEFAULT 1174 set --erase _KERL_DOCSH_USER_DEFAULT 1175 end 1176 if set --query _KERL_ERL_CALL_REMOVABLE 1177 _kerl_remove_el PATH "\$_KERL_ERL_CALL_REMOVABLE" 1178 set --erase _KERL_ERL_CALL_REMOVABLE 1179 end 1180 if test "\$argv[1]" != "nondestructive" 1181 functions --erase kerl_deactivate 1182 functions --erase _kerl_remove_el 1183 end 1184end 1185kerl_deactivate nondestructive 1186 1187set -x _KERL_SAVED_REBAR_PLT_DIR "\$REBAR_PLT_DIR" 1188set -x _KERL_PATH_REMOVABLE "$absdir/bin" 1189set -x PATH "\$_KERL_PATH_REMOVABLE" \$PATH 1190set -x _KERL_MANPATH_REMOVABLE "$absdir/lib/erlang/man" "$absdir/man" 1191set -x MANPATH \$MANPATH "\$_KERL_MANPATH_REMOVABLE" 1192set -x REBAR_PLT_DIR "$absdir" 1193set -x _KERL_ACTIVE_DIR "$absdir" 1194set -x _KERL_ERL_CALL_REMOVABLE (\\find "$absdir" -type d -path "*erl_interface*/bin") 1195set -x PATH "\$_KERL_ERL_CALL_REMOVABLE" \$PATH 1196 1197if test -f "$KERL_CONFIG.fish" 1198 source "$KERL_CONFIG.fish" 1199end 1200if set --query KERL_ENABLE_PROMPT 1201 functions --copy fish_prompt _kerl_saved_prompt 1202 function fish_prompt 1203 echo -n "($1)" 1204 _kerl_saved_prompt 1205 end 1206end 1207if test -d "$absdir/lib/docsh" 1208 set -x DOCSH_USER_DEFAULT "$absdir/lib/docsh/user_default" 1209 set -x _KERL_DOCSH_USER_DEFAULT yes 1210 if test -f "\$HOME/.erlang" 1211 if test ! x"\$KERL_DOCSH_DOT_ERLANG" = x"exists" 1212 echo "Couldn't symlink correct \$HOME/.erlang - file exists - docsh might not work." 1213 echo "Please make sure \$HOME/.erlang contains code" 1214 echo "from $absdir/lib/docsh/dot.erlang" 1215 echo "and export KERL_DOCSH_DOT_ERLANG=exists to suppress this warning." 1216 end 1217 else 1218 ln -s "$absdir/lib/docsh/dot.erlang" "\$HOME/.erlang" 1219 set -x _KERL_DOCSH_DOT_ERLANG yes 1220 end 1221end 1222ACTIVATE_FISH 1223 1224 cat <<ACTIVATE_CSH >"$absdir"/activate.csh 1225# This file must be used with "source bin/activate.csh" *from csh*. 1226# You cannot run it directly. 1227 1228alias kerl_deactivate 'test \$?_KERL_SAVED_PATH != 0 && setenv PATH "\$_KERL_SAVED_PATH" && unset _KERL_SAVED_PATH; rehash; test \$?_KERL_SAVED_MANPATH != 0 && setenv MANPATH "\$_KERL_SAVED_MANPATH" && unset _KERL_SAVED_MANPATH; test \$?_KERL_SAVED_REBAR_PLT_DIR != 0 && setenv REBAR_PLT_DIR "\$_KERL_SAVED_REBAR_PLT_DIR" && unset _KERL_SAVED_REBAR_PLT_DIR; test \$?_KERL_ACTIVE_DIR != 0 && unset _KERL_ACTIVE_DIR; test \$?_KERL_DOCSH_USER_DEFAULT != 0 && unsetenv DOCSH_USER_DEFAULT && unset _KERL_DOCSH_USER_DEFAULT; test \$?_KERL_ERL_CALL_REMOVABLE != 0 && unset _KERL_ERL_CALL_REMOVABLE; test \$?_KERL_DOCSH_DOT_ERLANG != 0 && rm "\$HOME/.erlang" && unset _KERL_DOCSH_DOT_ERLANG; test \$?_KERL_SAVED_PROMPT != 0 && set prompt="\$_KERL_SAVED_PROMPT" && unset _KERL_SAVED_PROMPT; test "!:*" != "nondestructive" && unalias deactivate' 1229 1230# Unset irrelevant variables. 1231kerl_deactivate nondestructive 1232 1233if ( \$?REBAR_PLT_DIR ) then 1234 set _KERL_SAVED_REBAR_PLT_DIR = "\$REBAR_PLT_DIR" 1235else 1236 set _KERL_SAVED_REBAR_PLT_DIR="" 1237endif 1238 1239set _KERL_PATH_REMOVABLE = "$absdir/bin" 1240set _KERL_SAVED_PATH = "\$PATH" 1241setenv PATH "\${_KERL_PATH_REMOVABLE}:\$PATH" 1242 1243if ( ! \$?MANPATH ) then 1244 set MANPATH = "" 1245endif 1246set _KERL_MANPATH_REMOVABLE = "$absdir/lib/erlang/man:$absdir/man" 1247set _KERL_SAVED_MANPATH = "\$MANPATH" 1248setenv MANPATH "\${_KERL_MANPATH_REMOVABLE}:\$MANPATH" 1249 1250setenv REBAR_PLT_DIR "$absdir" 1251 1252set _KERL_ACTIVE_DIR = "$absdir" 1253 1254set _KERL_ERL_CALL_REMOVABLE = $(\find "$absdir" -type d -wholename "*erl_interface*/bin") 1255setenv PATH "\${_KERL_ERL_CALL_REMOVABLE}:\$PATH" 1256 1257if ( -f "$KERL_CONFIG.csh" ) then 1258 source "$KERL_CONFIG.csh" 1259endif 1260 1261if ( \$?KERL_ENABLE_PROMPT ) then 1262 set _KERL_SAVED_PROMPT = "\$prompt" 1263 1264 if ( \$?KERL_PROMPT_FORMAT ) then 1265 set FRMT = "\$KERL_PROMPT_FORMAT" 1266 else 1267 set FRMT = "(%BUILDNAME%)" 1268 endif 1269 1270 set PROMPT = \$(echo "\$FRMT" | sed 's^%RELEASE%^$rel^;s^%BUILDNAME%^$1^') 1271 set prompt = "\$PROMPT\$prompt" 1272endif 1273 1274if ( -d "$absdir/lib/docsh" ) then 1275 setenv DOCSH_USER_DEFAULT "$absdir/lib/docsh/user_default" 1276 set _KERL_DOCSH_USER_DEFAULT = "yes" 1277 if ( -f "\$HOME/.erlang" ) then 1278 if ( \$?KERL_DOCSH_DOT_ERLANG == 0 ) then 1279 echo "Couldn't symlink correct \$HOME/.erlang - file exists - docsh might not work." 1280 echo "Please make sure \$HOME/.erlang contains code" 1281 echo "from $absdir/lib/docsh/dot.erlang" 1282 echo "and export KERL_DOCSH_DOT_ERLANG=exists to suppress this warning." 1283 endif 1284 else 1285 ln -s "$absdir/lib/docsh/dot.erlang" "\$HOME/.erlang" 1286 set _KERL_DOCSH_DOT_ERLANG = "yes" 1287 endif 1288endif 1289 1290rehash 1291ACTIVATE_CSH 1292 1293 if [ -n "$KERL_BUILD_DOCS" ]; then 1294 if ! (ERL_TOP="$ERL_TOP" make release_docs "DOC_TARGETS=$KERL_DOC_TARGETS" "RELEASE_ROOT=$absdir" >/dev/null 2>&1); then 1295 echo "Couldn't install docs for Erlang/OTP $rel ($1) in $absdir" 1296 exit 1 1297 fi 1298 else 1299 if [ "$KERL_BUILD_BACKEND" = 'tarball' ]; then 1300 if [ "$rel" != 'git' ]; then 1301 if [ -n "$KERL_INSTALL_MANPAGES" ]; then 1302 echo 'Fetching and installing manpages...' 1303 download_manpages "$rel" 1304 fi 1305 1306 if [ -n "$KERL_INSTALL_HTMLDOCS" ]; then 1307 echo 'Fetching and installing HTML docs...' 1308 download_htmldocs "$rel" 1309 fi 1310 fi 1311 fi 1312 fi 1313 1314 KERL_CONFIG_STORAGE_PATH="$KERL_BUILD_DIR/$1/otp_src_$rel/$KERL_CONFIG_STORAGE_FILENAME" 1315 [ -e "$KERL_CONFIG_STORAGE_PATH" ] && cp "$KERL_CONFIG_STORAGE_PATH" "$absdir/$KERL_CONFIG_STORAGE_FILENAME" 1316 1317 if [ -n "$KERL_BUILD_PLT" ]; then 1318 echo 'Building Dialyzer PLT...' 1319 build_plt "$absdir" 1320 fi 1321 1322 if command -v apk >/dev/null 2>&1; then 1323 # Running on Alpine Linux, assuming non-exotic shell 1324 SHELL_SUFFIX='' 1325 else 1326 PID=$$ 1327 PARENT_PID=$(\ps -p $PID -o ppid=) || exit 1 1328 # shellcheck disable=SC2086 1329 PARENT_CMD=$(\ps -p $PARENT_PID -o ucomm | tail -n 1) 1330 case "$PARENT_CMD" in 1331 fish) 1332 SHELL_SUFFIX='.fish' 1333 ;; 1334 csh) 1335 SHELL_SUFFIX='.csh' 1336 ;; 1337 *) 1338 SHELL_SUFFIX='' 1339 ;; 1340 esac 1341 fi 1342 1343 echo 'You can activate this installation running the following command:' 1344 echo ". $absdir/activate$SHELL_SUFFIX" 1345 echo 'Later on, you can leave the installation typing:' 1346 echo 'kerl_deactivate' 1347} 1348 1349install_docsh() { 1350 REPO_URL=$DOCSH_GITHUB_URL 1351 GIT=$(printf '%s' $REPO_URL | $MD5SUM | cut -d' ' -f $MD5SUM_FIELD) 1352 BUILDNAME="$1" 1353 DOCSH_DIR="$KERL_BUILD_DIR/$BUILDNAME/docsh" 1354 DOCSH_REF='0.7.1' 1355 ACTIVE_PATH="$2" 1356 1357 OTP_VERSION=$(get_otp_version "$1") 1358 # This has to be updated with docsh updates 1359 DOCSH_SUPPORTED='^1[9]\|2[01]$' 1360 if ! echo "$OTP_VERSION" | \grep "$DOCSH_SUPPORTED" >/dev/null 2>&1; then 1361 echo "Erlang/OTP version $OTP_VERSION not supported by docsh (does not match regex $DOCSH_SUPPORTED)" 1362 exit 1 1363 fi 1364 1365 mkdir -p "$KERL_GIT_DIR" || exit 1 1366 cd "$KERL_GIT_DIR" || exit 1 1367 echo "Checking out docsh git repository from $REPO_URL..." 1368 if [ ! -d "$GIT" ]; then 1369 if ! git clone -q --mirror "$REPO_URL" "$GIT" >/dev/null 2>&1; then 1370 echo 'Error mirroring remote git repository' 1371 exit 1 1372 fi 1373 fi 1374 cd "$GIT" || exit 1 1375 if ! git remote update --prune >/dev/null 2>&1; then 1376 echo 'Error updating remote git repository' 1377 exit 1 1378 fi 1379 1380 rm -Rf "$DOCSH_DIR" 1381 mkdir -p "$DOCSH_DIR" || exit 1 1382 cd "$DOCSH_DIR" || exit 1 1383 if ! git clone -l "$KERL_GIT_DIR/$GIT" "$DOCSH_DIR" >/dev/null 2>&1; then 1384 echo 'Error cloning local git repository' 1385 exit 1 1386 fi 1387 cd "$DOCSH_DIR" || exit 1 1388 if ! git checkout "$DOCSH_REF" >/dev/null 2>&1; then 1389 if ! git checkout -b "$DOCSH_REF" "$DOCSH_REF" >/dev/null 2>&1; then 1390 echo 'Could not checkout specified version' 1391 rm -Rf "$DOCSH_DIR" 1392 exit 1 1393 fi 1394 fi 1395 1396 if ! ./rebar3 compile; then 1397 echo 'Could not compile docsh' 1398 rm -Rf "$DOCSH_DIR" 1399 exit 1 1400 fi 1401 1402 ## Install docsh 1403 if [ -f "$ACTIVE_PATH"/lib/docsh ]; then 1404 echo "Couldn't install $ACTIVE_PATH/lib/docsh - the directory already exists" 1405 rm -Rf "$DOCSH_DIR" 1406 exit 1 1407 else 1408 cp -R "$DOCSH_DIR"/_build/default/lib/docsh "$ACTIVE_PATH"/lib/ 1409 fi 1410 ## Prepare dot.erlang for linking as $HOME/.erlang 1411 if [ -f "$ACTIVE_PATH"/lib/docsh/dot.erlang ]; then 1412 echo "Couldn't install $ACTIVE_PATH/lib/docsh/dot.erlang - the file already exists" 1413 rm -Rf "$DOCSH_DIR" 1414 exit 1 1415 else 1416 cat "$DOCSH_DIR"/templates/dot.erlang >"$ACTIVE_PATH"/lib/docsh/dot.erlang 1417 fi 1418 ## Warn if $HOME/.erlang exists 1419 if [ -f "$HOME"/.erlang ]; then 1420 echo "$HOME/.erlang exists - kerl won't be able to symlink a docsh-compatible version." 1421 echo "Please make sure your $HOME/.erlang contains code" 1422 echo "from $ACTIVE_PATH/lib/docsh/dot.erlang" 1423 echo 'and export KERL_DOCSH_DOT_ERLANG=exists to suppress further warnings' 1424 fi 1425 ## Install docsh user_default 1426 if [ -f "$ACTIVE_PATH"/lib/docsh/user_default.beam ]; then 1427 echo "Couldn't install $ACTIVE_PATH/lib/docsh/user_default.beam - the file already exists" 1428 rm -Rf "$DOCSH_DIR" 1429 exit 1 1430 else 1431 erlc -I "$DOCSH_DIR"/include -o "$ACTIVE_PATH"/lib/docsh/ "$DOCSH_DIR"/templates/user_default.erl 1432 fi 1433} 1434 1435download_manpages() { 1436 FILENAME=otp_doc_man_$1.tar.gz 1437 tarball_download "$FILENAME" 1438 echo 'Extracting manpages' 1439 cd "$absdir" && tar xzf "$KERL_DOWNLOAD_DIR/$FILENAME" 1440} 1441 1442download_htmldocs() { 1443 FILENAME=otp_doc_html_"$1".tar.gz 1444 tarball_download "$FILENAME" 1445 echo 'Extracting HTML docs' 1446 (cd "$absdir" && mkdir -p html && tar -C "$absdir"/html -xzf "$KERL_DOWNLOAD_DIR/$FILENAME") 1447} 1448 1449build_plt() { 1450 dialyzerd="$1"/dialyzer 1451 mkdir -p "$dialyzerd" || exit 1 1452 plt="$dialyzerd"/plt 1453 build_log="$dialyzerd"/build.log 1454 dirs=$(\find "$1"/lib -maxdepth 2 -name ebin -type d -exec dirname {} \;) 1455 apps=$(for app in $dirs; do basename "$app" | cut -d- -f1 ; done | \grep -Ev 'erl_interface|jinterface' | xargs echo) 1456 # shellcheck disable=SC2086 1457 "$1"/bin/dialyzer --output_plt "$plt" --build_plt --apps $apps >>"$build_log" 2>&1 1458 status=$? 1459 if [ $status -eq 0 ] || [ $status -eq 2 ]; then 1460 echo "Done building $plt" 1461 return 0 1462 else 1463 echo "Error building PLT, see $build_log for details" 1464 return 1 1465 fi 1466} 1467 1468do_plt() { 1469 ACTIVE_PATH="$1" 1470 if [ -n "$ACTIVE_PATH" ]; then 1471 plt="$ACTIVE_PATH"/dialyzer/plt 1472 if [ -f "$plt" ]; then 1473 echo 'Dialyzer PLT for the active installation is:' 1474 echo "$plt" 1475 return 0 1476 else 1477 echo 'There is no Dialyzer PLT for the active installation' 1478 return 1 1479 fi 1480 else 1481 echo 'No Erlang/OTP installation is currently active' 1482 return 2 1483 fi 1484} 1485 1486print_buildopts() { 1487 buildopts="$1/$KERL_CONFIG_STORAGE_FILENAME" 1488 if [ -f "$buildopts" ]; then 1489 echo 'The build options for the active installation are:' 1490 cat "$buildopts" 1491 return 0 1492 else 1493 echo 'The build options for the active installation are not available.' 1494 return 1 1495 fi 1496} 1497 1498do_deploy() { 1499 if [ -z "$1" ]; then 1500 echo 'No host given' 1501 exit 1 1502 fi 1503 host="$1" 1504 1505 assert_valid_installation "$2" 1506 rel="$(get_name_from_install_path "$2")" 1507 path="$2" 1508 remotepath="$path" 1509 1510 if [ -n "$3" ]; then 1511 remotepath="$3" 1512 fi 1513 1514 # shellcheck disable=SC2086 1515 if ! ssh $KERL_DEPLOY_SSH_OPTIONS "$host" true >/dev/null 2>&1; then 1516 echo "Couldn't ssh to $host" 1517 exit 1 1518 fi 1519 1520 echo "Cloning Erlang/OTP $rel ($path) to $host ($remotepath) ..." 1521 1522 # shellcheck disable=SC2086 1523 if ! rsync -aqz -e "ssh $KERL_DEPLOY_SSH_OPTIONS" $KERL_DEPLOY_RSYNC_OPTIONS "$path/" "$host:$remotepath/"; then 1524 echo "Couldn't rsync Erlang/OTP $rel ($path) to $host ($remotepath)" 1525 exit 1 1526 fi 1527 1528 # shellcheck disable=SC2086,SC2029 1529 if ! ssh $KERL_DEPLOY_SSH_OPTIONS "$host" "cd \"$remotepath\" && env ERL_TOP=\"\$(pwd)\" ./Install $INSTALL_OPT \"\$(pwd)\" >/dev/null 2>&1"; then 1530 echo "Couldn't install Erlang/OTP $rel to $host ($remotepath)" 1531 exit 1 1532 fi 1533 1534 # shellcheck disable=SC2086,SC2029 1535 if ! ssh $KERL_DEPLOY_SSH_OPTIONS "$host" "cd \"$remotepath\" && sed -i -e \"s#$path#\"\$(pwd)\"#g\" activate"; then 1536 echo "Couldn't completely install Erlang/OTP $rel to $host ($remotepath)" 1537 exit 1 1538 fi 1539 1540 echo "On $host, you can activate this installation running the following command:" 1541 echo ". $remotepath/activate" 1542 echo 'Later on, you can leave the installation typing:' 1543 echo 'kerl_deactivate' 1544} 1545 1546 1547# Quoted from https://github.com/mkropat/sh-realpath 1548# LICENSE: MIT 1549 1550realpath() { 1551 canonicalize_path "$(resolve_symlinks "$1")" 1552} 1553 1554resolve_symlinks() { 1555 _resolve_symlinks "$1" 1556} 1557 1558_resolve_symlinks() { 1559 _assert_no_path_cycles "$@" || return 1560 1561 if path=$(readlink -- "$1"); then 1562 dir_context=$(dirname -- "$1") 1563 _resolve_symlinks "$(_prepend_dir_context_if_necessary "$dir_context" "$path")" "$@" 1564 else 1565 printf '%s\n' "$1" 1566 fi 1567} 1568 1569_prepend_dir_context_if_necessary() { 1570 if [ "$1" = . ]; then 1571 printf '%s\n' "$2" 1572 else 1573 _prepend_path_if_relative "$1" "$2" 1574 fi 1575} 1576 1577_prepend_path_if_relative() { 1578 case "$2" in 1579 /* ) printf '%s\n' "$2" ;; 1580 * ) printf '%s\n' "$1/$2" ;; 1581 esac 1582} 1583 1584_assert_no_path_cycles() { 1585 target=$1 1586 shift 1587 1588 for path in "$@"; do 1589 if [ "$path" = "$target" ]; then 1590 return 1 1591 fi 1592 done 1593} 1594 1595canonicalize_path() { 1596 if [ -d "$1" ]; then 1597 _canonicalize_dir_path "$1" 1598 else 1599 _canonicalize_file_path "$1" 1600 fi 1601} 1602 1603_canonicalize_dir_path() { 1604 (cd "$1" 2>/dev/null && pwd -P) 1605} 1606 1607_canonicalize_file_path() { 1608 dir=$(dirname -- "$1") 1609 file=$(basename -- "$1") 1610 (cd "$dir" 2>/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file") 1611} 1612 1613# END QUOTE 1614 1615is_valid_install_path() { 1616 # don't allow installs into .erlang because 1617 # it's a special configuration file location for OTP 1618 if [ "$(basename -- "$1")" = '.erlang' ]; then 1619 echo 'ERROR: You cannot install a build into .erlang. (It is a special configuration file location for OTP.)' 1620 return 1 1621 fi 1622 1623 candidate=$(realpath "$1") 1624 canonical_home=$(realpath "$HOME") 1625 canonical_base_dir=$(realpath "$KERL_BASE_DIR") 1626 1627 # don't allow installs into home directory 1628 if [ "$candidate" = "$canonical_home" ]; then 1629 echo "ERROR: You cannot install a build into $HOME. It's a really bad idea." 1630 return 1 1631 fi 1632 1633 # don't install into our base directory either. 1634 if [ "$candidate" = "$canonical_base_dir" ]; then 1635 echo "ERROR: You cannot install a build into $KERL_BASE_DIR." 1636 return 1 1637 fi 1638 1639 INSTALLED_NAME=$(get_name_from_install_path "$candidate") 1640 if [ -n "$INSTALLED_NAME" ]; then 1641 echo "ERROR: Installation ($INSTALLED_NAME) already registered for this location ($1)" 1642 return 1 1643 fi 1644 1645 # if the install directory exists, 1646 # do not allow installs into a directory that is not empty 1647 if [ -e "$1" ]; then 1648 if [ ! -d "$1" ]; then 1649 echo "ERROR: $1 is not a directory." 1650 return 1 1651 else 1652 count=$(\find "$1" | wc -l) 1653 if [ "$count" -ne 1 ]; then 1654 echo "ERROR: $1 does not appear to be an empty directory." 1655 return 1 1656 fi 1657 fi 1658 fi 1659 1660 return 0 1661} 1662 1663maybe_remove() { 1664 candidate=$(realpath "$1") 1665 canonical_home=$(realpath "$HOME") 1666 1667 if [ "$candidate" = "$canonical_home" ]; then 1668 echo "WARNING: You cannot remove an install from $HOME; it's your home directory." 1669 return 0 1670 fi 1671 1672 ACTIVE_PATH="$(get_active_path)" 1673 if [ "$candidate" = "$ACTIVE_PATH" ]; then 1674 echo 'ERROR: You cannot delete the active installation. Deactivate it first.' 1675 exit 1 1676 fi 1677 1678 rm -Rf "$1" 1679} 1680 1681list_print() { 1682 if [ -f "$KERL_BASE_DIR/otp_$1" ]; then 1683 if [ "$(\wc -l "$KERL_BASE_DIR/otp_$1")" != '0' ]; then 1684 cat "$KERL_BASE_DIR/otp_$1" 1685 return 0 1686 fi 1687 fi 1688 echo "There are no $1 available" 1689} 1690 1691list_add() { 1692 if [ -f "$KERL_BASE_DIR/otp_$1" ]; then 1693 while read -r l; do 1694 if [ "$l" = "$2" ]; then 1695 return 1 1696 fi 1697 done <"$KERL_BASE_DIR/otp_$1" 1698 echo "$2" >>"$KERL_BASE_DIR/otp_$1" || exit 1 1699 else 1700 echo "$2" >"$KERL_BASE_DIR/otp_$1" || exit 1 1701 fi 1702} 1703 1704list_remove() { 1705 if [ -f "$KERL_BASE_DIR/otp_$1" ]; then 1706 sed $SED_OPT -i -e "/^.*$2$/d" "$KERL_BASE_DIR/otp_$1" || exit 1 1707 fi 1708} 1709 1710list_has() { 1711 if [ -f "$KERL_BASE_DIR/otp_$1" ]; then 1712 \grep "$2" "$KERL_BASE_DIR/otp_$1" >/dev/null 2>&1 && return 0 1713 fi 1714 return 1 1715} 1716 1717path_usage() { 1718 echo "usage: $0 path [<install_name>]" 1719} 1720 1721list_usage() { 1722 echo "usage: $0 list <releases|builds|installations>" 1723} 1724 1725delete_usage() { 1726 echo "usage: $0 delete <build|installation> <build_name or path>" 1727} 1728 1729cleanup_usage() { 1730 echo "usage: $0 cleanup <build_name|all>" 1731} 1732 1733update_usage() { 1734 echo "usage: $0 update releases" 1735} 1736 1737get_active_path() { 1738 if [ -n "$_KERL_ACTIVE_DIR" ]; then 1739 echo "$_KERL_ACTIVE_DIR" 1740 fi 1741 return 0 1742} 1743 1744get_name_from_install_path() { 1745 if [ -f "$KERL_BASE_DIR"/otp_installations ]; then 1746 \grep -m1 -E "$1$" "$KERL_BASE_DIR"/otp_installations | cut -d' ' -f1 1747 fi 1748 return 0 1749} 1750 1751get_install_path_from_name() { 1752 if [ -f "$KERL_BASE_DIR"/otp_installations ]; then 1753 \grep -m1 -E "$1$" "$KERL_BASE_DIR"/otp_installations | cut -d' ' -f2 1754 fi 1755 return 0 1756} 1757 1758do_active() { 1759 ACTIVE_PATH="$(get_active_path)" 1760 if [ -n "$ACTIVE_PATH" ]; then 1761 echo 'The current active installation is:' 1762 echo "$ACTIVE_PATH" 1763 return 0 1764 else 1765 echo 'No Erlang/OTP installation is currently active' 1766 return 1 1767 fi 1768} 1769 1770make_filename() { 1771 release=$(get_otp_version "$1") 1772 if [ "$release" -ge 17 ]; then 1773 echo "OTP-$1" 1774 else 1775 echo "OTP_$1" 1776 fi 1777} 1778 1779download() { 1780 mkdir -p "$KERL_DOWNLOAD_DIR" || exit 1 1781 if [ "$KERL_BUILD_BACKEND" = 'git' ]; then 1782 FILENAME=$(make_filename "$1") 1783 github_download "$1" "$FILENAME".tar.gz 1784 else 1785 FILENAME="otp_src_$1" 1786 tarball_download "$FILENAME".tar.gz 1787 fi 1788} 1789 1790github_download() { 1791 tarball_file="$KERL_DOWNLOAD_DIR/$2" 1792 tarball_url="$OTP_GITHUB_URL/archive/$2" 1793 prebuilt_url="$OTP_GITHUB_URL/releases/download/OTP-$1/otp_src_$1.tar.gz" 1794 if curl --silent --location --fail -I $prebuilt_url > /dev/null; then 1795 tarball_url=$prebuilt_url 1796 unset KERL_USE_AUTOCONF 1797 fi 1798 # if the file doesn't exist or the file has no size 1799 if [ ! -s $tarball_file ]; then 1800 echo "Downloading $1 to $KERL_DOWNLOAD_DIR..." 1801 curl -f -L -o $tarball_file $tarball_url || exit 1 1802 else 1803 # If the downloaded tarball was corrupted due to interruption while 1804 # downloading. 1805 if ! gunzip -t $tarball_file 2>/dev/null; then 1806 echo "$tarball_file corrupted and redownloading..." 1807 rm -rf $tarball_file 1808 curl -f -L -o $tarball_file $tarball_url || exit 1 1809 fi 1810 fi 1811} 1812 1813tarball_download() { 1814 if [ ! -s "$KERL_DOWNLOAD_DIR/$1" ]; then 1815 echo "Downloading $1 to $KERL_DOWNLOAD_DIR" 1816 curl -f -L -o "$KERL_DOWNLOAD_DIR/$1" "$ERLANG_DOWNLOAD_URL/$1" || exit 1 1817 update_checksum_file 1818 fi 1819 ensure_checksum_file 1820 echo 'Verifying archive checksum...' 1821 SUM="$($MD5SUM "$KERL_DOWNLOAD_DIR/$1" | cut -d' ' -f $MD5SUM_FIELD)" 1822 ORIG_SUM="$(\grep -F "$1" "$KERL_DOWNLOAD_DIR"/MD5 | cut -d' ' -f2)" 1823 if [ "$SUM" != "$ORIG_SUM" ]; then 1824 echo "Checksum error, check the files in $KERL_DOWNLOAD_DIR" 1825 exit 1 1826 fi 1827 echo "Checksum verified ($SUM)" 1828} 1829 1830apply_solaris_networking_patch() { 1831 patch -p1 <<_END_PATCH 1832--- otp-a/erts/emulator/drivers/common/inet_drv.c 1833+++ otp-b/erts/emulator/drivers/common/inet_drv.c 1834@@ -4166,16 +4166,7 @@ 1835 break; 1836 1837 case INET_IFOPT_HWADDR: { 1838-#ifdef SIOCGIFHWADDR 1839- if (ioctl(desc->s, SIOCGIFHWADDR, (char *)&ifreq) < 0) 1840- break; 1841- buf_check(sptr, s_end, 1+2+IFHWADDRLEN); 1842- *sptr++ = INET_IFOPT_HWADDR; 1843- put_int16(IFHWADDRLEN, sptr); sptr += 2; 1844- /* raw memcpy (fix include autoconf later) */ 1845- sys_memcpy(sptr, (char*)(&ifreq.ifr_hwaddr.sa_data), IFHWADDRLEN); 1846- sptr += IFHWADDRLEN; 1847-#elif defined(SIOCGENADDR) 1848+#if defined(SIOCGENADDR) 1849 if (ioctl(desc->s, SIOCGENADDR, (char *)&ifreq) < 0) 1850 break; 1851 buf_check(sptr, s_end, 1+2+sizeof(ifreq.ifr_enaddr)); 1852_END_PATCH 1853} 1854 1855apply_darwin_compiler_patch() { 1856 patch -p0 <<_END_PATCH 1857--- erts/emulator/beam/beam_bp.c.orig 2011-10-03 13:12:07.000000000 -0500 1858+++ erts/emulator/beam/beam_bp.c 2013-10-04 13:42:03.000000000 -0500 1859@@ -496,7 +496,8 @@ 1860 } 1861 1862 /* bp_hash */ 1863-ERTS_INLINE Uint bp_sched2ix() { 1864+#ifndef ERTS_DO_INCL_GLB_INLINE_FUNC_DEF 1865+ERTS_GLB_INLINE Uint bp_sched2ix() { 1866 #ifdef ERTS_SMP 1867 ErtsSchedulerData *esdp; 1868 esdp = erts_get_scheduler_data(); 1869@@ -505,6 +506,7 @@ 1870 return 0; 1871 #endif 1872 } 1873+#endif 1874 static void bp_hash_init(bp_time_hash_t *hash, Uint n) { 1875 Uint size = sizeof(bp_data_time_item_t)*n; 1876 Uint i; 1877--- erts/emulator/beam/beam_bp.h.orig 2011-10-03 13:12:07.000000000 -0500 1878+++ erts/emulator/beam/beam_bp.h 2013-10-04 13:42:08.000000000 -0500 1879@@ -144,7 +144,19 @@ 1880 #define ErtsSmpBPUnlock(BDC) 1881 #endif 1882 1883-ERTS_INLINE Uint bp_sched2ix(void); 1884+ERTS_GLB_INLINE Uint bp_sched2ix(void); 1885+ 1886+#ifdef ERTS_DO_INCL_GLB_INLINE_FUNC_DEF 1887+ERTS_GLB_INLINE Uint bp_sched2ix() { 1888+#ifdef ERTS_SMP 1889+ ErtsSchedulerData *esdp; 1890+ esdp = erts_get_scheduler_data(); 1891+ return esdp->no - 1; 1892+#else 1893+ return 0; 1894+#endif 1895+} 1896+#endif 1897 1898 #ifdef ERTS_SMP 1899 #define bp_sched2ix_proc(p) ((p)->scheduler_data->no - 1) 1900_END_PATCH 1901} 1902 1903# javadoc 8 includes always-enabled document linting which causes 1904# documentation builds to fail on older OTP releases. 1905apply_javadoc_linting_patch() { 1906 # The _END_PATCH token is quoted below to disable parameter substitution 1907 patch -p0 <<'_END_PATCH' 1908--- lib/jinterface/doc/src/Makefile.orig 2016-05-23 14:34:48.000000000 -0500 1909+++ lib/jinterface/doc/src/Makefile 2016-05-23 14:35:48.000000000 -0500 1910@@ -142,7 +142,7 @@ 1911 rm -f errs core *~ 1912 1913 jdoc:$(JAVA_SRC_FILES) 1914- (cd ../../java_src;$(JAVADOC) -sourcepath . -d $(JAVADOC_DEST) \ 1915+ (cd ../../java_src;$(JAVADOC) -Xdoclint:none -sourcepath . -d $(JAVADOC_DEST) \ 1916 -windowtitle $(JAVADOC_TITLE) $(JAVADOC_PKGS)) 1917 1918 man: 1919_END_PATCH 1920} 1921 1922# perl 5.24 fatalizes the warning this causes 1923apply_r14_beam_makeops_patch() { 1924 patch -p0 <<'_END_PATCH' 1925--- erts/emulator/utils/beam_makeops.orig 2016-05-23 21:40:42.000000000 -0500 1926+++ erts/emulator/utils/beam_makeops 2016-05-23 21:41:08.000000000 -0500 1927@@ -1576,7 +1576,7 @@ 1928 if $min_window{$key} > $min_window; 1929 1930 pop(@{$gen_transform{$key}}) 1931- if defined @{$gen_transform{$key}}; # Fail 1932+ if defined $gen_transform{$key}; # Fail 1933 my(@prefix) = (&make_op($comment), &make_op('', 'try_me_else', &tr_code_len(@code))); 1934 unshift(@code, @prefix); 1935 push(@{$gen_transform{$key}}, @code, &make_op('', 'fail')); 1936_END_PATCH 1937} 1938 1939# https://github.com/erlang/otp/commit/21ca6d3a137034f19862db769a5b7f1c5528dbc4.diff 1940apply_r15_beam_makeops_patch() { 1941 patch -p1 <<'_END_PATCH' 1942--- a/erts/emulator/utils/beam_makeops 1943+++ b/erts/emulator/utils/beam_makeops 1944@@ -1711,7 +1711,7 @@ sub tr_gen_to { 1945 my $prev_last; 1946 $prev_last = pop(@{$gen_transform{$key}}) 1947- if defined @{$gen_transform{$key}}; # Fail 1948+ if defined $gen_transform{$key}; # Fail 1949 1950 if ($prev_last && !is_instr($prev_last, 'fail')) { 1951 error("Line $line: A previous transformation shadows '$orig_transform'"); 1952_END_PATCH 1953} 1954 1955#https://github.com/erlang/otp/commit/a64c4d806fa54848c35632114585ad82b98712e8.diff 1956apply_wx_ptr_patch() { 1957 patch -p1 <<'_END_PATCH' 1958diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp 1959index 0d2da5d4a79..8118136d30e 100644 1960--- a/lib/wx/c_src/wxe_impl.cpp 1961+++ b/lib/wx/c_src/wxe_impl.cpp 1962@@ -666,7 +666,7 @@ void * WxeApp::getPtr(char * bp, wxeMemEnv *memenv) { 1963 throw wxe_badarg(index); 1964 } 1965 void * temp = memenv->ref2ptr[index]; 1966- if((index < memenv->next) && ((index == 0) || (temp > NULL))) 1967+ if((index < memenv->next) && ((index == 0) || (temp != (void *)NULL))) 1968 return temp; 1969 else { 1970 throw wxe_badarg(index); 1971@@ -678,7 +678,7 @@ void WxeApp::registerPid(char * bp, ErlDrvTermData pid, wxeMemEnv * memenv) { 1972 if(!memenv) 1973 throw wxe_badarg(index); 1974 void * temp = memenv->ref2ptr[index]; 1975- if((index < memenv->next) && ((index == 0) || (temp > NULL))) { 1976+ if((index < memenv->next) && ((index == 0) || (temp != (void *) NULL))) { 1977 ptrMap::iterator it; 1978 it = ptr2ref.find(temp); 1979 if(it != ptr2ref.end()) { 1980_END_PATCH 1981} 1982 1983apply_r16_wx_ptr_patch() { 1984 patch -p1 <<'_END_PATCH' 1985diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp 1986index cc9bcc995..1b1912630 100644 1987--- a/lib/wx/c_src/wxe_impl.cpp 1988+++ b/lib/wx/c_src/wxe_impl.cpp 1989@@ -757,7 +757,7 @@ void * WxeApp::getPtr(char * bp, wxeMemEnv *memenv) { 1990 throw wxe_badarg(index); 1991 } 1992 void * temp = memenv->ref2ptr[index]; 1993- if((index < memenv->next) && ((index == 0) || (temp > NULL))) 1994+ if((index < memenv->next) && ((index == 0) || (temp != (void *)NULL))) 1995 return temp; 1996 else { 1997 throw wxe_badarg(index); 1998@@ -769,7 +769,7 @@ void WxeApp::registerPid(char * bp, ErlDrvTermData pid, wxeMemEnv * memenv) { 1999 if(!memenv) 2000 throw wxe_badarg(index); 2001 void * temp = memenv->ref2ptr[index]; 2002- if((index < memenv->next) && ((index == 0) || (temp > NULL))) { 2003+ if((index < memenv->next) && ((index == 0) || (temp != (void *)NULL))) { 2004 ptrMap::iterator it; 2005 it = ptr2ref.find(temp); 2006 if(it != ptr2ref.end()) { 2007_END_PATCH 2008} 2009 2010# https://github.com/erlang/otp/commit/e27119948fc6ab28bea81019720bddaac5b655a7.patch 2011apply_zlib_patch() 2012{ 2013 2014 patch -p1 <<'_END_PATCH' 2015diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c 2016index 656de7c49ad..4491d486837 100644 2017--- a/erts/emulator/beam/external.c 2018+++ b/erts/emulator/beam/external.c 2019@@ -1193,6 +1193,7 @@ typedef struct B2TContext_t { 2020 } u; 2021 } B2TContext; 2022 2023+static B2TContext* b2t_export_context(Process*, B2TContext* src); 2024 2025 static uLongf binary2term_uncomp_size(byte* data, Sint size) 2026 { 2027@@ -1225,7 +1226,7 @@ static uLongf binary2term_uncomp_size(byte* data, Sint size) 2028 2029 static ERTS_INLINE int 2030 binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size, 2031- B2TContext* ctx) 2032+ B2TContext** ctxp, Process* p) 2033 { 2034 byte *bytes = data; 2035 Sint size = data_size; 2036@@ -1239,8 +1240,8 @@ binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size, 2037 size--; 2038 if (size < 5 || *bytes != COMPRESSED) { 2039 state->extp = bytes; 2040- if (ctx) 2041- ctx->state = B2TSizeInit; 2042+ if (ctxp) 2043+ (*ctxp)->state = B2TSizeInit; 2044 } 2045 else { 2046 uLongf dest_len = (Uint32) get_int32(bytes+1); 2047@@ -1257,16 +1258,26 @@ binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size, 2048 return -1; 2049 } 2050 state->extp = erts_alloc(ERTS_ALC_T_EXT_TERM_DATA, dest_len); 2051- ctx->reds -= dest_len; 2052+ if (ctxp) 2053+ (*ctxp)->reds -= dest_len; 2054 } 2055 state->exttmp = 1; 2056- if (ctx) { 2057+ if (ctxp) { 2058+ /* 2059+ * Start decompression by exporting trap context 2060+ * so we don't have to deal with deep-copying z_stream. 2061+ */ 2062+ B2TContext* ctx = b2t_export_context(p, *ctxp); 2063+ ASSERT(state = &(*ctxp)->b2ts); 2064+ state = &ctx->b2ts; 2065+ 2066 if (erl_zlib_inflate_start(&ctx->u.uc.stream, bytes, size) != Z_OK) 2067 return -1; 2068 2069 ctx->u.uc.dbytes = state->extp; 2070 ctx->u.uc.dleft = dest_len; 2071 ctx->state = B2TUncompressChunk; 2072+ *ctxp = ctx; 2073 } 2074 else { 2075 uLongf dlen = dest_len; 2076@@ -1308,7 +1319,7 @@ erts_binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size 2077 { 2078 Sint res; 2079 2080- if (binary2term_prepare(state, data, data_size, NULL) < 0 || 2081+ if (binary2term_prepare(state, data, data_size, NULL, NULL) < 0 || 2082 (res=decoded_size(state->extp, state->extp + state->extsize, 0, NULL)) < 0) { 2083 2084 if (state->exttmp) 2085@@ -1435,7 +1446,7 @@ static Eterm binary_to_term_int(Process* p, Uint32 flags, Eterm bin, Binary* con 2086 if (ctx->aligned_alloc) { 2087 ctx->reds -= bin_size / 8; 2088 } 2089- if (binary2term_prepare(&ctx->b2ts, bytes, bin_size, ctx) < 0) { 2090+ if (binary2term_prepare(&ctx->b2ts, bytes, bin_size, &ctx, p) < 0) { 2091 ctx->state = B2TBadArg; 2092 } 2093 break; 2094_END_PATCH 2095} 2096 2097# https://github.com/erlang/otp/commit/4b0467c.patch 2098apply_in6addr_test_patch() 2099{ 2100 2101 patch -p1 <<'_END_PATCH' 2102diff --git a/erts/configure.in b/erts/configure.in 2103index caa1ce568b..6ebb3d3a25 100644 2104--- a/erts/configure.in 2105+++ b/erts/configure.in 2106@@ -2191,6 +2191,7 @@ AC_CACHE_CHECK( 2107 #include <sys/types.h> 2108 #include <sys/socket.h> 2109 #include <netinet/in.h> 2110+ #include <stdio.h> 2111 ]], 2112 [[printf("%d", in6addr_any.s6_addr[16]);]] 2113 )], 2114@@ -2214,6 +2215,7 @@ AC_CACHE_CHECK( 2115 #include <sys/types.h> 2116 #include <sys/socket.h> 2117 #include <netinet/in.h> 2118+ #include <stdio.h> 2119 ]], 2120 [[printf("%d", in6addr_loopback.s6_addr[16]);]] 2121 )], 2122_END_PATCH 2123} 2124 2125case "$1" in 2126 version) 2127 echo "$KERL_VERSION" 2128 exit 0 2129 ;; 2130 build) 2131 if [ "$2" = 'git' ]; then 2132 if [ $# -ne 5 ]; then 2133 echo "usage: $0 $1 $2 <git_url> <git_version> <build_name>" 2134 exit 1 2135 fi 2136 do_git_build "$3" "$4" "$5" 2137 else 2138 if [ $# -eq 2 ]; then 2139 do_normal_build "$2" "$2" 2140 elif [ $# -eq 3 ]; then 2141 do_normal_build "$2" "$3" 2142 else 2143 echo "usage: $0 $1 <release> <build_name>" 2144 exit 1 2145 fi 2146 fi 2147 ;; 2148 install) 2149 if [ $# -lt 2 ]; then 2150 echo "usage: $0 $1 <build_name> [directory]" 2151 exit 1 2152 fi 2153 if [ $# -eq 3 ]; then 2154 do_install "$2" "$3" 2155 else 2156 if [ -z "$KERL_DEFAULT_INSTALL_DIR" ]; then 2157 do_install "$2" "$PWD" 2158 else 2159 do_install "$2" "$KERL_DEFAULT_INSTALL_DIR/$2" 2160 fi 2161 fi 2162 ;; 2163 install-docsh) 2164 ACTIVE_PATH="$(get_active_path)" 2165 if [ -n "$ACTIVE_PATH" ]; then 2166 ACTIVE_NAME="$(get_name_from_install_path "$ACTIVE_PATH")" 2167 if [ -z "$ACTIVE_NAME" ]; then 2168 ## TODO: Are git builds installed the usual way 2169 ## or do we need this clause to provide a fallback? 2170 #BUILDNAME="$(basename "$ACTIVE_PATH")" 2171 echo "$ACTIVE_PATH is not a kerl installation" 2172 exit 1 2173 else 2174 BUILDNAME="$ACTIVE_NAME" 2175 fi 2176 install_docsh "$BUILDNAME" "$ACTIVE_PATH" 2177 echo 'Please kerl_deactivate and activate again to enable docsh' 2178 else 2179 echo 'No Erlang/OTP installation is currently active - cannot install docsh' 2180 exit 1 2181 fi 2182 ;; 2183 deploy) 2184 if [ $# -lt 2 ]; then 2185 echo "usage: $0 $1 <[user@]host> [directory] [remote_directory]" 2186 exit 1 2187 fi 2188 if [ $# -eq 4 ]; then 2189 do_deploy "$2" "$3" "$4" 2190 else 2191 if [ $# -eq 3 ]; then 2192 do_deploy "$2" "$3" 2193 else 2194 do_deploy "$2" . 2195 fi 2196 fi 2197 ;; 2198 update) 2199 if [ $# -lt 2 ]; then 2200 update_usage 2201 exit 1 2202 fi 2203 case "$2" in 2204 releases) 2205 rm -f "${KERL_BASE_DIR:?}"/otp_releases 2206 check_releases 2207 echo 'The available releases are:' 2208 list_print releases 2209 ;; 2210 *) 2211 update_usage 2212 exit 1 2213 ;; 2214 esac 2215 ;; 2216 list) 2217 if [ $# -ne 2 ]; then 2218 list_usage 2219 exit 1 2220 fi 2221 case "$2" in 2222 releases) 2223 check_releases 2224 list_print "$2" 2225 echo "Run '$0 update releases' to update this list from erlang.org" 2226 ;; 2227 builds) 2228 list_print "$2" 2229 ;; 2230 installations) 2231 list_print "$2" 2232 ;; 2233 *) 2234 echo "Cannot list $2" 2235 list_usage 2236 exit 1 2237 ;; 2238 esac 2239 ;; 2240 path) 2241 # Usage: 2242 # kerl path 2243 # # Print currently active installation path, else non-zero exit 2244 # kerl path <install> 2245 # Print path to installation with name <install>, else non-zero exit 2246 if [ -z "$2" ]; then 2247 activepath=$(get_active_path) 2248 if [ -z "$activepath" ]; then 2249 echo 'No active kerl-managed erlang installation' 2250 exit 1 2251 fi 2252 echo "$activepath" 2253 else 2254 # There are some possible extensions to this we could 2255 # consider, such as: 2256 # - if 2+ matches: prefer one in a subdir from $PWD 2257 # - prefer $KERL_DEFAULT_INSTALL_DIR 2258 match= 2259 for ins in $(list_print installations | cut -d' ' -f2); do 2260 if [ "$(basename "$ins")" = "$2" ]; then 2261 if [ -z "$match" ]; then 2262 match="$ins" 2263 else 2264 echo 'Error: too many matching installations' >&2 2265 exit 2 2266 fi 2267 fi 2268 done 2269 [ -n "$match" ] && echo "$match" && exit 0 2270 echo 'Error: no matching installation found' >&2 && exit 1 2271 fi 2272 ;; 2273 delete) 2274 if [ $# -ne 3 ]; then 2275 delete_usage 2276 exit 1 2277 fi 2278 case "$2" in 2279 build) 2280 rel="$(get_release_from_name "$3")" 2281 if [ -d "${KERL_BUILD_DIR:?}/$3" ]; then 2282 maybe_remove "${KERL_BUILD_DIR:?}/$3" 2283 else 2284 if [ -z "$rel" ]; then 2285 echo "No build named $3" 2286 exit 1 2287 fi 2288 fi 2289 list_remove "$2"s "$rel,$3" 2290 echo "The $3 build has been deleted" 2291 ;; 2292 installation) 2293 assert_valid_installation "$3" 2294 if [ -d "$3" ]; then 2295 maybe_remove "$3" 2296 else 2297 maybe_remove "$(get_install_path_from_name "$3")" 2298 fi 2299 escaped="$(echo "$3" | \sed $SED_OPT -e 's#/$##' -e 's#\/#\\\/#g')" 2300 list_remove "$2"s "$escaped" 2301 echo "The installation \"$3\" has been deleted" 2302 ;; 2303 *) 2304 echo "Cannot delete $2" 2305 delete_usage 2306 exit 1 2307 ;; 2308 esac 2309 ;; 2310 active) 2311 if ! do_active; then 2312 exit 1; 2313 fi 2314 ;; 2315 plt) 2316 ACTIVE_PATH=$(get_active_path) 2317 if ! do_plt "$ACTIVE_PATH"; then 2318 exit 1; 2319 fi 2320 ;; 2321 status) 2322 echo 'Available builds:' 2323 list_print builds 2324 echo '----------' 2325 echo 'Available installations:' 2326 list_print installations 2327 echo '----------' 2328 if do_active; then 2329 ACTIVE_PATH=$(get_active_path) 2330 if [ -n "$ACTIVE_PATH" ]; then 2331 do_plt "$ACTIVE_PATH" 2332 print_buildopts "$ACTIVE_PATH" 2333 else 2334 echo 'No Erlang/OTP installation is currently active' 2335 exit 1 2336 fi 2337 fi 2338 exit 0 2339 ;; 2340 prompt) 2341 FMT=' (%s)' 2342 if [ -n "$2" ]; then 2343 FMT="$2" 2344 fi 2345 ACTIVE_PATH="$(get_active_path)" 2346 if [ -n "$ACTIVE_PATH" ]; then 2347 ACTIVE_NAME="$(get_name_from_install_path "$ACTIVE_PATH")" 2348 if [ -z "$ACTIVE_NAME" ]; then 2349 VALUE="$(basename "$ACTIVE_PATH")*" 2350 else 2351 VALUE="$ACTIVE_NAME" 2352 fi 2353 # shellcheck disable=SC2059 2354 printf "$FMT" "$VALUE" 2355 fi 2356 exit 0 2357 ;; 2358 cleanup) 2359 if [ $# -ne 2 ]; then 2360 cleanup_usage 2361 exit 1 2362 fi 2363 case "$2" in 2364 all) 2365 echo 'Cleaning up compilation products for ALL builds' 2366 rm -rf "${KERL_BUILD_DIR:?}"/* 2367 rm -rf "${KERL_DOWNLOAD_DIR:?}"/* 2368 rm -rf "${KERL_GIT_DIR:?}"/* 2369 echo "Cleaned up all compilation products under $KERL_BUILD_DIR" 2370 ;; 2371 *) 2372 echo "Cleaning up compilation products for $3" 2373 rm -rf "${KERL_BUILD_DIR:?}/$3" 2374 echo "Cleaned up compilation products for $3 under $KERL_BUILD_DIR" 2375 ;; 2376 esac 2377 ;; 2378 *) 2379 echo "unknown command: $1"; usage; exit 1 2380 ;; 2381esac 2382