aboutsummaryrefslogblamecommitdiffstats
path: root/kerl
blob: aaf1c05ce70e842432e4c46afee0cf43bbb60144 (plain) (tree)




























                                                                               
                   
                  
 


                             


                                                   





                                    













                          

       





                                                                         
                                                                                    
                                                             
                                                     
                                                               
                                                              




                               

              
                                     

                                                                                 

 

                      



                                                                      

                      




                                              

                





                                                                





                                                                       

               










                                           

                      









                                                    

                       





                                 














                                                                  









                                                                            
                                                                              
                                                                        




                                                                    


                                                  
                                     
                                                                      

                                                 

                                                                                              
                           
                                                                     
                             
              
      



                                                                        
                                                    
                      

                                             
                                 
                                                                                   


                                                                                 




                                                

 

            










                                                                  
                                                 
                                 

                                                                         




                                                        

                                       

                 









                                             



                                                             












                                                  

                                                     



                         
                                
                         



                                              
                             
                                             













                                                                             
      

                                                                            

                                                           

 

            










                                            

          
                                         

                                                             
        
                                         


      

             
                                           
                                                              


      

          

                                                                    



            

            


                                                         

              


                                                           






                                        









                                                                  













                                                             
                              




                           































                                                                  









                                   
                                                                                     













                                     










                                                            
                                                      









                                                        
                                                                       













                                                                           
           

                            

          










                                             



                                                  
 
#! /bin/sh

# 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
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 [ -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
        ;;
    *)
        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"
    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
        for v in $KERL_NO_AGNER_SUPPORT; do
            if [ "$v" = "$1" ]; then
                return 1
            fi
        done
        return 0
    fi
    return 1 
}

assert_valid_release()
{
    check_releases
    for rel in `cat $KERL_BASE_DIR/otp_releases`; do
        if [ "$1" = "$rel" ]; then
            return 0
        fi
    done
   echo "$1 is not a valid Erlang/OTP release" 
   exit 1
}

is_valid_installation()
{
    if [ -f "$1/activate" ]; then
        return 0
    fi
    return 1
}

do_update_agner()
{
    assert_valid_release $1
    TARGET=$KERL_BUILD_DIR/release_$1
    cd "$KERL_BUILD_DIR/agner_$1" && \
        AGNER_BIN="$TARGET/bin" AGNER_EXACT_PREFIX="$TARGET/lib" \
            ./agner install agner > /dev/null 2>&1
    if [ "$?" -eq 1 ]; then
        return 1
    fi
    return 0
}

do_build()
{
    assert_valid_release $1
    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"
    mkdir -p "$KERL_BASE_DIR/logs"
    if [ ! -d "$KERL_BUILD_DIR/otp_src_$1" ]; then
        echo "Extracting source code"
        cd "$KERL_BUILD_DIR" && tar xfz "$KERL_DOWNLOAD_DIR/$FILENAME"
    fi
    echo "Building Erlang/OTP $1, please wait..."
    cd "$KERL_BUILD_DIR/otp_src_$1"
    ./otp_build setup -a $KERL_CONFIGURE_OPTIONS > "$KERL_BASE_DIR/logs/otp_build_$1.log" 2>&1
    if [ "$?" -eq 1 ]; then
        echo "Build failed, see $KERL_BASE_DIR/logs/otp_build_$1.log"
        list_remove builds $2
        exit 1
    fi
    rm -f "$KERL_BASE_DIR/logs/otp_build_$1.log"
    ./otp_build release -a "$KERL_BUILD_DIR/release_$1" > /dev/null 2>&1
    cd "$KERL_BUILD_DIR/release_$1"
    ./Install $INSTALL_OPT "$KERL_BUILD_DIR/release_$1" > /dev/null 2>&1
    echo "Erlang/OTP $1 has been successfully built"
    list_add builds $1
    if agner_support $1; then
        echo "Fetching and building agner..."
        cd "$KERL_BUILD_DIR" && \
        git clone https://github.com/agner/agner.git agner_$1 > /dev/null 2>&1 && \
            cd agner_$1 && \
            PATH="$KERL_BASE_DIR/otp_src_$1/bin:$PATH" make > /dev/null 2>&1 && \
            do_update_agner $1
        if [ "$?" -eq 1 ]; then
            echo "Agner install failed"; exit 1
        fi
        echo "Agner has been successfully built"
    fi
}

do_install()
{
    assert_valid_release $1
    if ! list_has builds $1; then
        echo "You must build the $1 realease before installing it"
        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 $1 in $absdir..."
    cd $KERL_BUILD_DIR/otp_src_$1
    ./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 $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 "\$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
PATH="$absdir/bin:\$PATH"
export PATH
AGNER_BIN="$absdir/bin"
export AGNER_BIN
AGNER_EXACT_PREFIX="$absdir/lib"
export AGNER_EXACT_PREFIX
if [ -n "\$BASH" -o -n "\$ZSH_VERSION" ]; then
    hash -r
fi
ACTIVATE
    if agner_support $1; then
        echo "Installing agner in $absdir..."
        cp -R "$KERL_BUILD_DIR/release_$1/lib/agner-@master" "$absdir/lib/"
        cd "$absdir/bin" && ln -s "$absdir/lib/agner-@master/bin/agner" agner
        #. "$absdir/activate" && cd "$KERL_BASE_DIR/builds/agner_$1" && \
        #./agner install agner > /dev/null 2>&1
        #if [ "$?" -eq 1 ]; then
        #    echo "Couldn' install agner in $absdir"
        #    exit 1
        #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 [ -z "$2" ]; then
            cat $KERL_BASE_DIR/otp_$1
        else
            echo `cat $KERL_BASE_DIR/otp_$1`
        fi
    else
        echo "There are no $1 available"
    fi
}

list_add()
{
    if [ -f $KERL_BASE_DIR/otp_$1 ]; then
        grep "$2" $KERL_BASE_DIR/otp_$1 > /dev/null 2>&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 <releases|builds|installations>"
}

delete_usage()
{
    echo "usage: $0 delete <build|installation> id_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 | head -c -4`
        return 0
    else
        echo "No Erlang/OTP kerl installation is currently active"
        return 1
    fi
}

case "$1" in
    build)
        if [ $# -ne 2 ]; then
            echo "specify a release to install (e.g. R14B02)"
            exit 1
        fi
        do_build $2
        ;;
    install)
        if [ $# -lt 2 ]; then
            echo "usage: $0 $1 <release> [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>"
                    exit 1
                fi
                assert_valid_release $3
                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)
                assert_valid_release $3
                if [ -d "$KERL_BUILD_DIR/otp_src_$3" ]; then
                    rm -Rf $KERL_BUILD_DIR/otp_src_$3 
                    rm -Rf $KERL_BUILD_DIR/agner_$3 
                    rm -Rf $KERL_BUILD_DIR/release_$3 
                    list_remove $2s $3
                    echo "The $3 build has been deleted"
                else
                    echo "No build for Erlang/OTP $3"
                    exit 1
                fi
                ;;
            installation)
                if is_valid_installation "$3"; then
                    rm -Rf "$3"
                    escaped=`echo "$3" | sed $SED_OPT -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 "----------"
        echo "Currently active installation:"
        do_active
        exit 0
        ;;
    *)
        echo "unkwnown command: $1"; usage; exit 1
        ;;
esac