/kerl
Shell | 646 lines | 592 code | 29 blank | 25 comment | 59 complexity | 33f0bec8a912cfd875336fd86cf841c3 MD5 | raw file
- #! /bin/sh
- # Copyright (c) 2011 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.
- ERLANG_DOWNLOAD_URL=http://www.erlang.org/download
- KERL_BASE_DIR="$HOME/.kerl"
- KERL_CONFIG="$HOME/.kerlrc"
- KERL_DOWNLOAD_DIR="$KERL_BASE_DIR/archives"
- KERL_BUILD_DIR="$KERL_BASE_DIR/builds"
- if [ -n "$KERL_CONFIGURE_OPTIONS" ]; then
- _KCO="$KERL_CONFIGURE_OPTIONS"
- fi
- if [ -n "$KERL_SASL_STARTUP" ]; then
- _KSS="$KERL_SASL_STARTUP"
- fi
- if [ -n "$KERL_AGNER_AUTOINSTALL" ]; then
- _KAA="$KERL_AGNER_AUTOINSTALL"
- fi
- KERL_CONFIGURE_OPTIONS=
- KERL_DISABLE_AGNER=
- KERL_SASL_STARTUP=
- # ensure the base dir exsists
- mkdir -p "$KERL_BASE_DIR"
- # source the config file if available
- if [ -f "$KERL_CONFIG" ]; then . "$KERL_CONFIG"; fi
- if [ -n "$_KCO" ]; then
- KERL_CONFIGURE_OPTIONS="$_KCO"
- fi
- if [ -n "$_KSS" ]; then
- KERL_SASL_STARTUP="$_KSS"
- fi
- if [ -n "$_KAA" ]; then
- KERL_AGNER_AUTOINSTALL="$_KAA"
- fi
- if [ -z "$KERL_SASL_STARTUP" ]; then
- INSTALL_OPT=-minimal
- else
- INSTALL_OPT=-sasl
- fi
- KERL_SYSTEM=`uname -s`
- case "$KERL_SYSTEM" in
- Darwin)
- MD5SUM="openssl md5"
- MD5SUM_FIELD=2
- SED_OPT=-E
- if [ `gcc --version | grep llvm | wc -l` = "1" ]; then
- if [ -x `which gcc-4.2` ]; then
- echo "Adjust compiler settings for OS X: using gcc-4.2"
- KERL_CONFIGURE_OPTIONS="CC=gcc-4.2 $KERL_CONFIGURE_OPTIONS"
- else
- echo "Adjust compiler settings for OS X: using -O0"
- KERL_CONFIGURE_OPTIONS="CFLAGS=-O0 $KERL_CONFIGURE_OPTIONS"
- fi
- fi
- ;;
- *)
- MD5SUM=md5sum
- MD5SUM_FIELD=1
- SED_OPT=-r
- ;;
- esac
- usage()
- {
- echo "kerl: build and install Erlang/OTP"
- echo "usage: $0 <command> [options ...]"
- echo "\n <command> Command to be executed\n"
- echo "Valid commands are:"
- echo " build Build specified release or git repository"
- echo " install Install the specified release at the given location"
- echo " update Update agner or the list of available releases from erlang.org"
- echo " list List releases, builds and installations"
- echo " delete Delete builds and installations"
- echo " active Print the path of the active installation"
- echo " status Print available builds and installations"
- exit 1
- }
- if [ $# -eq 0 ]; then usage; fi
- get_releases()
- {
- curl -s $ERLANG_DOWNLOAD_URL/ | \
- sed $SED_OPT -e 's/^.*>otp_src_(R1[-1234567890ABCD]+)\.tar\.gz<.*$/\1/' \
- -e '/^R/!d'
- }
- update_checksum_file()
- {
- echo "Getting the checksum file from erlang.org..."
- curl $ERLANG_DOWNLOAD_URL/MD5 > "$KERL_DOWNLOAD_DIR/MD5" || exit 1
- }
- ensure_checksum_file()
- {
- if [ ! -f "$KERL_DOWNLOAD_DIR/MD5" ]; then
- update_checksum_file
- fi
- }
- check_releases()
- {
- if [ ! -f "$KERL_BASE_DIR/otp_releases" ]; then
- echo "Getting the available releases from erlang.org..."
- get_releases > "$KERL_BASE_DIR/otp_releases"
- fi
- }
- # c.f. agner issue #98
- # https://github.com/agner/agner/issues/#issue/98
- KERL_NO_AGNER_SUPPORT="R10B-0 R10B-2 R10B-3 R10B-4 R10B-5 R10B-6 R10B-7
- R10B-8 R10B-9 R11B-0 R11B-1 R11B-2 R11B-3 R11B-4 R11B-5 R12B-0 R12B-1
- R12B-2 R12B-3 R12B-4 R12B-5 R13A R13B R13B01 R13B02 R13B03 R13B04"
- agner_support()
- {
- if [ -z "$KERL_DISABLE_AGNER" ]; then
- return 1;
- fi
- for v in $KERL_NO_AGNER_SUPPORT; do
- if [ "$v" = "$1" ]; then
- return 1
- fi
- done
- return 0
- }
- is_valid_release()
- {
- check_releases
- for rel in `cat $KERL_BASE_DIR/otp_releases`; do
- if [ "$1" = "$rel" ]; then
- return 0
- fi
- done
- 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
- for l in `cat "$KERL_BASE_DIR/otp_builds"`; 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
- fi
- return 1
- }
- is_valid_installation()
- {
- if [ -f "$1/activate" ]; then
- return 0
- fi
- return 1
- }
- do_update_agner()
- {
- rel=`get_release_from_name $1`
- if [ "$?" -eq 1 ]; then
- echo "Unknown build name $1"
- exit 1
- fi
- TARGET="$KERL_BUILD_DIR/$1/release_$rel"
- cd "$KERL_BUILD_DIR/$1/agner_$rel" && \
- git pull &&
- PATH="$KERL_BUILD_DIR/$1/otp_src_$rel/bin:$PATH" \
- make > /dev/null 2>&1
- if [ "$?" -eq 1 ]; then
- return 1
- fi
- return 0
- }
- assert_build_name_unused()
- {
- if [ -f "$KERL_BASE_DIR/otp_builds" ]; then
- for l in `cat "$KERL_BASE_DIR/otp_builds"`; do
- name=`echo $l | cut -d "," -f 2`
- if [ "$name" = "$1" ]; then
- echo "There's already a build named $1"
- exit 1
- fi
- done
- fi
- }
- do_git_build()
- {
- assert_build_name_unused $3
- mkdir -p "$KERL_BUILD_DIR/$3"
- cd "$KERL_BUILD_DIR/$3"
- echo "Checking Erlang/OTP git repository from $1..."
- git clone $1 otp_src_git > /dev/null 2>&1
- if [ "$?" -eq 1 ]; then
- echo "Error retriving git repository"
- exit 1
- fi
- if [ ! -x otp_src_git/otp_build ]; then
- echo "Not a valid Erlang/OTP repository"
- rm -Rf "$KERL_BUILD_DIR/$3"
- exit 1
- fi
- cd otp_src_git
- git branch -a | grep "$2" > /dev/null 2>&1
- if [ "$?" -eq 1 ]; then
- git checkout $2 > /dev/null 2>&1
- else
- git checkout -b $2 origin/$2 > /dev/null 2>&1
- fi
- if [ "$?" -eq 1 ]; then
- echo "Couldn't checkout specified version"
- rm -Rf "$KERL_BUILD_DIR/$3"
- exit 1
- fi
- LOGFILE="$KERL_BUILD_DIR/$3/opt_build.log"
- echo "Building Erlang/OTP $3 from git, please wait..."
- ./otp_build setup -a $KERL_CONFIGURE_OPTIONS > "$LOGFILE" 2>&1
- if [ "$?" -eq 1 ]; then
- echo "Build error, see $LOGFILE"
- exit 1
- fi
- rm -f "$LOGFILE"
- ./otp_build release -a "$KERL_BUILD_DIR/$3/release_git" > /dev/null 2>&1
- cd "$KERL_BUILD_DIR/$3/release_git"
- ./Install $INSTALL_OPT "$KERL_BUILD_DIR/$3/release_git" > /dev/null 2>&1
- echo "Erlang/OTP $3 from git has been successfully built"
- list_add builds "git,$3"
- if [ -z "$KERL_DISABLE_AGNER" ]; then
- echo "Fetching and building agner..."
- cd "$KERL_BUILD_DIR/$3" && \
- git clone https://github.com/agner/agner.git agner_git > /dev/null 2>&1 && \
- cd agner_git && \
- PATH="$KERL_BUILD_DIR/$3/otp_src_git/bin:$PATH" make > /dev/null 2>&1 && \
- if [ "$?" -eq 1 ]; then
- echo "Agner install failed"; exit 1
- fi
- echo "Agner has been successfully built"
- fi
- }
- do_build()
- {
- assert_valid_release $1
- assert_build_name_unused $2
- FILENAME=otp_src_$1.tar.gz
- if [ ! -f "$KERL_DOWNLOAD_DIR/$FILENAME" ]; then
- echo "Downloading $FILENAME to $KERL_DOWNLOAD_DIR"
- mkdir -p "$KERL_DOWNLOAD_DIR"
- curl $ERLANG_DOWNLOAD_URL/$FILENAME > "$KERL_DOWNLOAD_DIR/$FILENAME"
- update_checksum_file
- fi
- ensure_checksum_file
- echo "Verifying archive checksum..."
- SUM=`$MD5SUM "$KERL_DOWNLOAD_DIR/$FILENAME" | cut -d " " -f $MD5SUM_FIELD`
- ORIG_SUM=`grep $FILENAME "$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)"
- mkdir -p "$KERL_BUILD_DIR/$2"
- if [ ! -d "$KERL_BUILD_DIR/$2/otp_src_$1" ]; then
- echo "Extracting source code"
- cd "$KERL_BUILD_DIR/$2" && tar xfz "$KERL_DOWNLOAD_DIR/$FILENAME"
- fi
- echo "Building Erlang/OTP $1 ($2), please wait..."
- cd "$KERL_BUILD_DIR/$2/otp_src_$1"
- LOGFILE="$KERL_BUILD_DIR/$2/otp_build_$1.log"
- if [ -n "$KERL_USE_AUTOCONF" ]; then
- ./otp_build setup -a $KERL_CONFIGURE_OPTIONS > "$LOGFILE" 2>&1
- else
- ./otp_build configure $KERL_CONFIGURE_OPTIONS > "$LOGFILE" 2>&1 && \
- ./otp_build boot -a > "$LOGFILE" 2>&1
- fi
- if [ "$?" -eq 1 ]; then
- echo "Build failed, see $LOGFILE"
- list_remove builds "$1 $2"
- exit 1
- fi
- rm -f "$LOGFILE"
- ./otp_build release -a "$KERL_BUILD_DIR/$2/release_$1" > /dev/null 2>&1
- cd "$KERL_BUILD_DIR/$2/release_$1"
- ./Install $INSTALL_OPT "$KERL_BUILD_DIR/$2/release_$1" > /dev/null 2>&1
- echo "Erlang/OTP $1 ($2) has been successfully built"
- list_add builds "$1,$2"
- if agner_support $1; then
- echo "Fetching and building agner..."
- cd "$KERL_BUILD_DIR/$2" && \
- git clone https://github.com/agner/agner.git agner_$1 > /dev/null 2>&1 && \
- cd agner_$1 && \
- PATH="$KERL_BUILD_DIR/$2/otp_src_$1/bin:$PATH" make > /dev/null 2>&1 && \
- if [ "$?" -eq 1 ]; then
- echo "Agner install failed"; exit 1
- fi
- echo "Agner has been successfully built"
- fi
- }
- do_install()
- {
- rel=`get_release_from_name $1`
- if [ "$?" -eq 1 ]; then
- echo "No build named $1"
- exit 1
- fi
- mkdir -p "$2"
- if [ ! -d "$2" ]; then
- echo "Destination is not a directory"
- exit 1
- fi
- absdir=`cd "$2" && pwd`
- echo "Installing Erlang/OTP $rel ($1) in $absdir..."
- cd "$KERL_BUILD_DIR/$1/otp_src_$rel"
- ./otp_build release -a "$absdir" > /dev/null 2>&1 &&
- cd "$absdir" && ./Install $INSTALL_OPT "$absdir" > /dev/null 2>&1
- if [ $? -eq 1 ]; then
- echo "Couldn't install Erlang/OTP $rel ($1) in $absdir"
- exit 1
- fi
- list_add installations "$1 $absdir";
- cat <<ACTIVATE > "$absdir/activate"
- # credits to virtualenv
- kerl_deactivate()
- {
- if [ -n "\$_KERL_SAVED_PATH" ]; then
- PATH="\$_KERL_SAVED_PATH"
- export PATH
- unset _KERL_SAVED_PATH
- fi
- if [ -n "\$_KERL_SAVED_AGNER_BIN" ]; then
- AGNER_BIN="\$_KERL_SAVED_AGNER_BIN"
- export AGNER_BIN
- unset _KERL_SAVED_AGNER_BIN
- fi
- if [ -n "\$_KERL_SAVED_AGNER_EXACT_PREFIX" ]; then
- AGNER_EXACT_PREFIX="\$_KERL_SAVED_AGNER_EXACT_PREFIX"
- export AGNER_EXACT_PREFIX
- unset _KERL_SAVED_AGNER_EXACT_PREFIX
- 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 "\$BASH" -o -n "\$ZSH_VERSION" ]; then
- hash -r
- fi
- if [ ! "\$1" = "nondestructive" ]; then
- unset -f kerl_deactivate
- fi
- }
- kerl_deactivate nondestructive
- _KERL_SAVED_PATH="\$PATH"
- export _KERL_SAVED_PATH
- _KERL_SAVED_AGNER_BIN="\$AGNER_BIN"
- export _KERL_SAVED_AGNER_BIN
- _KERL_SAVED_AGNER_EXACT_PREFIX="\$AGNER_EXACT_PREFIX"
- export _KERL_SAVED_AGNER_EXACT_PREFIX
- _KERL_SAVED_REBAR_PLT_DIR="\$REBAR_PLT_DIR"
- export _KERL_SAVED_REBAR_PLT_DIR
- PATH="$absdir/bin:\$PATH"
- export PATH
- AGNER_BIN="$absdir/bin"
- export AGNER_BIN
- AGNER_EXACT_PREFIX="$absdir/lib"
- export AGNER_EXACT_PREFIX
- REBAR_PLT_DIR="$absdir"
- export REBAR_PLT_DIR
- if [ -n "\$BASH" -o -n "\$ZSH_VERSION" ]; then
- hash -r
- fi
- ACTIVATE
- if agner_support $1; then
- echo "Installing agner in $absdir..."
- cp "$KERL_BUILD_DIR/$1/agner_$rel/agner" "$absdir/bin/"
- if [ -n "$KERL_INSTALL_AGNERIZED_REBAR" ]; then
- echo "Installing agnerized rebar in $absdir..."
- cp "$KERL_BUILD_DIR/$1/agner_$rel/agner" "$absdir/bin/rebar"
- fi
- if [ -n "$KERL_AGNER_AUTOINSTALL" ]; then
- for i in $KERL_AGNER_AUTOINSTALL; do
- echo "Autoinstalling $i"
- agner install $i > /dev/null 2>&1
- done
- fi
- 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"
- }
- list_print()
- {
- if [ -f $KERL_BASE_DIR/otp_$1 ]; then
- if [ "`cat "$KERL_BASE_DIR/otp_$1" | wc -l`" != "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
- for l in `cat "$KERL_BASE_DIR/otp_$1"`; do
- if [ "$l" = "$2" ]; then
- return 1
- fi
- done
- 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 <releases|builds|installations>"
- }
- delete_usage()
- {
- echo "usage: $0 delete <build|installation> <build_name or path>"
- }
- update_usage()
- {
- echo "usage: $0 $1 <releases|agner>"
- }
- do_active()
- {
- if [ -n "$_KERL_SAVED_PATH" ]; then
- echo "The current active installation is:"
- echo `echo $PATH | cut -d ":" -f 1 | sed 's/\(.*\)..../\1/'`
- return 0
- else
- echo "No Erlang/OTP kerl installation is currently active"
- return 1
- fi
- }
- case "$1" in
- 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_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
- do_install $2 .
- 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
- ;;
- agner)
- if [ $# -ne 3 ]; then
- echo "usage: $0 $1 $2 <build_name>"
- exit 1
- fi
- if agner_support $3; then
- echo "Updating agner for build $3..."
- if do_update_agner $3; then
- echo "agner has been updated successfully"
- else
- echo "failed to update agner"
- exit 1
- fi
- fi
- ;;
- *)
- 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
- rm -Rf "$KERL_BUILD_DIR/$3"
- list_remove $2s "$rel,$3"
- echo "The $3 build has been deleted"
- else
- echo "No build named $3"
- exit 1
- fi
- ;;
- installation)
- if is_valid_installation "$3"; then
- rm -Rf "$3"
- escaped=`echo "$3" | sed $SED_OPT -e 's#/$##' -e 's#\/#\\\/#g'`
- list_remove $2s "$escaped"
- echo "The installation in $3 has been deleted"
- else
- echo "$3 is not a kerl-managed Erlang/OTP installation"
- exit 1
- fi
- ;;
- *)
- echo "Cannot delete $2"
- delete_usage
- exit 1
- ;;
- esac
- ;;
- active)
- if ! do_active; then
- exit 1;
- fi
- ;;
- status)
- echo "Available builds:"
- list_print builds
- echo "----------"
- echo "Available installations:"
- list_print installations
- echo "----------"
- do_active
- exit 0
- ;;
- *)
- echo "unkwnown command: $1"; usage; exit 1
- ;;
- esac