#! /bin/sh # Copyright (c) 2016 Mark Allen # Copyright (c) 2011, 2012 Spawngrid, Inc # Copyright (c) 2011 Evax Software # # 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. #Grep fix for mac pcre errors GREP_OPTIONS='' ERLANG_DOWNLOAD_URL="http://www.erlang.org/download" # Default values : ${OTP_GITHUB_URL:="https://github.com/erlang/otp"} : ${KERL_BASE_DIR:="$HOME"/.kerl} : ${KERL_CONFIG:="$HOME"/.kerlrc} : ${KERL_DOWNLOAD_DIR:="${KERL_BASE_DIR:?}"/archives} : ${KERL_BUILD_DIR:="${KERL_BASE_DIR:?}"/builds} : ${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_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_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 . "$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 "$_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 [options ...]" printf "\n 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 " 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)" 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" \ | egrep -o 'OTP[_-][^^{}]+' \ | sed $SED_OPT 's/OTP[_-]//' \ | sort -n \ | uniq } get_tarball_releases() { curl -L -s $ERLANG_DOWNLOAD_URL/ | \ sed $SED_OPT -e 's/^.*<[aA] [hH][rR][eE][fF]=\"\otp_src_([-0-9A-Za-z_.]+)\.tar\.gz\">.*$/\1/' \ -e '/^R1|^[0-9]/!d' | \ sed -e "s/^R\(.*\)/\1:R\1/" | sed -e "s/^\([^\:]*\)$/\1-z:\1/" | sort | cut -d':' -f2 } update_checksum_file() { if [ "$KERL_BUILD_BACKEND" = "git" ]; then return 0 else echo "Getting the checksum file from erlang.org..." curl -L $ERLANG_DOWNLOAD_URL/MD5 > "$KERL_DOWNLOAD_DIR"/MD5 || exit 1 fi } ensure_checksum_file() { if [ ! -f "$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 "," -f 1) name=$(echo "$l" | cut -d "," -f 2) 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 " " -f 1) path=$(echo "$l" | cut -d " " -f 2) if [ "$name" = "$1" -o "$path" = "$1" ]; then if [ -f "$1"/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 "," -f 2) if [ "$name" = "$1" ]; then echo "There's already a build named $1" exit 1 fi done < "$KERL_BASE_DIR"/otp_builds fi } do_git_build() { assert_build_name_unused "$3" GIT=$(echo -n "$1" | $MD5SUM | cut -d ' ' -f $MD5SUM_FIELD) mkdir -p "$KERL_GIT_DIR" || exit 1 cd "$KERL_GIT_DIR" || exit 1 echo "Checking Erlang/OTP git repository from $1..." if [ ! -d "$GIT" ]; then git clone -q --mirror "$1" "$GIT" > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "Error mirroring remote git repository" exit 1 fi fi cd "$GIT" || exit 1 git remote update --prune > /dev/null 2>&1 if [ $? -ne 0 ]; 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 git clone -l "$KERL_GIT_DIR/$GIT" otp_src_git > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "Error cloning local git repository" exit 1 fi cd otp_src_git || exit 1 git checkout "$2" > /dev/null 2>&1 if [ $? -ne 0 ]; then git checkout -b "$2" "$2" > /dev/null 2>&1 fi if [ $? -ne 0 ]; then echo "Couldn't checkout specified version" rm -Rf "${KERL_BUILD_DIR:?}/$3" exit 1 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})[.AB]?[0-9]*/\1/' } show_logfile() { echo "$1" tail "$2" echo echo "Please see $2 for full details." } 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 xfz "$KERL_DOWNLOAD_DIR/$FILENAME.tar.gz" && mv ./* "$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" } _do_build() { case "$KERL_SYSTEM" in Darwin) # Apple removed OpenSSL from El Capitan, but its still in this # funky location, so set ssl headers to look here OSVERSION=`uname -r` RELVERSION=`get_otp_version "$1"` case "$OSVERSION" in 15*) echo -n $KERL_CONFIGURE_OPTIONS | grep "ssl" 1>/dev/null 2>&1 # Reminder to self: 0 from grep means the string was detected if [ $? -ne 0 ]; then if [ ! -d /usr/include/openssl -o ! -d /usr/local/include/openssl ]; then 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" else echo 'WARNING: No OpenSSL library was found in the usual places. Your Erlang will be built without crypto support!' fi unset xc_ssl fi fi ;; *) ;; esac ;; *) ;; 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" if [ -n "$KERL_USE_AUTOCONF" ]; then ./otp_build autoconf $KERL_CONFIGURE_OPTIONS > "$LOGFILE" 2>&1 && \ ./otp_build configure $KERL_CONFIGURE_OPTIONS >> "$LOGFILE" 2>&1 else ./otp_build configure $KERL_CONFIGURE_OPTIONS > "$LOGFILE" 2>&1 fi if [ $? -ne 0 ]; then show_logfile "Configure failed." "$LOGFILE" list_remove builds "$1 $2" exit 1 fi # TODO: Check to see if we got any warnings from the configure # step. if [ -n "$KERL_CONFIGURE_APPLICATIONS" ]; then find ./lib -maxdepth 1 -type d -exec touch -f {}/SKIP \; for i in $KERL_CONFIGURE_APPLICATIONS; do rm ./lib/"$i"/SKIP if [ $? -ne 0 ]; then echo "Couldn't prepare '$i' application for building" list_remove builds "$1 $2" exit 1 fi done fi if [ -n "$KERL_CONFIGURE_DISABLE_APPLICATIONS" ]; then for i in $KERL_CONFIGURE_DISABLE_APPLICATIONS; do touch -f ./lib/"$i"/SKIP if [ $? -ne 0 ]; then echo "Couldn't disable '$i' application for building" exit 1 fi done fi ./otp_build boot -a $KERL_CONFIGURE_OPTIONS > "$LOGFILE" 2>&1 if [ $? -ne 0 ]; then show_logfile "Build failed." "$LOGFILE" list_remove builds "$1 $2" exit 1 fi if [ -n "$KERL_BUILD_DOCS" ]; then echo "Building docs..." make docs >> "$LOGFILE" 2>&1 if [ $? -ne 0 ]; then show_logfile "Building docs failed." "$LOGFILE" list_remove builds "$1 $2" exit 1 fi make install-docs >> "$LOGFILE" 2>&1 if [ $? -ne 0 ]; 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() { rel=$(get_release_from_name "$1") if [ $? -ne 0 ]; 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 ERL_TOP="$ERL_TOP" ./otp_build release -a "$absdir" > /dev/null 2>&1 && cd "$absdir" && ./Install $INSTALL_OPT "$absdir" > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "Couldn't install Erlang/OTP $rel ($1) in $absdir" exit 1 fi list_add installations "$1 $absdir"; cat < "$absdir"/activate # credits to virtualenv kerl_deactivate() { if [ -n "\$_KERL_PATH_REMOVABLE" ]; then PATH=\${PATH//\${_KERL_PATH_REMOVABLE}:/} export PATH unset _KERL_PATH_REMOVABLE fi if [ -n "\$_KERL_MANPATH_REMOVABLE" ]; then MANPATH=\${MANPATH//\${_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 "\$BASH" -o -n "\$ZSH_VERSION" ]; then hash -r fi if [ ! "\$1" = "nondestructive" ]; then unset -f kerl_deactivate fi } 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 if [ -f "$KERL_CONFIG" ]; then . "$KERL_CONFIG"; fi if [ -n "\$KERL_ENABLE_PROMPT" ]; then _KERL_SAVED_PS1="\$PS1" export _KERL_SAVED_PS1 PS1="($1)\$PS1" export PS1 fi if [ -n "\$BASH" -o -n "\$ZSH_VERSION" ]; then hash -r fi ACTIVATE if [ -n "$KERL_BUILD_DOCS" ]; then DOC_DIR="$KERL_BUILD_DIR/$1/release_$rel/lib/erlang" if [ -d "$DOC_DIR" ]; then echo "Installing docs..." mkdir -p "$absdir/lib/erlang" || exit 1 cp $CP_OPT "$DOC_DIR/" "$absdir/lib/erlang" ln -s "$absdir/lib/erlang/man" "$absdir/man" ln -s "$absdir/lib/erlang/doc" "$absdir/html" 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 if [ -n "$KERL_BUILD_PLT" ]; then echo "Building Dialyzer PLT..." build_plt "$absdir" fi echo "You can activate this installation running the following command:" echo ". $absdir/activate" echo "Later on, you can leave the installation typing:" echo "kerl_deactivate" } download_manpages() { FILENAME=otp_doc_man_$1.tar.gz tarball_download "$FILENAME" echo "Extracting manpages" cd "$absdir" && tar xfz "$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 dialyzer=$1/bin/dialyzer apps=`ls -1 $1/lib | cut -d- -f1 | grep -Ev 'erl_interface|jinterface' | xargs echo` $dialyzer --output_plt $plt --build_plt --apps $apps > $build_log 2>&1 status=$? if [ $status -eq 0 -o $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=`get_active_path` 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's no Dialyzer PLT for the active installation" return 1 fi else echo "No Erlang/OTP kerl installation is currently active" return 2 fi } do_deploy() { if [ -z "$1" ]; then echo "No host given" exit 1 fi host="$1" assert_valid_installation "$2" if ! is_valid_install_path "$2"; then exit 1 fi rel="$(get_name_from_install_path "$2")" path="$2" remotepath="$path" if [ ! -z "$3" ]; then remotepath="$3" fi ssh $KERL_DEPLOY_SSH_OPTIONS "$host" true > /dev/null 2>&1 if [ $? -ne 0 ]; then echo "Couldn't ssh to $host" exit 1 fi echo "Cloning Erlang/OTP $rel ($path) to $host ($remotepath) ..." rsync -aqz -e "ssh $KERL_DEPLOY_SSH_OPTIONS" $KERL_DEPLOY_RSYNC_OPTIONS "$path/" "$host:$remotepath/" if [ $? -ne 0 ]; then echo "Couldn't rsync Erlang/OTP $rel ($path) to $host ($remotepath)" exit 1 fi ssh $KERL_DEPLOY_SSH_OPTIONS "$host" "cd \"$remotepath\" && env ERL_TOP=\"\`pwd\`\" ./Install $INSTALL_OPT \"\`pwd\`\" > /dev/null 2>&1" if [ $? -ne 0 ]; then echo "Couldn't install Erlang/OTP $rel to $host ($remotepath)" exit 1 fi ssh $KERL_DEPLOY_SSH_OPTIONS "$host" "cd \"$remotepath\" && sed -i -e \"s#$path#\"\`pwd\`\"#g\" activate" if [ $? -ne 0 ]; 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 local dir_context path path=$(readlink -- "$1") if [ $? -eq 0 ]; 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() { local target path 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() { local dir file 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's 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 # if the install directory exists, # do not allow installs into a directory # that is not empty if [ -e "$1" ]; then if [ -d "$1" ]; then count=$(ls -la "$1" | wc -l) if [ $count -ne 3 ]; then echo "ERROR: $1 does not appear to be an empty directory." return 1 fi else echo "ERROR: $1 is not a directory." return 1 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 if [ -z "$2" ]; then cat "$KERL_BASE_DIR/otp_$1" else echo `cat "$KERL_BASE_DIR/otp_$1"` fi 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" else echo "$2" > "$KERL_BASE_DIR/otp_$1" fi } list_remove() { if [ -f "$KERL_BASE_DIR/otp_$1" ]; then sed $SED_OPT -i -e "/^.*$2$/d" "$KERL_BASE_DIR/otp_$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 } list_usage() { echo "usage: $0 list " } delete_usage() { echo "usage: $0 delete " } cleanup_usage() { echo "usage: $0 cleanup " } 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 -F "$1" "$KERL_BASE_DIR"/otp_installations | cut -d ' ' -f 1 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 kerl installation is currently active" return 1 fi } download() { mkdir -p "$KERL_DOWNLOAD_DIR" || exit 1 if [ "$KERL_BUILD_BACKEND" = "git" ]; then FILENAME="OTP-$1" github_download "$FILENAME.tar.gz" else FILENAME="otp_src_$1" tarball_download "$FILENAME.tar.gz" fi } github_download() { if [ ! -f "$KERL_DOWNLOAD_DIR/$1" ]; then echo "Downloading $1 to $KERL_DOWNLOAD_DIR" curl -L "$OTP_GITHUB_URL/archive/$1" > "$KERL_DOWNLOAD_DIR/$1" fi } tarball_download() { if [ ! -f "$KERL_DOWNLOAD_DIR/$1" ]; then curl -L "$ERLANG_DOWNLOAD_URL/$1" > "$KERL_DOWNLOAD_DIR/$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 ' ' -f 2)" if [ "$SUM" != "$ORIG_SUM" ]; then echo "Checksum error, check the files in $KERL_DOWNLOAD_DIR" exit 1 fi echo "Checksum verified ($SUM)" } case "$1" in build) if [ "$2" = "git" ]; then if [ $# -ne 5 ]; then echo "usage: $0 $1 $2 " exit 1 fi do_git_build "$3" "$4" "$5" else if [ $# -lt 3 ]; then echo "usage: $0 $1 " exit 1 fi do_normal_build "$2" "$3" fi ;; install) if [ $# -lt 2 ]; then echo "usage: $0 $1 [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 ;; 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 spaces ;; *) update_usage exit 1 ;; esac ;; list) if [ $# -ne 2 ]; then list_usage exit 1 fi case "$2" in releases) check_releases list_print "$2" space 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 ;; 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" maybe_remove "$3" escaped="$(echo "$3" | sed $SED_OPT -e 's#/$##' -e 's#\/#\\\/#g')" list_remove "$2"s "$escaped" echo "The installation in $3 has been deleted" ;; *) echo "Cannot delete $2" delete_usage exit 1 ;; esac ;; active) if ! do_active; then exit 1; fi ;; plt) if ! do_plt; then exit 1; fi ;; status) echo "Available builds:" list_print builds echo "----------" echo "Available installations:" list_print installations echo "----------" if do_active; then do_plt 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 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