2132 lines
65 KiB
Bash
Executable File
2132 lines
65 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
# Copyright (c) 2016-2018 Mark Allen
|
|
# Copyright (c) 2011, 2012 Spawngrid, Inc
|
|
# Copyright (c) 2011 Evax Software <contact(at)evax(dot)org>
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
# THE SOFTWARE.
|
|
|
|
unset ERL_TOP
|
|
|
|
# Make sure CDPATH doesn't affect cd in case path is relative.
|
|
unset CDPATH
|
|
|
|
KERL_VERSION='1.8.3'
|
|
|
|
DOCSH_GITHUB_URL='https://github.com/erszcz/docsh.git'
|
|
ERLANG_DOWNLOAD_URL='https://www.erlang.org/download'
|
|
KERL_CONFIG_STORAGE_FILENAME='.kerl_config'
|
|
|
|
if [ -z "$HOME" ]; then
|
|
# shellcheck disable=SC2016
|
|
echo 'Error: $HOME is empty or not set.' 1>&2
|
|
exit 1
|
|
fi
|
|
|
|
# Default values
|
|
OTP_GITHUB_URL=${OTP_GITHUB_URL:='https://github.com/erlang/otp'}
|
|
KERL_BASE_DIR=${KERL_BASE_DIR:="$HOME"/.kerl}
|
|
KERL_CONFIG=${KERL_CONFIG:="$HOME"/.kerlrc}
|
|
KERL_DOWNLOAD_DIR=${KERL_DOWNLOAD_DIR:="${KERL_BASE_DIR:?}"/archives}
|
|
KERL_BUILD_DIR=${KERL_BUILD_DIR:="${KERL_BASE_DIR:?}"/builds}
|
|
KERL_GIT_DIR=${KERL_GIT_DIR:="${KERL_BASE_DIR:?}"/gits}
|
|
|
|
if [ -n "$OTP_GITHUB_URL" ]; then
|
|
_OGU="$OTP_GITHUB_URL"
|
|
fi
|
|
if [ -n "$KERL_CONFIGURE_OPTIONS" ]; then
|
|
_KCO="$KERL_CONFIGURE_OPTIONS"
|
|
fi
|
|
if [ -n "$KERL_CONFIGURE_APPLICATIONS" ]; then
|
|
_KCA="$KERL_CONFIGURE_APPLICATIONS"
|
|
fi
|
|
if [ -n "$KERL_CONFIGURE_DISABLE_APPLICATIONS" ]; then
|
|
_KCDA="$KERL_CONFIGURE_DISABLE_APPLICATIONS"
|
|
fi
|
|
if [ -n "$KERL_SASL_STARTUP" ]; then
|
|
_KSS="$KERL_SASL_STARTUP"
|
|
fi
|
|
if [ -n "$KERL_DEPLOY_SSH_OPTIONS" ]; then
|
|
_KDSSH="$KERL_DEPLOY_SSH_OPTIONS"
|
|
fi
|
|
if [ -n "$KERL_DEPLOY_RSYNC_OPTIONS" ]; then
|
|
_KDRSYNC="$KERL_DEPLOY_RSYNC_OPTIONS"
|
|
fi
|
|
if [ -n "$KERL_INSTALL_MANPAGES" ]; then
|
|
_KIM="$KERL_INSTALL_MANPAGES"
|
|
fi
|
|
if [ -n "$KERL_INSTALL_HTMLDOCS" ]; then
|
|
_KIHD="$KERL_INSTALL_HTMLDOCS"
|
|
fi
|
|
if [ -n "$KERL_BUILD_PLT" ]; then
|
|
_KBPLT="$KERL_BUILD_PLT"
|
|
fi
|
|
if [ -n "$KERL_BUILD_DOCS" ]; then
|
|
_KBD="$KERL_BUILD_DOCS"
|
|
fi
|
|
if [ -n "$KERL_BUILD_BACKEND" ]; then
|
|
_KBB="$KERL_BUILD_BACKEND"
|
|
fi
|
|
OTP_GITHUB_URL=
|
|
KERL_CONFIGURE_OPTIONS=
|
|
KERL_CONFIGURE_APPLICATIONS=
|
|
KERL_CONFIGURE_DISABLE_APPLICATIONS=
|
|
KERL_SASL_STARTUP=
|
|
KERL_DEPLOY_SSH_OPTIONS=
|
|
KERL_DEPLOY_RSYNC_OPTIONS=
|
|
KERL_INSTALL_MANPAGES=
|
|
KERL_INSTALL_HTMLDOCS=
|
|
KERL_BUILD_PLT=
|
|
KERL_BUILD_DOCS=
|
|
KERL_BUILD_BACKEND=
|
|
|
|
# ensure the base dir exists
|
|
mkdir -p "$KERL_BASE_DIR" || exit 1
|
|
|
|
# source the config file if available
|
|
if [ -f "$KERL_CONFIG" ]; then
|
|
# shellcheck source=/dev/null
|
|
. "$KERL_CONFIG"
|
|
fi
|
|
|
|
if [ -n "$_OGU" ]; then
|
|
OTP_GITHUB_URL="$_OGU"
|
|
fi
|
|
if [ -n "$_KCO" ]; then
|
|
KERL_CONFIGURE_OPTIONS="$_KCO"
|
|
fi
|
|
if [ -n "$_KCA" ]; then
|
|
KERL_CONFIGURE_APPLICATIONS="$_KCA"
|
|
fi
|
|
if [ -n "$_KCDA" ]; then
|
|
KERL_CONFIGURE_DISABLE_APPLICATIONS="$_KCDA"
|
|
fi
|
|
if [ -n "$_KSS" ]; then
|
|
KERL_SASL_STARTUP="$_KSS"
|
|
fi
|
|
if [ -n "$_KDSSH" ]; then
|
|
KERL_DEPLOY_SSH_OPTIONS="$_KDSSH"
|
|
fi
|
|
if [ -n "$_KDRSYNC" ]; then
|
|
KERL_DEPLOY_RSYNC_OPTIONS="$_KDRSYNC"
|
|
fi
|
|
if [ -n "$_KIM" ]; then
|
|
KERL_INSTALL_MANPAGES="$_KIM"
|
|
fi
|
|
if [ -n "$_KIHD" ]; then
|
|
KERL_INSTALL_HTMLDOCS="$_KIHD"
|
|
fi
|
|
if [ -n "$_KBPLT" ]; then
|
|
KERL_BUILD_PLT="$_KBPLT"
|
|
fi
|
|
if [ -n "$_KBD" ]; then
|
|
KERL_BUILD_DOCS="$_KBD"
|
|
fi
|
|
if [ -n "$_KBB" ]; then
|
|
KERL_BUILD_BACKEND="$_KBB"
|
|
fi
|
|
|
|
if [ -z "$KERL_SASL_STARTUP" ]; then
|
|
INSTALL_OPT='-minimal'
|
|
else
|
|
INSTALL_OPT='-sasl'
|
|
fi
|
|
|
|
if [ -z "$KERL_BUILD_BACKEND" ]; then
|
|
KERL_BUILD_BACKEND='tarball'
|
|
else
|
|
KERL_BUILD_BACKEND='git'
|
|
KERL_USE_AUTOCONF=1
|
|
fi
|
|
|
|
KERL_SYSTEM=$(uname -s)
|
|
case "$KERL_SYSTEM" in
|
|
Darwin|FreeBSD|OpenBSD)
|
|
MD5SUM='openssl md5'
|
|
MD5SUM_FIELD=2
|
|
SED_OPT=-E
|
|
CP_OPT=-a
|
|
;;
|
|
*)
|
|
MD5SUM=md5sum
|
|
MD5SUM_FIELD=1
|
|
SED_OPT=-r
|
|
CP_OPT=-pr
|
|
;;
|
|
esac
|
|
|
|
|
|
usage() {
|
|
echo 'kerl: build and install Erlang/OTP'
|
|
echo "usage: $0 <command> [options ...]"
|
|
printf '\n <command> Command to be executed\n\n'
|
|
echo 'Valid commands are:'
|
|
echo ' build Build specified release or git repository'
|
|
echo ' install Install the specified release at the given location'
|
|
echo ' deploy Deploy the specified installation to the given host and location'
|
|
echo ' update Update the list of available releases from your source provider'
|
|
echo ' list List releases, builds and installations'
|
|
echo ' delete Delete builds and installations'
|
|
echo ' install-docsh Install erl shell documentation access extension - docsh'
|
|
echo ' path Print the path of a given installation'
|
|
echo ' active Print the path of the active installation'
|
|
echo ' plt Print Dialyzer PLT path for the active installation'
|
|
echo ' status Print available builds and installations'
|
|
echo ' prompt Print a string suitable for insertion in prompt'
|
|
echo ' cleanup Remove compilation artifacts (use after installation)'
|
|
echo " version Print current version (current: $KERL_VERSION)"
|
|
exit 1
|
|
}
|
|
|
|
if [ $# -eq 0 ]; then usage; fi
|
|
|
|
get_releases() {
|
|
if [ "$KERL_BUILD_BACKEND" = 'git' ]; then
|
|
get_git_releases
|
|
else
|
|
get_tarball_releases
|
|
fi
|
|
}
|
|
|
|
get_git_releases() {
|
|
git ls-remote --tags "$OTP_GITHUB_URL" \
|
|
| grep -E -o 'OTP[_-][^^{}]+' \
|
|
| sed $SED_OPT 's/OTP[_-]//' \
|
|
| sort -n \
|
|
| uniq
|
|
}
|
|
|
|
get_tarball_releases() {
|
|
tmp="$(mktemp /tmp/kerl.XXXXXX)"
|
|
if [ 200 = "$(curl -qsL --output "$tmp" --write-out '%{http_code}' $ERLANG_DOWNLOAD_URL/)" ]; then
|
|
sed $SED_OPT \
|
|
-e 's/^.*<[aA] [hH][rR][eE][fF]=\"otp_src_([-0-9A-Za-z_.]+)\.tar\.gz\">.*$/\1/' \
|
|
-e '/^R1|^[0-9]/!d' "$tmp" \
|
|
| sed -e 's/^R\(.*\)/\1:R\1/' \
|
|
| sed -e 's/^\([^\:]*\)$/\1-z:\1/' \
|
|
| sort | cut -d: -f2
|
|
rm "$tmp"
|
|
return 0
|
|
fi
|
|
rm "$tmp"
|
|
exit 1
|
|
}
|
|
|
|
update_checksum_file() {
|
|
if [ "$KERL_BUILD_BACKEND" = 'git' ]; then
|
|
return 0
|
|
else
|
|
echo 'Getting checksum file from erlang.org...'
|
|
curl -f -L -o "$KERL_DOWNLOAD_DIR"/MD5 "$ERLANG_DOWNLOAD_URL"/MD5 || exit 1
|
|
fi
|
|
}
|
|
|
|
ensure_checksum_file() {
|
|
if [ ! -s "$KERL_DOWNLOAD_DIR"/MD5 ]; then
|
|
update_checksum_file
|
|
fi
|
|
}
|
|
|
|
check_releases() {
|
|
if [ ! -f "$KERL_BASE_DIR"/otp_releases ]; then
|
|
get_releases >"$KERL_BASE_DIR"/otp_releases
|
|
fi
|
|
}
|
|
|
|
is_valid_release() {
|
|
check_releases
|
|
while read -r rel; do
|
|
if [ "$1" = "$rel" ]; then
|
|
return 0
|
|
fi
|
|
done <"$KERL_BASE_DIR"/otp_releases
|
|
return 1
|
|
}
|
|
|
|
assert_valid_release() {
|
|
if ! is_valid_release "$1"; then
|
|
echo "$1 is not a valid Erlang/OTP release"
|
|
exit 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
get_release_from_name() {
|
|
if [ -f "$KERL_BASE_DIR"/otp_builds ]; then
|
|
while read -r l; do
|
|
rel=$(echo "$l" | cut -d, -f1)
|
|
name=$(echo "$l" | cut -d, -f2)
|
|
if [ "$name" = "$1" ]; then
|
|
echo "$rel"
|
|
return 0
|
|
fi
|
|
done <"$KERL_BASE_DIR"/otp_builds
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
get_newest_valid_release() {
|
|
check_releases
|
|
|
|
rel=$(tail -1 "$KERL_BASE_DIR"/otp_releases)
|
|
|
|
if [ ! -z "$rel" ]; then
|
|
echo "$rel"
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
is_valid_installation() {
|
|
if [ -f "$KERL_BASE_DIR"/otp_installations ]; then
|
|
while read -r l; do
|
|
name=$(echo "$l" | cut -d' ' -f1)
|
|
path=$(echo "$l" | cut -d' ' -f2)
|
|
if [ "$name" = "$1" ] || [ "$path" = "$1" ]; then
|
|
if [ -f "$path"/activate ]; then
|
|
return 0
|
|
fi
|
|
fi
|
|
done <"$KERL_BASE_DIR"/otp_installations
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
assert_valid_installation() {
|
|
if ! is_valid_installation "$1"; then
|
|
echo "$1 is not a kerl-managed Erlang/OTP installation"
|
|
exit 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
assert_build_name_unused() {
|
|
if [ -f "$KERL_BASE_DIR"/otp_builds ]; then
|
|
while read -r l; do
|
|
name=$(echo "$l" | cut -d, -f2)
|
|
if [ "$name" = "$1" ]; then
|
|
echo "There's already a build named $1"
|
|
exit 1
|
|
fi
|
|
done <"$KERL_BASE_DIR"/otp_builds
|
|
fi
|
|
}
|
|
|
|
_check_required_pkgs() {
|
|
has_dpkg=$(command -v dpkg)
|
|
has_rpm=$(command -v rpm)
|
|
if [ -n "$has_dpkg" ] || [ -n "$has_rpm" ]; then
|
|
# found either dpkg or rpm (or maybe even both!)
|
|
if [ -n "$has_dpkg" ] && [ -n "$has_rpm" ]; then
|
|
echo 'WARNING: You appear to have BOTH rpm and dpkg. This is very strange. No package checks done.'
|
|
elif [ -n "$has_dpkg" ]; then
|
|
_check_dpkg
|
|
elif [ -n "$has_rpm" ]; then
|
|
_check_rpm
|
|
fi
|
|
fi
|
|
}
|
|
|
|
_dpkg_is_installed() {
|
|
# gratefully stolen from
|
|
# https://superuser.com/questions/427318/test-if-a-package-is-installed-in-apt
|
|
# returns 0 (true) if found, 1 otherwise
|
|
dpkg-query -Wf'${db:Status-abbrev}' "$1" 2>/dev/null | grep -q '^i'
|
|
}
|
|
|
|
_check_dpkg() {
|
|
required='
|
|
libssl-dev
|
|
make
|
|
automake
|
|
autoconf
|
|
libncurses5-dev
|
|
gcc
|
|
'
|
|
for pkg in $required; do
|
|
if ! _dpkg_is_installed "$pkg"; then
|
|
echo "WARNING: It appears that a required development package '$pkg' is not installed."
|
|
fi
|
|
done
|
|
}
|
|
|
|
_rpm_is_installed() {
|
|
rpm --quiet -q "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
_check_rpm() {
|
|
required='
|
|
openssl-devel
|
|
make
|
|
automake
|
|
autoconf
|
|
ncurses-devel
|
|
gcc
|
|
'
|
|
for pkg in $required; do
|
|
if ! _rpm_is_installed "$pkg"; then
|
|
echo "WARNING: It appears a required development package '$pkg' is not installed."
|
|
fi
|
|
done
|
|
}
|
|
|
|
do_git_build() {
|
|
assert_build_name_unused "$3"
|
|
|
|
GIT=$(printf '%s' "$1" | $MD5SUM | cut -d ' ' -f $MD5SUM_FIELD)
|
|
mkdir -p "$KERL_GIT_DIR" || exit 1
|
|
cd "$KERL_GIT_DIR" || exit 1
|
|
echo "Checking out Erlang/OTP git repository from $1..."
|
|
if [ ! -d "$GIT" ]; then
|
|
if ! git clone -q --mirror "$1" "$GIT" >/dev/null 2>&1; then
|
|
echo 'Error mirroring remote git repository'
|
|
exit 1
|
|
fi
|
|
fi
|
|
cd "$GIT" || exit 1
|
|
if ! git remote update --prune >/dev/null 2>&1; then
|
|
echo 'Error updating remote git repository'
|
|
exit 1
|
|
fi
|
|
|
|
rm -Rf "${KERL_BUILD_DIR:?}/$3"
|
|
mkdir -p "$KERL_BUILD_DIR/$3" || exit 1
|
|
cd "$KERL_BUILD_DIR/$3" || exit 1
|
|
if ! git clone -l "$KERL_GIT_DIR/$GIT" otp_src_git >/dev/null 2>&1; then
|
|
echo 'Error cloning local git repository'
|
|
exit 1
|
|
fi
|
|
cd otp_src_git || exit 1
|
|
if ! git checkout "$2" >/dev/null 2>&1; then
|
|
if ! git checkout -b "$2" "$2" >/dev/null 2>&1; then
|
|
echo 'Could not checkout specified version'
|
|
rm -Rf "${KERL_BUILD_DIR:?}/$3"
|
|
exit 1
|
|
fi
|
|
fi
|
|
if [ ! -x otp_build ]; then
|
|
echo 'Not a valid Erlang/OTP repository'
|
|
rm -Rf "${KERL_BUILD_DIR:?}/$3"
|
|
exit 1
|
|
fi
|
|
echo "Building Erlang/OTP $3 from git, please wait..."
|
|
if [ -z "$KERL_BUILD_AUTOCONF" ]; then
|
|
KERL_USE_AUTOCONF=1
|
|
fi
|
|
_do_build 'git' "$3"
|
|
echo "Erlang/OTP $3 from git has been successfully built"
|
|
list_add builds git,"$3"
|
|
}
|
|
|
|
get_otp_version() {
|
|
echo "$1" | sed $SED_OPT -e 's/R?([0-9]{1,2}).+/\1/'
|
|
}
|
|
|
|
get_perl_version() {
|
|
if assert_perl; then
|
|
# This is really evil but it's portable and it works. Don't @ me bro
|
|
perl -e 'print int(($] - 5)*1000)'
|
|
else
|
|
echo 'FATAL: could not find perl which is required to compile Erlang.'
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
assert_perl() {
|
|
perl_loc=$(command -v perl)
|
|
if [ -z "$perl_loc" ]; then
|
|
return 1
|
|
else
|
|
# 0 to bash is "true" because of Unix exit code conventions
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
get_javac_version() {
|
|
java_loc=$(command -v javac)
|
|
if [ -z "$java_loc" ]; then
|
|
# Java's not installed, so just return 0
|
|
0
|
|
else
|
|
javaout=$(javac -version 2>&1)
|
|
echo "$javaout" | cut -d' ' -f2 | cut -d. -f2
|
|
fi
|
|
}
|
|
|
|
show_configuration_warnings() {
|
|
# $1 is logfile
|
|
# $2 is section header (E.g. "APPLICATIONS DISABLED")
|
|
# Find the row number for the section we are looking for
|
|
INDEX=$(grep -n -m1 "$2" "$1" | cut -d: -f1)
|
|
|
|
# If there are no warnings, the section won't appear in the log
|
|
if [ -n "$INDEX" ]; then
|
|
# Skip the section header, find the end line and skip it
|
|
# then print the results indented
|
|
tail -n +$((INDEX+3)) "$1" | \
|
|
sed -n '1,/\*/p' | \
|
|
awk -F: -v logfile="$1" -v section="$2" \
|
|
'BEGIN { printf "%s (See: %s)\n", section, logfile }
|
|
/^[^\*]/ { print " *", $0 }
|
|
END { print "" } '
|
|
fi
|
|
}
|
|
|
|
show_logfile() {
|
|
echo "$1"
|
|
tail "$2"
|
|
echo
|
|
echo "Please see $2 for full details."
|
|
}
|
|
|
|
maybe_patch() {
|
|
# $1 = OS platform e.g., Darwin, etc
|
|
# $2 = OTP release
|
|
|
|
release=$(get_otp_version "$2")
|
|
case "$1" in
|
|
Darwin)
|
|
maybe_patch_darwin "$release"
|
|
;;
|
|
SunOS)
|
|
maybe_patch_sunos "$release"
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
|
|
maybe_patch_all "$release"
|
|
}
|
|
|
|
maybe_patch_all() {
|
|
perlver=$(get_perl_version)
|
|
if [ "$perlver" -ge 22 ]; then
|
|
case "$1" in
|
|
14)
|
|
apply_r14_beam_makeops_patch >>"$LOGFILE"
|
|
;;
|
|
15)
|
|
apply_r15_beam_makeops_patch >>"$LOGFILE"
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
# Are we building docs?
|
|
if [ -n "$KERL_BUILD_DOCS" ]; then
|
|
if [ "$1" -le 16 ]; then
|
|
javaver=$(get_javac_version)
|
|
if [ "$javaver" -ge 8 ]; then
|
|
apply_javadoc_linting_patch >>"$LOGFILE"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Maybe apply zlib patch
|
|
if [ "$1" -ge 17 ] && [ "$1" -le 19 ]; then
|
|
apply_zlib_patch >> "$LOGFILE"
|
|
fi
|
|
}
|
|
|
|
maybe_patch_darwin() {
|
|
# Reminder: $1 = OTP release version
|
|
if [ "$1" -le 14 ]; then
|
|
CFLAGS='-DERTS_DO_INCL_GLB_INLINE_FUNC_DEF'
|
|
apply_darwin_compiler_patch >>"$LOGFILE"
|
|
elif [ "$1" -eq 16 ]; then
|
|
# TODO: Maybe check if clang version == 9
|
|
apply_r16_wx_ptr_patch >>"$LOGFILE"
|
|
elif [ "$1" -ge 17 ] && [ "$1" -le 19 ]; then
|
|
apply_wx_ptr_patch >>"$LOGFILE"
|
|
fi
|
|
}
|
|
|
|
maybe_patch_sunos() {
|
|
if [ "$1" -le 14 ]; then
|
|
apply_solaris_networking_patch >>"$LOGFILE"
|
|
fi
|
|
}
|
|
|
|
do_normal_build() {
|
|
assert_valid_release "$1"
|
|
assert_build_name_unused "$2"
|
|
FILENAME=""
|
|
download "$1"
|
|
mkdir -p "$KERL_BUILD_DIR/$2" || exit 1
|
|
if [ ! -d "$KERL_BUILD_DIR/$2/$FILENAME" ]; then
|
|
echo 'Extracting source code'
|
|
UNTARDIRNAME="$KERL_BUILD_DIR/$2/$FILENAME-kerluntar-$$"
|
|
rm -rf "$UNTARDIRNAME"
|
|
mkdir -p "$UNTARDIRNAME" || exit 1
|
|
# github tarballs have a directory in the form of "otp[_-]TAGNAME"
|
|
# Ericsson tarballs have the classic otp_src_RELEASE pattern
|
|
# Standardize on Ericsson format because that's what the rest of the script expects
|
|
(cd "$UNTARDIRNAME" && tar xzf "$KERL_DOWNLOAD_DIR/$FILENAME".tar.gz && mv -f ./* "$KERL_BUILD_DIR/$2/otp_src_$1")
|
|
rm -rf "$UNTARDIRNAME"
|
|
fi
|
|
|
|
echo "Building Erlang/OTP $1 ($2), please wait..."
|
|
_do_build "$1" "$2"
|
|
echo "Erlang/OTP $1 ($2) has been successfully built"
|
|
list_add builds "$1,$2"
|
|
}
|
|
|
|
_flags() {
|
|
# We need to munge the LD and DED flags for clang 9 shipped with
|
|
# High Sierra (macOS 10.13)
|
|
case "$KERL_SYSTEM" in
|
|
Darwin)
|
|
osver=$(uname -r)
|
|
case "$osver" in
|
|
17*)
|
|
# Make sure we don't overwrite values that someone who
|
|
# knows better than us set.
|
|
if [ -z "$DED_LD" ]; then
|
|
DED_LD='clang'
|
|
fi
|
|
if [ -z "$CC" ]; then
|
|
CC='clang'
|
|
fi
|
|
if [ -z "$DED_LDFLAGS" ]; then
|
|
host=$(./erts/autoconf/config.guess)
|
|
DED_LDFLAGS="-m64 -bundle -bundle_loader ${ERL_TOP}/bin/$host/beam.smp"
|
|
fi
|
|
CFLAGS="$CFLAGS" DED_LD="$DED_LD" CC="$CC" DED_LDFLAGS="$DED_LDFLAGS" "$@"
|
|
;;
|
|
*)
|
|
CFLAGS="$CFLAGS" "$@"
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
CFLAGS="$CFLAGS" "$@"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
_do_build() {
|
|
case "$KERL_SYSTEM" in
|
|
Darwin)
|
|
OSVERSION=$(uname -r)
|
|
|
|
# Ensure that the --enable-darwin-64bit flag is set on all macOS
|
|
# That way even on older Erlangs we get 64 bit Erlang builds
|
|
# macOS has been mandatory 64 bit for a while
|
|
if ! echo "$KERL_CONFIGURE_OPTIONS" | grep 'darwin-64bit' >/dev/null 2>&1; then
|
|
KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS "--enable-darwin-64bit
|
|
fi
|
|
|
|
case "$OSVERSION" in
|
|
17*|16*|15*)
|
|
if ! echo "$KERL_CONFIGURE_OPTIONS" | grep 'ssl' >/dev/null 2>&1; then
|
|
whichbrew=$(command -v brew)
|
|
if [ -n "$whichbrew" ] && [ -x "$whichbrew" ]; then
|
|
brew_prefix=$(brew --prefix openssl)
|
|
if [ -n "$brew_prefix" ] && [ -d "$brew_prefix" ]; then
|
|
KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS "--with-ssl=$brew_prefix
|
|
fi
|
|
elif [ ! -d /usr/include/openssl ] || [ ! -d /usr/local/include/openssl ]; then
|
|
# Apple removed OpenSSL from El Capitan, but its still in this
|
|
# funky location, so set ssl headers to look here
|
|
xc_ssl='/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift-migrator/sdk/MacOSX.sdk/usr'
|
|
if [ -d "$xc_ssl"/include/openssl ]; then
|
|
KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS --with-ssl=$xc_ssl"
|
|
fi
|
|
unset xc_ssl
|
|
fi
|
|
fi
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
;;
|
|
Linux)
|
|
# we are going to check here to see if the Linux uses dpkg or rpms
|
|
#
|
|
# this is a "best effort" attempt to discover if a Linux has the
|
|
# packages needed to build Erlang. We will always assume the user
|
|
# knows better than us and are going to go ahead and try to build
|
|
# Erlang anyway. But at least it will be a clear warning to the
|
|
# user if a build fails.
|
|
_check_required_pkgs
|
|
;;
|
|
*)
|
|
;;
|
|
esac
|
|
|
|
if [ -n "$KERL_BUILD_DOCS" ]; then
|
|
KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS --prefix=$KERL_BUILD_DIR/$2/release_$1"
|
|
fi
|
|
|
|
ERL_TOP="$KERL_BUILD_DIR/$2/otp_src_$1"
|
|
cd "$ERL_TOP" || exit 1
|
|
LOGFILE="$KERL_BUILD_DIR/$2/otp_build_$1.log"
|
|
|
|
# Set configuation flags given applications white/black lists
|
|
if [ -n "$KERL_CONFIGURE_APPLICATIONS" ]; then
|
|
for app in $KERL_CONFIGURE_APPLICATIONS; do
|
|
case "$KERL_CONFIGURE_OPTIONS" in
|
|
*"--with-$app"*)
|
|
echo "Option '--with-$app' in KERL_CONFIGURE_OPTIONS is superfluous" ;;
|
|
*)
|
|
KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS --with-$app" ;;
|
|
esac
|
|
done
|
|
fi
|
|
if [ -n "$KERL_CONFIGURE_DISABLE_APPLICATIONS" ]; then
|
|
for app in $KERL_CONFIGURE_DISABLE_APPLICATIONS; do
|
|
case "$KERL_CONFIGURE_OPTIONS" in
|
|
*"--without-$app"*)
|
|
echo "Option '--without-$app' in KERL_CONFIGURE_OPTIONS is superfluous" ;;
|
|
*)
|
|
KERL_CONFIGURE_OPTIONS="$KERL_CONFIGURE_OPTIONS --without-$app" ;;
|
|
esac
|
|
done
|
|
fi
|
|
|
|
# Check to see if configuration options need to be stored or have changed
|
|
TMPOPT="/tmp/kerloptions.$$"
|
|
echo "$CFLAGS" >"$TMPOPT"
|
|
echo "$KERL_CONFIGURE_OPTIONS" >>"$TMPOPT"
|
|
SUM=$($MD5SUM "$TMPOPT" | cut -d ' ' -f $MD5SUM_FIELD)
|
|
# Check for a .kerl_config.md5 file
|
|
if [ -e ./"$KERL_CONFIG_STORAGE_FILENAME".md5 ]; then
|
|
# Compare our current options to the saved ones
|
|
read -r OLD_SUM <./"$KERL_CONFIG_STORAGE_FILENAME".md5
|
|
if [ "$SUM" != "$OLD_SUM" ]; then
|
|
echo 'Configure options have changed. Reconfiguring...'
|
|
rm -f configure
|
|
mv "$TMPOPT" ./"$KERL_CONFIG_STORAGE_FILENAME"
|
|
echo "$SUM" >./"$KERL_CONFIG_STORAGE_FILENAME".md5
|
|
else
|
|
# configure options are the same
|
|
rm -f "$TMPOPT"
|
|
fi
|
|
else
|
|
# no file exists, so write one
|
|
mv "$TMPOPT" .kerl_config
|
|
echo "$SUM" >.kerl_config.md5
|
|
fi
|
|
|
|
# Don't apply patches to "custom" git builds. We have no idea if they will apply
|
|
# cleanly or not.
|
|
if [ "$1" != 'git' ]; then
|
|
maybe_patch "$KERL_SYSTEM" "$1"
|
|
fi
|
|
if [ -n "$KERL_USE_AUTOCONF" ]; then
|
|
# shellcheck disable=SC2086
|
|
./otp_build autoconf $KERL_CONFIGURE_OPTIONS >>"$LOGFILE" 2>&1 && \
|
|
_flags ./otp_build configure $KERL_CONFIGURE_OPTIONS >>"$LOGFILE" 2>&1
|
|
else
|
|
# shellcheck disable=SC2086
|
|
_flags ./otp_build configure $KERL_CONFIGURE_OPTIONS >>"$LOGFILE" 2>&1
|
|
|
|
fi
|
|
if ! echo "$KERL_CONFIGURE_OPTIONS" | grep '--enable-native-libs' >/dev/null 2>&1; then
|
|
make clean >>"$LOGFILE" 2>&1
|
|
# shellcheck disable=SC2086
|
|
if ! _flags ./otp_build configure $KERL_CONFIGURE_OPTIONS >>"$LOGFILE" 2>&1; then
|
|
show_logfile 'Configure failed.' "$LOGFILE"
|
|
list_remove builds "$1 $2"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
for SECTION in 'APPLICATIONS DISABLED' \
|
|
'APPLICATIONS INFORMATION' \
|
|
'DOCUMENTATION INFORMATION'; do
|
|
show_configuration_warnings "$LOGFILE" "$SECTION"
|
|
done
|
|
|
|
if [ -n "$KERL_CONFIGURE_APPLICATIONS" ]; then
|
|
find ./lib -maxdepth 1 -type d -exec touch -f {}/SKIP \;
|
|
for app in $KERL_CONFIGURE_APPLICATIONS; do
|
|
if ! rm ./lib/"$app"/SKIP; then
|
|
echo "Couldn't prepare '$app' application for building"
|
|
list_remove builds "$1 $2"
|
|
exit 1
|
|
fi
|
|
done
|
|
fi
|
|
if [ -n "$KERL_CONFIGURE_DISABLE_APPLICATIONS" ]; then
|
|
for app in $KERL_CONFIGURE_DISABLE_APPLICATIONS; do
|
|
if ! touch -f ./lib/"$app"/SKIP; then
|
|
echo "Couldn't disable '$app' application for building"
|
|
exit 1
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# shellcheck disable=SC2086
|
|
if ! _flags ./otp_build boot -a $KERL_CONFIGURE_OPTIONS >>"$LOGFILE" 2>&1; then
|
|
show_logfile 'Build failed.' "$LOGFILE"
|
|
list_remove builds "$1 $2"
|
|
exit 1
|
|
fi
|
|
if [ -n "$KERL_BUILD_DOCS" ]; then
|
|
echo 'Building docs...'
|
|
if ! make docs >>"$LOGFILE" 2>&1; then
|
|
show_logfile 'Building docs failed.' "$LOGFILE"
|
|
list_remove builds "$1 $2"
|
|
exit 1
|
|
fi
|
|
if ! make install-docs >>"$LOGFILE" 2>&1; then
|
|
show_logfile 'Installing docs failed.' "$LOGFILE"
|
|
list_remove builds "$1 $2"
|
|
exit 1
|
|
fi
|
|
fi
|
|
rm -f "$LOGFILE"
|
|
ERL_TOP="$ERL_TOP" ./otp_build release -a "$KERL_BUILD_DIR/$2/release_$1" >/dev/null 2>&1
|
|
cd "$KERL_BUILD_DIR/$2/release_$1" || exit 1
|
|
./Install $INSTALL_OPT "$KERL_BUILD_DIR/$2/release_$1" >/dev/null 2>&1
|
|
}
|
|
|
|
do_install() {
|
|
if ! rel=$(get_release_from_name "$1"); then
|
|
echo "No build named $1"
|
|
exit 1
|
|
fi
|
|
if ! is_valid_install_path "$2"; then
|
|
exit 1
|
|
fi
|
|
mkdir -p "$2" || exit 1
|
|
absdir=$(cd "$2" && pwd)
|
|
echo "Installing Erlang/OTP $rel ($1) in $absdir..."
|
|
ERL_TOP="$KERL_BUILD_DIR/$1/otp_src_$rel"
|
|
cd "$ERL_TOP" || exit 1
|
|
if ! (ERL_TOP="$ERL_TOP" ./otp_build release -a "$absdir" >/dev/null 2>&1 &&
|
|
cd "$absdir" && ./Install $INSTALL_OPT "$absdir" >/dev/null 2>&1); then
|
|
echo "Couldn't install Erlang/OTP $rel ($1) in $absdir"
|
|
exit 1
|
|
fi
|
|
list_add installations "$1 $absdir";
|
|
cat <<ACTIVATE >"$absdir"/activate
|
|
#!/bin/sh
|
|
# credits to virtualenv
|
|
kerl_deactivate() {
|
|
if [ -n "\$_KERL_SAVED_ERL_AFLAGS" ]; then
|
|
ERL_AFLAGS="\$_KERL_SAVED_ERL_AFLAGS"
|
|
export ERL_AFLAGS
|
|
unset _KERL_SAVED_ERL_AFLAGS
|
|
fi
|
|
if [ -n "\$_KERL_PATH_REMOVABLE" ]; then
|
|
# shellcheck disable=SC2001
|
|
PATH="\$(echo "\$PATH" | sed -e "s#\$_KERL_PATH_REMOVABLE:##")"
|
|
export PATH
|
|
unset _KERL_PATH_REMOVABLE
|
|
fi
|
|
if [ -n "\$_KERL_MANPATH_REMOVABLE" ]; then
|
|
# shellcheck disable=SC2001
|
|
MANPATH="\$(echo "\$MANPATH" | sed -e "s#\$_KERL_MANPATH_REMOVABLE:##")"
|
|
export MANPATH
|
|
unset _KERL_MANPATH_REMOVABLE
|
|
fi
|
|
if [ -n "\$_KERL_SAVED_REBAR_PLT_DIR" ]; then
|
|
REBAR_PLT_DIR="\$_KERL_SAVED_REBAR_PLT_DIR"
|
|
export REBAR_PLT_DIR
|
|
unset _KERL_SAVED_REBAR_PLT_DIR
|
|
fi
|
|
if [ -n "\$_KERL_ACTIVE_DIR" ]; then
|
|
unset _KERL_ACTIVE_DIR
|
|
fi
|
|
if [ -n "\$_KERL_SAVED_PS1" ]; then
|
|
PS1="\$_KERL_SAVED_PS1"
|
|
export PS1
|
|
unset _KERL_SAVED_PS1
|
|
fi
|
|
if [ -n "\$_KERL_DOCSH_DOT_ERLANG" ]; then
|
|
rm "\$HOME/.erlang"
|
|
unset _KERL_DOCSH_DOT_ERLANG
|
|
fi
|
|
if [ -n "\$_KERL_DOCSH_USER_DEFAULT" ]; then
|
|
unset DOCSH_USER_DEFAULT
|
|
unset _KERL_DOCSH_USER_DEFAULT
|
|
fi
|
|
if [ -n "\$BASH" ] || [ -n "\$ZSH_VERSION" ]; then
|
|
hash -r
|
|
fi
|
|
if [ ! "\$1" = "nondestructive" ]; then
|
|
unset -f kerl_deactivate
|
|
fi
|
|
unset KERL_ENABLE_PROMPT
|
|
unset KERL_PROMPT_FORMAT
|
|
}
|
|
kerl_deactivate nondestructive
|
|
|
|
_KERL_SAVED_REBAR_PLT_DIR="\$REBAR_PLT_DIR"
|
|
export _KERL_SAVED_REBAR_PLT_DIR
|
|
_KERL_PATH_REMOVABLE="$absdir/bin"
|
|
PATH="\${_KERL_PATH_REMOVABLE}:\$PATH"
|
|
export PATH _KERL_PATH_REMOVABLE
|
|
_KERL_MANPATH_REMOVABLE="$absdir/lib/erlang/man:$absdir/man"
|
|
MANPATH="\${_KERL_MANPATH_REMOVABLE}:\$MANPATH"
|
|
export MANPATH _KERL_MANPATH_REMOVABLE
|
|
REBAR_PLT_DIR="$absdir"
|
|
export REBAR_PLT_DIR
|
|
_KERL_ACTIVE_DIR="$absdir"
|
|
export _KERL_ACTIVE_DIR
|
|
# https://twitter.com/mononcqc/status/877544929496629248
|
|
export _KERL_SAVED_ERL_AFLAGS=" \$ERL_AFLAGS"
|
|
kernel_history=\$(echo "\$ERL_AFLAGS" | grep 'kernel shell_history' || true)
|
|
if [ -z "\$kernel_history" ]; then
|
|
export ERL_AFLAGS="-kernel shell_history enabled \$ERL_AFLAGS"
|
|
fi
|
|
# shellcheck source=/dev/null
|
|
if [ -f "$KERL_CONFIG" ]; then . "$KERL_CONFIG"; fi
|
|
if [ -n "\$KERL_ENABLE_PROMPT" ]; then
|
|
_KERL_SAVED_PS1="\$PS1"
|
|
export _KERL_SAVED_PS1
|
|
if [ -n "\$KERL_PROMPT_FORMAT" ]; then
|
|
FRMT="\$KERL_PROMPT_FORMAT"
|
|
else
|
|
FRMT="(%BUILDNAME%)"
|
|
fi
|
|
PRMPT=\$(echo "\$FRMT" | sed 's^%RELEASE%^$rel^;s^%BUILDNAME%^$1^')
|
|
PS1="\$PRMPT\$PS1"
|
|
export PS1
|
|
fi
|
|
if [ -d "$absdir/lib/docsh" ]; then
|
|
export DOCSH_USER_DEFAULT="$absdir/lib/docsh/user_default"
|
|
export _KERL_DOCSH_USER_DEFAULT=yes
|
|
if [ -f "\$HOME/.erlang" ]; then
|
|
# shellcheck disable=SC2153
|
|
if [ ! x"\$KERL_DOCSH_DOT_ERLANG" = x'exists' ]; then
|
|
echo "Couldn't symlink correct \$HOME/.erlang - file exists - docsh might not work."
|
|
echo "Please make sure \$HOME/.erlang contains code"
|
|
echo "from $absdir/lib/docsh/dot.erlang"
|
|
echo 'and export KERL_DOCSH_DOT_ERLANG=exists to suppress this warning.'
|
|
fi
|
|
else
|
|
ln -s "$absdir/lib/docsh/dot.erlang" "\$HOME/.erlang"
|
|
export _KERL_DOCSH_DOT_ERLANG=yes
|
|
fi
|
|
fi
|
|
if [ -n "\$BASH" ] || [ -n "\$ZSH_VERSION" ]; then
|
|
hash -r
|
|
fi
|
|
ACTIVATE
|
|
|
|
cat <<ACTIVATE_FISH >"$absdir"/activate.fish
|
|
# credits to virtualenv
|
|
function _kerl_remove_el --description 'remove element from array'
|
|
set -l new_array
|
|
for el in \$\$argv[1]
|
|
if test \$el != \$argv[2]
|
|
set new_array \$new_array \$el
|
|
end
|
|
end
|
|
set -x \$argv[1] \$new_array
|
|
end
|
|
|
|
function kerl_deactivate --description "deactivate erlang environment"
|
|
if set --query _KERL_PATH_REMOVABLE
|
|
_kerl_remove_el PATH "\$_KERL_PATH_REMOVABLE"
|
|
set --erase _KERL_PATH_REMOVABLE
|
|
end
|
|
if set --query _KERL_MANPATH_REMOVABLE
|
|
_kerl_remove_el MANPATH "\$_KERL_MANPATH_REMOVABLE"
|
|
set --erase _KERL_MANPATH_REMOVABLE
|
|
end
|
|
if set --query _KERL_SAVED_REBAR_PLT_DIR
|
|
set -x REBAR_PLT_DIR "\$_KERL_SAVED_REBAR_PLT_DIR"
|
|
set --erase _KERL_SAVED_REBAR_PLT_DIR
|
|
end
|
|
if set --query _KERL_ACTIVE_DIR
|
|
set --erase _KERL_ACTIVE_DIR
|
|
end
|
|
if functions --query _kerl_saved_prompt
|
|
functions --erase fish_prompt
|
|
# functions --copy complains about about fish_prompt already being defined
|
|
# so we take a page from virtualenv's book
|
|
. ( begin
|
|
printf "function fish_prompt\\n\\t#"
|
|
functions _kerl_saved_prompt
|
|
end | psub )
|
|
functions --erase _kerl_saved_prompt
|
|
end
|
|
if set --query _KERL_DOCSH_DOT_ERLANG
|
|
rm "\$HOME/.erlang"
|
|
set --erase _KERL_DOCSH_DOT_ERLANG
|
|
end
|
|
if set --query _KERL_DOCSH_USER_DEFAULT
|
|
set --erase DOCSH_USER_DEFAULT
|
|
set --erase _KERL_DOCSH_USER_DEFAULT
|
|
end
|
|
if test "\$argv[1]" != "nondestructive"
|
|
functions --erase kerl_deactivate
|
|
functions --erase _kerl_remove_el
|
|
end
|
|
end
|
|
kerl_deactivate nondestructive
|
|
|
|
set -x _KERL_SAVED_REBAR_PLT_DIR "\$REBAR_PLT_DIR"
|
|
set -x _KERL_PATH_REMOVABLE "$absdir/bin"
|
|
set -x PATH "\$_KERL_PATH_REMOVABLE" \$PATH
|
|
set -x _KERL_MANPATH_REMOVABLE "$absdir/lib/erlang/man" "$absdir/man"
|
|
set -x MANPATH \$MANPATH "\$_KERL_MANPATH_REMOVABLE"
|
|
set -x REBAR_PLT_DIR "$absdir"
|
|
set -x _KERL_ACTIVE_DIR "$absdir"
|
|
if test -f "$KERL_CONFIG.fish"
|
|
source "$KERL_CONFIG.fish"
|
|
end
|
|
if set --query KERL_ENABLE_PROMPT
|
|
functions --copy fish_prompt _kerl_saved_prompt
|
|
function fish_prompt
|
|
echo -n "($1)"
|
|
_kerl_saved_prompt
|
|
end
|
|
end
|
|
if test -d "$absdir/lib/docsh"
|
|
set -x DOCSH_USER_DEFAULT "$absdir/lib/docsh/user_default"
|
|
set -x _KERL_DOCSH_USER_DEFAULT yes
|
|
if test -f "\$HOME/.erlang"
|
|
if test ! x"\$KERL_DOCSH_DOT_ERLANG" = x"exists"
|
|
echo "Couldn't symlink correct \$HOME/.erlang - file exists - docsh might not work."
|
|
echo "Please make sure \$HOME/.erlang contains code"
|
|
echo "from $absdir/lib/docsh/dot.erlang"
|
|
echo "and export KERL_DOCSH_DOT_ERLANG=exists to suppress this warning."
|
|
end
|
|
else
|
|
ln -s "$absdir/lib/docsh/dot.erlang" "\$HOME/.erlang"
|
|
set -x _KERL_DOCSH_DOT_ERLANG yes
|
|
end
|
|
end
|
|
ACTIVATE_FISH
|
|
|
|
cat <<ACTIVATE_CSH >"$absdir"/activate.csh
|
|
# This file must be used with "source bin/activate.csh" *from csh*.
|
|
# You cannot run it directly.
|
|
|
|
alias 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_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'
|
|
|
|
# Unset irrelevant variables.
|
|
kerl_deactivate nondestructive
|
|
|
|
if ( \$?REBAR_PLT_DIR ) then
|
|
set _KERL_SAVED_REBAR_PLT_DIR = "\$REBAR_PLT_DIR"
|
|
else
|
|
set _KERL_SAVED_REBAR_PLT_DIR=""
|
|
endif
|
|
|
|
set _KERL_PATH_REMOVABLE = "$absdir/bin"
|
|
set _KERL_SAVED_PATH = "\$PATH"
|
|
setenv PATH "\${_KERL_PATH_REMOVABLE}:\$PATH"
|
|
|
|
if ( ! \$?MANPATH ) then
|
|
set MANPATH = ""
|
|
endif
|
|
set _KERL_MANPATH_REMOVABLE = "$absdir/lib/erlang/man:$absdir/man"
|
|
set _KERL_SAVED_MANPATH = "\$MANPATH"
|
|
setenv MANPATH "\${_KERL_MANPATH_REMOVABLE}:\$MANPATH"
|
|
|
|
setenv REBAR_PLT_DIR "$absdir"
|
|
|
|
set _KERL_ACTIVE_DIR = "$absdir"
|
|
|
|
if ( -f "$KERL_CONFIG.csh" ) then
|
|
source "$KERL_CONFIG.csh"
|
|
endif
|
|
|
|
if ( \$?KERL_ENABLE_PROMPT ) then
|
|
set _KERL_SAVED_PROMPT = "\$prompt"
|
|
|
|
if ( \$?KERL_PROMPT_FORMAT ) then
|
|
set FRMT = "\$KERL_PROMPT_FORMAT"
|
|
else
|
|
set FRMT = "(%BUILDNAME%)"
|
|
endif
|
|
|
|
set PROMPT = \$(echo "\$FRMT" | sed 's^%RELEASE%^$rel^;s^%BUILDNAME%^$1^')
|
|
set prompt = "\$PROMPT\$prompt"
|
|
endif
|
|
|
|
if ( -d "$absdir/lib/docsh" ) then
|
|
setenv DOCSH_USER_DEFAULT "$absdir/lib/docsh/user_default"
|
|
set _KERL_DOCSH_USER_DEFAULT = "yes"
|
|
if ( -f "\$HOME/.erlang" ) then
|
|
if ( \$?KERL_DOCSH_DOT_ERLANG == 0 ) then
|
|
echo "Couldn't symlink correct \$HOME/.erlang - file exists - docsh might not work."
|
|
echo "Please make sure \$HOME/.erlang contains code"
|
|
echo "from $absdir/lib/docsh/dot.erlang"
|
|
echo "and export KERL_DOCSH_DOT_ERLANG=exists to suppress this warning."
|
|
endif
|
|
else
|
|
ln -s "$absdir/lib/docsh/dot.erlang" "\$HOME/.erlang"
|
|
set _KERL_DOCSH_DOT_ERLANG = "yes"
|
|
endif
|
|
endif
|
|
|
|
rehash
|
|
ACTIVATE_CSH
|
|
|
|
if [ -n "$KERL_BUILD_DOCS" ]; then
|
|
DOC_DIR="$KERL_BUILD_DIR/$1/release_$rel"/lib/erlang
|
|
if [ -d "$DOC_DIR" ]; then
|
|
echo 'Installing docs...'
|
|
cp $CP_OPT "$DOC_DIR/" "$absdir"/lib
|
|
if [ -d "$absdir"/lib/erlang/man ]; then
|
|
ln -s "$absdir"/lib/erlang/man "$absdir"/man
|
|
ln -s "$absdir"/lib/erlang/doc "$absdir"/html
|
|
elif [ -d "$absdir"/lib/man ]; then
|
|
ln -s "$absdir"/lib/man "$absdir"/man
|
|
ln -s "$absdir"/lib/doc "$absdir"/html
|
|
fi
|
|
fi
|
|
else
|
|
if [ "$KERL_BUILD_BACKEND" = 'tarball' ]; then
|
|
if [ "$rel" != 'git' ]; then
|
|
if [ -n "$KERL_INSTALL_MANPAGES" ]; then
|
|
echo 'Fetching and installing manpages...'
|
|
download_manpages "$rel"
|
|
fi
|
|
|
|
if [ -n "$KERL_INSTALL_HTMLDOCS" ]; then
|
|
echo 'Fetching and installing HTML docs...'
|
|
download_htmldocs "$rel"
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
KERL_CONFIG_STORAGE_PATH="$KERL_BUILD_DIR/$1/otp_src_$rel/$KERL_CONFIG_STORAGE_FILENAME"
|
|
[ -e "$KERL_CONFIG_STORAGE_PATH" ] && cp "$KERL_CONFIG_STORAGE_PATH" "$absdir/$KERL_CONFIG_STORAGE_FILENAME"
|
|
|
|
if [ -n "$KERL_BUILD_PLT" ]; then
|
|
echo 'Building Dialyzer PLT...'
|
|
build_plt "$absdir"
|
|
fi
|
|
|
|
if command -v apk >/dev/null 2>&1; then
|
|
# Running on Alpine Linux, assuming non-exotic shell
|
|
SHELL_SUFFIX=''
|
|
else
|
|
PID=$$
|
|
PARENT_PID=$(ps -p $PID -o ppid=) || exit 1
|
|
# shellcheck disable=SC2086
|
|
PARENT_CMD=$(ps -p $PARENT_PID -o ucomm | tail -n 1)
|
|
case "$PARENT_CMD" in
|
|
fish)
|
|
SHELL_SUFFIX='.fish'
|
|
;;
|
|
csh)
|
|
SHELL_SUFFIX='.csh'
|
|
;;
|
|
*)
|
|
SHELL_SUFFIX=''
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
echo 'You can activate this installation running the following command:'
|
|
echo ". $absdir/activate$SHELL_SUFFIX"
|
|
echo 'Later on, you can leave the installation typing:'
|
|
echo 'kerl_deactivate'
|
|
}
|
|
|
|
install_docsh() {
|
|
REPO_URL=$DOCSH_GITHUB_URL
|
|
GIT=$(printf '%s' $REPO_URL | $MD5SUM | cut -d' ' -f $MD5SUM_FIELD)
|
|
BUILDNAME="$1"
|
|
DOCSH_DIR="$KERL_BUILD_DIR/$BUILDNAME/docsh"
|
|
DOCSH_REF='0.6.1'
|
|
ACTIVE_PATH="$2"
|
|
|
|
OTP_VERSION=$(get_otp_version "$1")
|
|
# This has to be updated with docsh updates
|
|
DOCSH_SUPPORTED='^1[89]\|2[01]$'
|
|
if ! echo "$OTP_VERSION" | grep "$DOCSH_SUPPORTED" >/dev/null 2>&1; then
|
|
echo "Erlang/OTP version $OTP_VERSION not supported by docsh (does not match regex $DOCSH_SUPPORTED)"
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$KERL_GIT_DIR" || exit 1
|
|
cd "$KERL_GIT_DIR" || exit 1
|
|
echo "Checking out docsh git repository from $REPO_URL..."
|
|
if [ ! -d "$GIT" ]; then
|
|
if ! git clone -q --mirror "$REPO_URL" "$GIT" >/dev/null 2>&1; then
|
|
echo 'Error mirroring remote git repository'
|
|
exit 1
|
|
fi
|
|
fi
|
|
cd "$GIT" || exit 1
|
|
if ! git remote update --prune >/dev/null 2>&1; then
|
|
echo 'Error updating remote git repository'
|
|
exit 1
|
|
fi
|
|
|
|
rm -Rf "$DOCSH_DIR"
|
|
mkdir -p "$DOCSH_DIR" || exit 1
|
|
cd "$DOCSH_DIR" || exit 1
|
|
if ! git clone -l "$KERL_GIT_DIR/$GIT" "$DOCSH_DIR" >/dev/null 2>&1; then
|
|
echo 'Error cloning local git repository'
|
|
exit 1
|
|
fi
|
|
cd "$DOCSH_DIR" || exit 1
|
|
if ! git checkout "$DOCSH_REF" >/dev/null 2>&1; then
|
|
if ! git checkout -b "$DOCSH_REF" "$DOCSH_REF" >/dev/null 2>&1; then
|
|
echo 'Could not checkout specified version'
|
|
rm -Rf "$DOCSH_DIR"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if ! ./rebar3 compile; then
|
|
echo 'Could not compile docsh'
|
|
rm -Rf "$DOCSH_DIR"
|
|
exit 1
|
|
fi
|
|
|
|
## Install docsh
|
|
if [ -f "$ACTIVE_PATH"/lib/docsh ]; then
|
|
echo "Couldn't install $ACTIVE_PATH/lib/docsh - the directory already exists"
|
|
rm -Rf "$DOCSH_DIR"
|
|
exit 1
|
|
else
|
|
cp -R "$DOCSH_DIR"/_build/default/lib/docsh "$ACTIVE_PATH"/lib/
|
|
fi
|
|
## Prepare dot.erlang for linking as $HOME/.erlang
|
|
if [ -f "$ACTIVE_PATH"/lib/docsh/dot.erlang ]; then
|
|
echo "Couldn't install $ACTIVE_PATH/lib/docsh/dot.erlang - the file already exists"
|
|
rm -Rf "$DOCSH_DIR"
|
|
exit 1
|
|
else
|
|
cat "$DOCSH_DIR"/templates/dot.erlang >"$ACTIVE_PATH"/lib/docsh/dot.erlang
|
|
fi
|
|
## Warn if $HOME/.erlang exists
|
|
if [ -f "$HOME"/.erlang ]; then
|
|
echo "$HOME/.erlang exists - kerl won't be able to symlink a docsh-compatible version."
|
|
echo "Please make sure your $HOME/.erlang contains code"
|
|
echo "from $ACTIVE_PATH/lib/docsh/dot.erlang"
|
|
echo 'and export KERL_DOCSH_DOT_ERLANG=exists to suppress further warnings'
|
|
fi
|
|
## Install docsh user_default
|
|
if [ -f "$ACTIVE_PATH"/lib/docsh/user_default.beam ]; then
|
|
echo "Couldn't install $ACTIVE_PATH/lib/docsh/user_default.beam - the file already exists"
|
|
rm -Rf "$DOCSH_DIR"
|
|
exit 1
|
|
else
|
|
erlc -I "$DOCSH_DIR"/include -o "$ACTIVE_PATH"/lib/docsh/ "$DOCSH_DIR"/templates/user_default.erl
|
|
fi
|
|
}
|
|
|
|
download_manpages() {
|
|
FILENAME=otp_doc_man_$1.tar.gz
|
|
tarball_download "$FILENAME"
|
|
echo 'Extracting manpages'
|
|
cd "$absdir" && tar xzf "$KERL_DOWNLOAD_DIR/$FILENAME"
|
|
}
|
|
|
|
download_htmldocs() {
|
|
FILENAME=otp_doc_html_"$1".tar.gz
|
|
tarball_download "$FILENAME"
|
|
echo 'Extracting HTML docs'
|
|
(cd "$absdir" && mkdir -p html && tar -C "$absdir"/html -xzf "$KERL_DOWNLOAD_DIR/$FILENAME")
|
|
}
|
|
|
|
build_plt() {
|
|
dialyzerd="$1"/dialyzer
|
|
mkdir -p "$dialyzerd" || exit 1
|
|
plt="$dialyzerd"/plt
|
|
build_log="$dialyzerd"/build.log
|
|
dirs=$(find "$1"/lib -maxdepth 2 -name ebin -type d -exec dirname {} \;)
|
|
apps=$(for app in $dirs; do basename "$app" | cut -d- -f1 ; done | grep -Ev 'erl_interface|jinterface' | xargs echo)
|
|
# shellcheck disable=SC2086
|
|
"$1"/bin/dialyzer --output_plt "$plt" --build_plt --apps $apps >>"$build_log" 2>&1
|
|
status=$?
|
|
if [ $status -eq 0 ] || [ $status -eq 2 ]; then
|
|
echo "Done building $plt"
|
|
return 0
|
|
else
|
|
echo "Error building PLT, see $build_log for details"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
do_plt() {
|
|
ACTIVE_PATH="$1"
|
|
if [ -n "$ACTIVE_PATH" ]; then
|
|
plt="$ACTIVE_PATH"/dialyzer/plt
|
|
if [ -f "$plt" ]; then
|
|
echo 'Dialyzer PLT for the active installation is:'
|
|
echo "$plt"
|
|
return 0
|
|
else
|
|
echo 'There is no Dialyzer PLT for the active installation'
|
|
return 1
|
|
fi
|
|
else
|
|
echo 'No Erlang/OTP installation is currently active'
|
|
return 2
|
|
fi
|
|
}
|
|
|
|
print_buildopts() {
|
|
buildopts="$1/$KERL_CONFIG_STORAGE_FILENAME"
|
|
if [ -f "$buildopts" ]; then
|
|
echo 'The build options for the active installation are:'
|
|
cat "$buildopts"
|
|
return 0
|
|
else
|
|
echo 'The build options for the active installation are not available.'
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
do_deploy() {
|
|
if [ -z "$1" ]; then
|
|
echo 'No host given'
|
|
exit 1
|
|
fi
|
|
host="$1"
|
|
|
|
assert_valid_installation "$2"
|
|
rel="$(get_name_from_install_path "$2")"
|
|
path="$2"
|
|
remotepath="$path"
|
|
|
|
if [ ! -z "$3" ]; then
|
|
remotepath="$3"
|
|
fi
|
|
|
|
# shellcheck disable=SC2086
|
|
if ! ssh $KERL_DEPLOY_SSH_OPTIONS "$host" true >/dev/null 2>&1; then
|
|
echo "Couldn't ssh to $host"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Cloning Erlang/OTP $rel ($path) to $host ($remotepath) ..."
|
|
|
|
# shellcheck disable=SC2086
|
|
if ! rsync -aqz -e "ssh $KERL_DEPLOY_SSH_OPTIONS" $KERL_DEPLOY_RSYNC_OPTIONS "$path/" "$host:$remotepath/"; then
|
|
echo "Couldn't rsync Erlang/OTP $rel ($path) to $host ($remotepath)"
|
|
exit 1
|
|
fi
|
|
|
|
# shellcheck disable=SC2086,SC2029
|
|
if ! ssh $KERL_DEPLOY_SSH_OPTIONS "$host" "cd \"$remotepath\" && env ERL_TOP=\"\$(pwd)\" ./Install $INSTALL_OPT \"\$(pwd)\" >/dev/null 2>&1"; then
|
|
echo "Couldn't install Erlang/OTP $rel to $host ($remotepath)"
|
|
exit 1
|
|
fi
|
|
|
|
# shellcheck disable=SC2086,SC2029
|
|
if ! ssh $KERL_DEPLOY_SSH_OPTIONS "$host" "cd \"$remotepath\" && sed -i -e \"s#$path#\"\$(pwd)\"#g\" activate"; then
|
|
echo "Couldn't completely install Erlang/OTP $rel to $host ($remotepath)"
|
|
exit 1
|
|
fi
|
|
|
|
echo "On $host, you can activate this installation running the following command:"
|
|
echo ". $remotepath/activate"
|
|
echo 'Later on, you can leave the installation typing:'
|
|
echo 'kerl_deactivate'
|
|
}
|
|
|
|
|
|
# Quoted from https://github.com/mkropat/sh-realpath
|
|
# LICENSE: MIT
|
|
|
|
realpath() {
|
|
canonicalize_path "$(resolve_symlinks "$1")"
|
|
}
|
|
|
|
resolve_symlinks() {
|
|
_resolve_symlinks "$1"
|
|
}
|
|
|
|
_resolve_symlinks() {
|
|
_assert_no_path_cycles "$@" || return
|
|
|
|
if path=$(readlink -- "$1"); then
|
|
dir_context=$(dirname -- "$1")
|
|
_resolve_symlinks "$(_prepend_dir_context_if_necessary "$dir_context" "$path")" "$@"
|
|
else
|
|
printf '%s\n' "$1"
|
|
fi
|
|
}
|
|
|
|
_prepend_dir_context_if_necessary() {
|
|
if [ "$1" = . ]; then
|
|
printf '%s\n' "$2"
|
|
else
|
|
_prepend_path_if_relative "$1" "$2"
|
|
fi
|
|
}
|
|
|
|
_prepend_path_if_relative() {
|
|
case "$2" in
|
|
/* ) printf '%s\n' "$2" ;;
|
|
* ) printf '%s\n' "$1/$2" ;;
|
|
esac
|
|
}
|
|
|
|
_assert_no_path_cycles() {
|
|
target=$1
|
|
shift
|
|
|
|
for path in "$@"; do
|
|
if [ "$path" = "$target" ]; then
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
canonicalize_path() {
|
|
if [ -d "$1" ]; then
|
|
_canonicalize_dir_path "$1"
|
|
else
|
|
_canonicalize_file_path "$1"
|
|
fi
|
|
}
|
|
|
|
_canonicalize_dir_path() {
|
|
(cd "$1" 2>/dev/null && pwd -P)
|
|
}
|
|
|
|
_canonicalize_file_path() {
|
|
dir=$(dirname -- "$1")
|
|
file=$(basename -- "$1")
|
|
(cd "$dir" 2>/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file")
|
|
}
|
|
|
|
# END QUOTE
|
|
|
|
is_valid_install_path() {
|
|
# don't allow installs into .erlang because
|
|
# it's a special configuration file location for OTP
|
|
if [ "$(basename -- "$1")" = '.erlang' ]; then
|
|
echo 'ERROR: You cannot install a build into .erlang. (It is a special configuration file location for OTP.)'
|
|
return 1
|
|
fi
|
|
|
|
candidate=$(realpath "$1")
|
|
canonical_home=$(realpath "$HOME")
|
|
canonical_base_dir=$(realpath "$KERL_BASE_DIR")
|
|
|
|
# don't allow installs into home directory
|
|
if [ "$candidate" = "$canonical_home" ]; then
|
|
echo "ERROR: You cannot install a build into $HOME. It's a really bad idea."
|
|
return 1
|
|
fi
|
|
|
|
# don't install into our base directory either.
|
|
if [ "$candidate" = "$canonical_base_dir" ]; then
|
|
echo "ERROR: You cannot install a build into $KERL_BASE_DIR."
|
|
return 1
|
|
fi
|
|
|
|
INSTALLED_NAME=$(get_name_from_install_path "$candidate")
|
|
if [ -n "$INSTALLED_NAME" ]; then
|
|
echo "ERROR: Installation ($INSTALLED_NAME) already registered for this location ($1)"
|
|
return 1
|
|
fi
|
|
|
|
# if the install directory exists,
|
|
# do not allow installs into a directory that is not empty
|
|
if [ -e "$1" ]; then
|
|
if [ ! -d "$1" ]; then
|
|
echo "ERROR: $1 is not a directory."
|
|
return 1
|
|
else
|
|
count=$(find "$1" | wc -l)
|
|
if [ "$count" -ne 1 ]; then
|
|
echo "ERROR: $1 does not appear to be an empty directory."
|
|
return 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
maybe_remove() {
|
|
candidate=$(realpath "$1")
|
|
canonical_home=$(realpath "$HOME")
|
|
|
|
if [ "$candidate" = "$canonical_home" ]; then
|
|
echo "WARNING: You cannot remove an install from $HOME; it's your home directory."
|
|
return 0
|
|
fi
|
|
|
|
ACTIVE_PATH="$(get_active_path)"
|
|
if [ "$candidate" = "$ACTIVE_PATH" ]; then
|
|
echo 'ERROR: You cannot delete the active installation. Deactivate it first.'
|
|
exit 1
|
|
fi
|
|
|
|
rm -Rf "$1"
|
|
}
|
|
|
|
list_print() {
|
|
if [ -f "$KERL_BASE_DIR/otp_$1" ]; then
|
|
if [ "$(wc -l "$KERL_BASE_DIR/otp_$1")" != '0' ]; then
|
|
cat "$KERL_BASE_DIR/otp_$1"
|
|
return 0
|
|
fi
|
|
fi
|
|
echo "There are no $1 available"
|
|
}
|
|
|
|
list_add() {
|
|
if [ -f "$KERL_BASE_DIR/otp_$1" ]; then
|
|
while read -r l; do
|
|
if [ "$l" = "$2" ]; then
|
|
return 1
|
|
fi
|
|
done <"$KERL_BASE_DIR/otp_$1"
|
|
echo "$2" >>"$KERL_BASE_DIR/otp_$1" || exit 1
|
|
else
|
|
echo "$2" >"$KERL_BASE_DIR/otp_$1" || exit 1
|
|
fi
|
|
}
|
|
|
|
list_remove() {
|
|
if [ -f "$KERL_BASE_DIR/otp_$1" ]; then
|
|
sed $SED_OPT -i -e "/^.*$2$/d" "$KERL_BASE_DIR/otp_$1" || exit 1
|
|
fi
|
|
}
|
|
|
|
list_has() {
|
|
if [ -f "$KERL_BASE_DIR/otp_$1" ]; then
|
|
grep "$2" "$KERL_BASE_DIR/otp_$1" >/dev/null 2>&1 && return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
path_usage() {
|
|
echo "usage: $0 path [<install_name>]"
|
|
}
|
|
|
|
list_usage() {
|
|
echo "usage: $0 list <releases|builds|installations>"
|
|
}
|
|
|
|
delete_usage() {
|
|
echo "usage: $0 delete <build|installation> <build_name or path>"
|
|
}
|
|
|
|
cleanup_usage() {
|
|
echo "usage: $0 cleanup <build_name|all>"
|
|
}
|
|
|
|
update_usage() {
|
|
echo "usage: $0 update releases"
|
|
}
|
|
|
|
get_active_path() {
|
|
if [ -n "$_KERL_ACTIVE_DIR" ]; then
|
|
echo "$_KERL_ACTIVE_DIR"
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
get_name_from_install_path() {
|
|
if [ -f "$KERL_BASE_DIR"/otp_installations ]; then
|
|
grep -m1 -E "$1$" "$KERL_BASE_DIR"/otp_installations | cut -d' ' -f1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
get_install_path_from_name() {
|
|
if [ -f "$KERL_BASE_DIR"/otp_installations ]; then
|
|
grep -m1 -E "$1$" "$KERL_BASE_DIR"/otp_installations | cut -d' ' -f2
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
do_active() {
|
|
ACTIVE_PATH="$(get_active_path)"
|
|
if [ -n "$ACTIVE_PATH" ]; then
|
|
echo 'The current active installation is:'
|
|
echo "$ACTIVE_PATH"
|
|
return 0
|
|
else
|
|
echo 'No Erlang/OTP installation is currently active'
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
make_filename() {
|
|
release=$(get_otp_version "$1")
|
|
if [ "$release" -ge 17 ]; then
|
|
echo "OTP-$1"
|
|
else
|
|
echo "OTP_$1"
|
|
fi
|
|
}
|
|
|
|
download() {
|
|
mkdir -p "$KERL_DOWNLOAD_DIR" || exit 1
|
|
if [ "$KERL_BUILD_BACKEND" = 'git' ]; then
|
|
FILENAME=$(make_filename "$1")
|
|
github_download "$FILENAME".tar.gz
|
|
else
|
|
FILENAME="otp_src_$1"
|
|
tarball_download "$FILENAME".tar.gz
|
|
fi
|
|
}
|
|
|
|
github_download() {
|
|
# if the file doesn't exist or the file has no size
|
|
if [ ! -s "$KERL_DOWNLOAD_DIR/$1" ]; then
|
|
echo "Downloading $1 to $KERL_DOWNLOAD_DIR"
|
|
curl -f -L -o "$KERL_DOWNLOAD_DIR/$1" "$OTP_GITHUB_URL/archive/$1" || exit 1
|
|
fi
|
|
}
|
|
|
|
tarball_download() {
|
|
if [ ! -s "$KERL_DOWNLOAD_DIR/$1" ]; then
|
|
echo "Downloading $1 to $KERL_DOWNLOAD_DIR"
|
|
curl -f -L -o "$KERL_DOWNLOAD_DIR/$1" "$ERLANG_DOWNLOAD_URL/$1" || exit 1
|
|
update_checksum_file
|
|
fi
|
|
ensure_checksum_file
|
|
echo 'Verifying archive checksum...'
|
|
SUM="$($MD5SUM "$KERL_DOWNLOAD_DIR/$1" | cut -d' ' -f $MD5SUM_FIELD)"
|
|
ORIG_SUM="$(grep -F "$1" "$KERL_DOWNLOAD_DIR"/MD5 | cut -d' ' -f2)"
|
|
if [ "$SUM" != "$ORIG_SUM" ]; then
|
|
echo "Checksum error, check the files in $KERL_DOWNLOAD_DIR"
|
|
exit 1
|
|
fi
|
|
echo "Checksum verified ($SUM)"
|
|
}
|
|
|
|
apply_solaris_networking_patch() {
|
|
patch -p1 <<_END_PATCH
|
|
--- otp-a/erts/emulator/drivers/common/inet_drv.c
|
|
+++ otp-b/erts/emulator/drivers/common/inet_drv.c
|
|
@@ -4166,16 +4166,7 @@
|
|
break;
|
|
|
|
case INET_IFOPT_HWADDR: {
|
|
-#ifdef SIOCGIFHWADDR
|
|
- if (ioctl(desc->s, SIOCGIFHWADDR, (char *)&ifreq) < 0)
|
|
- break;
|
|
- buf_check(sptr, s_end, 1+2+IFHWADDRLEN);
|
|
- *sptr++ = INET_IFOPT_HWADDR;
|
|
- put_int16(IFHWADDRLEN, sptr); sptr += 2;
|
|
- /* raw memcpy (fix include autoconf later) */
|
|
- sys_memcpy(sptr, (char*)(&ifreq.ifr_hwaddr.sa_data), IFHWADDRLEN);
|
|
- sptr += IFHWADDRLEN;
|
|
-#elif defined(SIOCGENADDR)
|
|
+#if defined(SIOCGENADDR)
|
|
if (ioctl(desc->s, SIOCGENADDR, (char *)&ifreq) < 0)
|
|
break;
|
|
buf_check(sptr, s_end, 1+2+sizeof(ifreq.ifr_enaddr));
|
|
_END_PATCH
|
|
}
|
|
|
|
apply_darwin_compiler_patch() {
|
|
patch -p0 <<_END_PATCH
|
|
--- erts/emulator/beam/beam_bp.c.orig 2011-10-03 13:12:07.000000000 -0500
|
|
+++ erts/emulator/beam/beam_bp.c 2013-10-04 13:42:03.000000000 -0500
|
|
@@ -496,7 +496,8 @@
|
|
}
|
|
|
|
/* bp_hash */
|
|
-ERTS_INLINE Uint bp_sched2ix() {
|
|
+#ifndef ERTS_DO_INCL_GLB_INLINE_FUNC_DEF
|
|
+ERTS_GLB_INLINE Uint bp_sched2ix() {
|
|
#ifdef ERTS_SMP
|
|
ErtsSchedulerData *esdp;
|
|
esdp = erts_get_scheduler_data();
|
|
@@ -505,6 +506,7 @@
|
|
return 0;
|
|
#endif
|
|
}
|
|
+#endif
|
|
static void bp_hash_init(bp_time_hash_t *hash, Uint n) {
|
|
Uint size = sizeof(bp_data_time_item_t)*n;
|
|
Uint i;
|
|
--- erts/emulator/beam/beam_bp.h.orig 2011-10-03 13:12:07.000000000 -0500
|
|
+++ erts/emulator/beam/beam_bp.h 2013-10-04 13:42:08.000000000 -0500
|
|
@@ -144,7 +144,19 @@
|
|
#define ErtsSmpBPUnlock(BDC)
|
|
#endif
|
|
|
|
-ERTS_INLINE Uint bp_sched2ix(void);
|
|
+ERTS_GLB_INLINE Uint bp_sched2ix(void);
|
|
+
|
|
+#ifdef ERTS_DO_INCL_GLB_INLINE_FUNC_DEF
|
|
+ERTS_GLB_INLINE Uint bp_sched2ix() {
|
|
+#ifdef ERTS_SMP
|
|
+ ErtsSchedulerData *esdp;
|
|
+ esdp = erts_get_scheduler_data();
|
|
+ return esdp->no - 1;
|
|
+#else
|
|
+ return 0;
|
|
+#endif
|
|
+}
|
|
+#endif
|
|
|
|
#ifdef ERTS_SMP
|
|
#define bp_sched2ix_proc(p) ((p)->scheduler_data->no - 1)
|
|
_END_PATCH
|
|
}
|
|
|
|
# javadoc 8 includes always-enabled document linting which causes
|
|
# documentation builds to fail on older OTP releases.
|
|
apply_javadoc_linting_patch() {
|
|
# The _END_PATCH token is quoted below to disable parameter substitution
|
|
patch -p0 <<'_END_PATCH'
|
|
--- lib/jinterface/doc/src/Makefile.orig 2016-05-23 14:34:48.000000000 -0500
|
|
+++ lib/jinterface/doc/src/Makefile 2016-05-23 14:35:48.000000000 -0500
|
|
@@ -142,7 +142,7 @@
|
|
rm -f errs core *~
|
|
|
|
jdoc:$(JAVA_SRC_FILES)
|
|
- (cd ../../java_src;$(JAVADOC) -sourcepath . -d $(JAVADOC_DEST) \
|
|
+ (cd ../../java_src;$(JAVADOC) -Xdoclint:none -sourcepath . -d $(JAVADOC_DEST) \
|
|
-windowtitle $(JAVADOC_TITLE) $(JAVADOC_PKGS))
|
|
|
|
man:
|
|
_END_PATCH
|
|
}
|
|
|
|
# perl 5.24 fatalizes the warning this causes
|
|
apply_r14_beam_makeops_patch() {
|
|
patch -p0 <<'_END_PATCH'
|
|
--- erts/emulator/utils/beam_makeops.orig 2016-05-23 21:40:42.000000000 -0500
|
|
+++ erts/emulator/utils/beam_makeops 2016-05-23 21:41:08.000000000 -0500
|
|
@@ -1576,7 +1576,7 @@
|
|
if $min_window{$key} > $min_window;
|
|
|
|
pop(@{$gen_transform{$key}})
|
|
- if defined @{$gen_transform{$key}}; # Fail
|
|
+ if defined $gen_transform{$key}; # Fail
|
|
my(@prefix) = (&make_op($comment), &make_op('', 'try_me_else', &tr_code_len(@code)));
|
|
unshift(@code, @prefix);
|
|
push(@{$gen_transform{$key}}, @code, &make_op('', 'fail'));
|
|
_END_PATCH
|
|
}
|
|
|
|
# https://github.com/erlang/otp/commit/21ca6d3a137034f19862db769a5b7f1c5528dbc4.diff
|
|
apply_r15_beam_makeops_patch() {
|
|
patch -p1 <<'_END_PATCH'
|
|
--- a/erts/emulator/utils/beam_makeops
|
|
+++ b/erts/emulator/utils/beam_makeops
|
|
@@ -1711,7 +1711,7 @@ sub tr_gen_to {
|
|
my $prev_last;
|
|
$prev_last = pop(@{$gen_transform{$key}})
|
|
- if defined @{$gen_transform{$key}}; # Fail
|
|
+ if defined $gen_transform{$key}; # Fail
|
|
|
|
if ($prev_last && !is_instr($prev_last, 'fail')) {
|
|
error("Line $line: A previous transformation shadows '$orig_transform'");
|
|
_END_PATCH
|
|
}
|
|
|
|
#https://github.com/erlang/otp/commit/a64c4d806fa54848c35632114585ad82b98712e8.diff
|
|
apply_wx_ptr_patch() {
|
|
patch -p1 <<'_END_PATCH'
|
|
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
|
|
index 0d2da5d4a79..8118136d30e 100644
|
|
--- a/lib/wx/c_src/wxe_impl.cpp
|
|
+++ b/lib/wx/c_src/wxe_impl.cpp
|
|
@@ -666,7 +666,7 @@ void * WxeApp::getPtr(char * bp, wxeMemEnv *memenv) {
|
|
throw wxe_badarg(index);
|
|
}
|
|
void * temp = memenv->ref2ptr[index];
|
|
- if((index < memenv->next) && ((index == 0) || (temp > NULL)))
|
|
+ if((index < memenv->next) && ((index == 0) || (temp != (void *)NULL)))
|
|
return temp;
|
|
else {
|
|
throw wxe_badarg(index);
|
|
@@ -678,7 +678,7 @@ void WxeApp::registerPid(char * bp, ErlDrvTermData pid, wxeMemEnv * memenv) {
|
|
if(!memenv)
|
|
throw wxe_badarg(index);
|
|
void * temp = memenv->ref2ptr[index];
|
|
- if((index < memenv->next) && ((index == 0) || (temp > NULL))) {
|
|
+ if((index < memenv->next) && ((index == 0) || (temp != (void *) NULL))) {
|
|
ptrMap::iterator it;
|
|
it = ptr2ref.find(temp);
|
|
if(it != ptr2ref.end()) {
|
|
_END_PATCH
|
|
}
|
|
|
|
apply_r16_wx_ptr_patch() {
|
|
patch -p1 <<'_END_PATCH'
|
|
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
|
|
index cc9bcc995..1b1912630 100644
|
|
--- a/lib/wx/c_src/wxe_impl.cpp
|
|
+++ b/lib/wx/c_src/wxe_impl.cpp
|
|
@@ -757,7 +757,7 @@ void * WxeApp::getPtr(char * bp, wxeMemEnv *memenv) {
|
|
throw wxe_badarg(index);
|
|
}
|
|
void * temp = memenv->ref2ptr[index];
|
|
- if((index < memenv->next) && ((index == 0) || (temp > NULL)))
|
|
+ if((index < memenv->next) && ((index == 0) || (temp != (void *)NULL)))
|
|
return temp;
|
|
else {
|
|
throw wxe_badarg(index);
|
|
@@ -769,7 +769,7 @@ void WxeApp::registerPid(char * bp, ErlDrvTermData pid, wxeMemEnv * memenv) {
|
|
if(!memenv)
|
|
throw wxe_badarg(index);
|
|
void * temp = memenv->ref2ptr[index];
|
|
- if((index < memenv->next) && ((index == 0) || (temp > NULL))) {
|
|
+ if((index < memenv->next) && ((index == 0) || (temp != (void *)NULL))) {
|
|
ptrMap::iterator it;
|
|
it = ptr2ref.find(temp);
|
|
if(it != ptr2ref.end()) {
|
|
_END_PATCH
|
|
}
|
|
|
|
# https://github.com/erlang/otp/commit/e27119948fc6ab28bea81019720bddaac5b655a7.patch
|
|
apply_zlib_patch()
|
|
{
|
|
|
|
patch -p1 <<'_END_PATCH'
|
|
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
|
|
index 656de7c49ad..4491d486837 100644
|
|
--- a/erts/emulator/beam/external.c
|
|
+++ b/erts/emulator/beam/external.c
|
|
@@ -1193,6 +1193,7 @@ typedef struct B2TContext_t {
|
|
} u;
|
|
} B2TContext;
|
|
|
|
+static B2TContext* b2t_export_context(Process*, B2TContext* src);
|
|
|
|
static uLongf binary2term_uncomp_size(byte* data, Sint size)
|
|
{
|
|
@@ -1225,7 +1226,7 @@ static uLongf binary2term_uncomp_size(byte* data, Sint size)
|
|
|
|
static ERTS_INLINE int
|
|
binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size,
|
|
- B2TContext* ctx)
|
|
+ B2TContext** ctxp, Process* p)
|
|
{
|
|
byte *bytes = data;
|
|
Sint size = data_size;
|
|
@@ -1239,8 +1240,8 @@ binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size,
|
|
size--;
|
|
if (size < 5 || *bytes != COMPRESSED) {
|
|
state->extp = bytes;
|
|
- if (ctx)
|
|
- ctx->state = B2TSizeInit;
|
|
+ if (ctxp)
|
|
+ (*ctxp)->state = B2TSizeInit;
|
|
}
|
|
else {
|
|
uLongf dest_len = (Uint32) get_int32(bytes+1);
|
|
@@ -1257,16 +1258,26 @@ binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size,
|
|
return -1;
|
|
}
|
|
state->extp = erts_alloc(ERTS_ALC_T_EXT_TERM_DATA, dest_len);
|
|
- ctx->reds -= dest_len;
|
|
+ if (ctxp)
|
|
+ (*ctxp)->reds -= dest_len;
|
|
}
|
|
state->exttmp = 1;
|
|
- if (ctx) {
|
|
+ if (ctxp) {
|
|
+ /*
|
|
+ * Start decompression by exporting trap context
|
|
+ * so we don't have to deal with deep-copying z_stream.
|
|
+ */
|
|
+ B2TContext* ctx = b2t_export_context(p, *ctxp);
|
|
+ ASSERT(state = &(*ctxp)->b2ts);
|
|
+ state = &ctx->b2ts;
|
|
+
|
|
if (erl_zlib_inflate_start(&ctx->u.uc.stream, bytes, size) != Z_OK)
|
|
return -1;
|
|
|
|
ctx->u.uc.dbytes = state->extp;
|
|
ctx->u.uc.dleft = dest_len;
|
|
ctx->state = B2TUncompressChunk;
|
|
+ *ctxp = ctx;
|
|
}
|
|
else {
|
|
uLongf dlen = dest_len;
|
|
@@ -1308,7 +1319,7 @@ erts_binary2term_prepare(ErtsBinary2TermState *state, byte *data, Sint data_size
|
|
{
|
|
Sint res;
|
|
|
|
- if (binary2term_prepare(state, data, data_size, NULL) < 0 ||
|
|
+ if (binary2term_prepare(state, data, data_size, NULL, NULL) < 0 ||
|
|
(res=decoded_size(state->extp, state->extp + state->extsize, 0, NULL)) < 0) {
|
|
|
|
if (state->exttmp)
|
|
@@ -1435,7 +1446,7 @@ static Eterm binary_to_term_int(Process* p, Uint32 flags, Eterm bin, Binary* con
|
|
if (ctx->aligned_alloc) {
|
|
ctx->reds -= bin_size / 8;
|
|
}
|
|
- if (binary2term_prepare(&ctx->b2ts, bytes, bin_size, ctx) < 0) {
|
|
+ if (binary2term_prepare(&ctx->b2ts, bytes, bin_size, &ctx, p) < 0) {
|
|
ctx->state = B2TBadArg;
|
|
}
|
|
break;
|
|
_END_PATCH
|
|
}
|
|
|
|
case "$1" in
|
|
version)
|
|
echo "$KERL_VERSION"
|
|
exit 0
|
|
;;
|
|
build)
|
|
if [ "$2" = 'git' ]; then
|
|
if [ $# -ne 5 ]; then
|
|
echo "usage: $0 $1 $2 <git_url> <git_version> <build_name>"
|
|
exit 1
|
|
fi
|
|
do_git_build "$3" "$4" "$5"
|
|
else
|
|
if [ $# -lt 3 ]; then
|
|
echo "usage: $0 $1 <release> <build_name>"
|
|
exit 1
|
|
fi
|
|
do_normal_build "$2" "$3"
|
|
fi
|
|
;;
|
|
install)
|
|
if [ $# -lt 2 ]; then
|
|
echo "usage: $0 $1 <build_name> [directory]"
|
|
exit 1
|
|
fi
|
|
if [ $# -eq 3 ]; then
|
|
do_install "$2" "$3"
|
|
else
|
|
if [ -z "$KERL_DEFAULT_INSTALL_DIR" ]; then
|
|
do_install "$2" "$PWD"
|
|
else
|
|
do_install "$2" "$KERL_DEFAULT_INSTALL_DIR/$2"
|
|
fi
|
|
fi
|
|
;;
|
|
install-docsh)
|
|
ACTIVE_PATH="$(get_active_path)"
|
|
if [ -n "$ACTIVE_PATH" ]; then
|
|
ACTIVE_NAME="$(get_name_from_install_path "$ACTIVE_PATH")"
|
|
if [ -z "$ACTIVE_NAME" ]; then
|
|
## TODO: Are git builds installed the usual way
|
|
## or do we need this clause to provide a fallback?
|
|
#BUILDNAME="$(basename "$ACTIVE_PATH")"
|
|
echo "$ACTIVE_PATH is not a kerl installation"
|
|
exit 1
|
|
else
|
|
BUILDNAME="$ACTIVE_NAME"
|
|
fi
|
|
install_docsh "$BUILDNAME" "$ACTIVE_PATH"
|
|
echo 'Please kerl_deactivate and activate again to enable docsh'
|
|
else
|
|
echo 'No Erlang/OTP installation is currently active - cannot install docsh'
|
|
exit 1
|
|
fi
|
|
;;
|
|
deploy)
|
|
if [ $# -lt 2 ]; then
|
|
echo "usage: $0 $1 <[user@]host> [directory] [remote_directory]"
|
|
exit 1
|
|
fi
|
|
if [ $# -eq 4 ]; then
|
|
do_deploy "$2" "$3" "$4"
|
|
else
|
|
if [ $# -eq 3 ]; then
|
|
do_deploy "$2" "$3"
|
|
else
|
|
do_deploy "$2" .
|
|
fi
|
|
fi
|
|
;;
|
|
update)
|
|
if [ $# -lt 2 ]; then
|
|
update_usage
|
|
exit 1
|
|
fi
|
|
case "$2" in
|
|
releases)
|
|
rm -f "${KERL_BASE_DIR:?}"/otp_releases
|
|
check_releases
|
|
echo 'The available releases are:'
|
|
list_print releases
|
|
;;
|
|
*)
|
|
update_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
;;
|
|
list)
|
|
if [ $# -ne 2 ]; then
|
|
list_usage
|
|
exit 1
|
|
fi
|
|
case "$2" in
|
|
releases)
|
|
check_releases
|
|
list_print "$2"
|
|
echo "Run '$0 update releases' to update this list from erlang.org"
|
|
;;
|
|
builds)
|
|
list_print "$2"
|
|
;;
|
|
installations)
|
|
list_print "$2"
|
|
;;
|
|
*)
|
|
echo "Cannot list $2"
|
|
list_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
;;
|
|
path)
|
|
# Usage:
|
|
# kerl path
|
|
# # Print currently active installation path, else non-zero exit
|
|
# kerl path <install>
|
|
# Print path to installation with name <install>, else non-zero exit
|
|
if [ -z "$2" ]; then
|
|
activepath=$(get_active_path)
|
|
if [ -z "$activepath" ]; then
|
|
echo 'No active kerl-managed erlang installation'
|
|
exit 1
|
|
fi
|
|
echo "$activepath"
|
|
else
|
|
# There are some possible extensions to this we could
|
|
# consider, such as:
|
|
# - if 2+ matches: prefer one in a subdir from $PWD
|
|
# - prefer $KERL_DEFAULT_INSTALL_DIR
|
|
match=
|
|
for ins in $(list_print installations | cut -d' ' -f2); do
|
|
if [ "$(basename "$ins")" = "$2" ]; then
|
|
if [ -z "$match" ]; then
|
|
match="$ins"
|
|
else
|
|
echo 'Error: too many matching installations' >&2
|
|
exit 2
|
|
fi
|
|
fi
|
|
done
|
|
[ -n "$match" ] && echo "$match" && exit 0
|
|
echo 'Error: no matching installation found' >&2 && exit 1
|
|
fi
|
|
;;
|
|
delete)
|
|
if [ $# -ne 3 ]; then
|
|
delete_usage
|
|
exit 1
|
|
fi
|
|
case "$2" in
|
|
build)
|
|
rel="$(get_release_from_name "$3")"
|
|
if [ -d "${KERL_BUILD_DIR:?}/$3" ]; then
|
|
maybe_remove "${KERL_BUILD_DIR:?}/$3"
|
|
else
|
|
if [ -z "$rel" ]; then
|
|
echo "No build named $3"
|
|
exit 1
|
|
fi
|
|
fi
|
|
list_remove "$2"s "$rel,$3"
|
|
echo "The $3 build has been deleted"
|
|
;;
|
|
installation)
|
|
assert_valid_installation "$3"
|
|
if [ -d "$3" ]; then
|
|
maybe_remove "$3"
|
|
else
|
|
maybe_remove "$(get_install_path_from_name "$3")"
|
|
fi
|
|
escaped="$(echo "$3" | sed $SED_OPT -e 's#/$##' -e 's#\/#\\\/#g')"
|
|
list_remove "$2"s "$escaped"
|
|
echo "The installation \"$3\" has been deleted"
|
|
;;
|
|
*)
|
|
echo "Cannot delete $2"
|
|
delete_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
;;
|
|
active)
|
|
if ! do_active; then
|
|
exit 1;
|
|
fi
|
|
;;
|
|
plt)
|
|
ACTIVE_PATH=$(get_active_path)
|
|
if ! do_plt "$ACTIVE_PATH"; then
|
|
exit 1;
|
|
fi
|
|
;;
|
|
status)
|
|
echo 'Available builds:'
|
|
list_print builds
|
|
echo '----------'
|
|
echo 'Available installations:'
|
|
list_print installations
|
|
echo '----------'
|
|
if do_active; then
|
|
ACTIVE_PATH=$(get_active_path)
|
|
if [ -n "$ACTIVE_PATH" ]; then
|
|
do_plt "$ACTIVE_PATH"
|
|
print_buildopts "$ACTIVE_PATH"
|
|
else
|
|
echo 'No Erlang/OTP installation is currently active'
|
|
exit 1
|
|
fi
|
|
fi
|
|
exit 0
|
|
;;
|
|
prompt)
|
|
FMT=' (%s)'
|
|
if [ -n "$2" ]; then
|
|
FMT="$2"
|
|
fi
|
|
ACTIVE_PATH="$(get_active_path)"
|
|
if [ -n "$ACTIVE_PATH" ]; then
|
|
ACTIVE_NAME="$(get_name_from_install_path "$ACTIVE_PATH")"
|
|
if [ -z "$ACTIVE_NAME" ]; then
|
|
VALUE="$(basename "$ACTIVE_PATH")*"
|
|
else
|
|
VALUE="$ACTIVE_NAME"
|
|
fi
|
|
# shellcheck disable=SC2059
|
|
printf "$FMT" "$VALUE"
|
|
fi
|
|
exit 0
|
|
;;
|
|
cleanup)
|
|
if [ $# -ne 2 ]; then
|
|
cleanup_usage
|
|
exit 1
|
|
fi
|
|
case "$2" in
|
|
all)
|
|
echo 'Cleaning up compilation products for ALL builds'
|
|
rm -rf "${KERL_BUILD_DIR:?}"/*
|
|
rm -rf "${KERL_DOWNLOAD_DIR:?}"/*
|
|
rm -rf "${KERL_GIT_DIR:?}"/*
|
|
echo "Cleaned up all compilation products under $KERL_BUILD_DIR"
|
|
;;
|
|
*)
|
|
echo "Cleaning up compilation products for $3"
|
|
rm -rf "${KERL_BUILD_DIR:?}/$3"
|
|
echo "Cleaned up compilation products for $3 under $KERL_BUILD_DIR"
|
|
;;
|
|
esac
|
|
;;
|
|
*)
|
|
echo "unknown command: $1"; usage; exit 1
|
|
;;
|
|
esac
|