PageRenderTime 59ms CodeModel.GetById 2ms app.highlight 51ms RepoModel.GetById 2ms app.codeStats 0ms

/kerl

http://github.com/evax/kerl
Shell | 646 lines | 592 code | 29 blank | 25 comment | 59 complexity | 33f0bec8a912cfd875336fd86cf841c3 MD5 | raw file
  1#! /bin/sh
  2
  3# Copyright (c) 2011 Spawngrid, Inc
  4# Copyright (c) 2011 Evax Software <contact(at)evax(dot)org>
  5#
  6# Permission is hereby granted, free of charge, to any person obtaining a copy
  7# of this software and associated documentation files (the "Software"), to deal
  8# in the Software without restriction, including without limitation the rights
  9# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10# copies of the Software, and to permit persons to whom the Software is
 11# furnished to do so, subject to the following conditions:
 12#
 13# The above copyright notice and this permission notice shall be included in
 14# all copies or substantial portions of the Software.
 15#
 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 22# THE SOFTWARE.
 23
 24ERLANG_DOWNLOAD_URL=http://www.erlang.org/download
 25
 26KERL_BASE_DIR="$HOME/.kerl"
 27KERL_CONFIG="$HOME/.kerlrc"
 28KERL_DOWNLOAD_DIR="$KERL_BASE_DIR/archives"
 29KERL_BUILD_DIR="$KERL_BASE_DIR/builds"
 30if [ -n "$KERL_CONFIGURE_OPTIONS" ]; then
 31    _KCO="$KERL_CONFIGURE_OPTIONS"
 32fi
 33if [ -n "$KERL_SASL_STARTUP" ]; then
 34    _KSS="$KERL_SASL_STARTUP"
 35fi
 36if [ -n "$KERL_AGNER_AUTOINSTALL" ]; then
 37    _KAA="$KERL_AGNER_AUTOINSTALL"
 38fi
 39KERL_CONFIGURE_OPTIONS=
 40KERL_DISABLE_AGNER=
 41KERL_SASL_STARTUP=
 42
 43# ensure the base dir exsists
 44mkdir -p "$KERL_BASE_DIR"
 45
 46# source the config file if available
 47if [ -f "$KERL_CONFIG" ]; then . "$KERL_CONFIG"; fi
 48
 49if [ -n "$_KCO" ]; then
 50    KERL_CONFIGURE_OPTIONS="$_KCO"
 51fi
 52if [ -n "$_KSS" ]; then
 53    KERL_SASL_STARTUP="$_KSS"
 54fi
 55if [ -n "$_KAA" ]; then
 56    KERL_AGNER_AUTOINSTALL="$_KAA"
 57fi
 58
 59if [ -z "$KERL_SASL_STARTUP" ]; then
 60    INSTALL_OPT=-minimal
 61else
 62    INSTALL_OPT=-sasl
 63fi
 64
 65KERL_SYSTEM=`uname -s`
 66case "$KERL_SYSTEM" in
 67    Darwin)
 68        MD5SUM="openssl md5"
 69        MD5SUM_FIELD=2
 70        SED_OPT=-E
 71        if [ `gcc --version | grep llvm | wc -l` = "1" ]; then
 72            if [ -x `which gcc-4.2` ]; then
 73                echo "Adjust compiler settings for OS X: using gcc-4.2"
 74                KERL_CONFIGURE_OPTIONS="CC=gcc-4.2 $KERL_CONFIGURE_OPTIONS"
 75            else
 76                echo "Adjust compiler settings for OS X: using -O0"
 77                KERL_CONFIGURE_OPTIONS="CFLAGS=-O0 $KERL_CONFIGURE_OPTIONS"
 78            fi
 79        fi
 80        ;;
 81    *)
 82        MD5SUM=md5sum
 83        MD5SUM_FIELD=1
 84        SED_OPT=-r
 85        ;;
 86esac
 87
 88usage()
 89{
 90    echo "kerl: build and install Erlang/OTP"
 91    echo "usage: $0 <command> [options ...]"
 92    echo "\n  <command>       Command to be executed\n"
 93    echo "Valid commands are:"
 94    echo "  build    Build specified release or git repository"
 95    echo "  install  Install the specified release at the given location"
 96    echo "  update   Update agner or the list of available releases from erlang.org"
 97    echo "  list     List releases, builds and installations"
 98    echo "  delete   Delete builds and installations"
 99    echo "  active   Print the path of the active installation"
100    echo "  status   Print available builds and installations"
101    exit 1
102}
103
104if [ $# -eq 0 ]; then usage; fi
105
106get_releases()
107{
108    curl -s $ERLANG_DOWNLOAD_URL/ | \
109        sed $SED_OPT -e 's/^.*>otp_src_(R1[-1234567890ABCD]+)\.tar\.gz<.*$/\1/' \
110                     -e '/^R/!d'
111}
112
113update_checksum_file()
114{
115    echo "Getting the checksum file from erlang.org..."
116    curl $ERLANG_DOWNLOAD_URL/MD5 > "$KERL_DOWNLOAD_DIR/MD5" || exit 1
117}
118
119ensure_checksum_file()
120{
121    if [ ! -f "$KERL_DOWNLOAD_DIR/MD5" ]; then
122        update_checksum_file
123    fi
124}
125
126check_releases()
127{
128    if [ ! -f "$KERL_BASE_DIR/otp_releases" ]; then
129        echo "Getting the available releases from erlang.org..."
130        get_releases > "$KERL_BASE_DIR/otp_releases"
131    fi
132}
133
134# c.f. agner issue #98
135# https://github.com/agner/agner/issues/#issue/98
136KERL_NO_AGNER_SUPPORT="R10B-0 R10B-2 R10B-3 R10B-4 R10B-5 R10B-6 R10B-7
137R10B-8 R10B-9 R11B-0 R11B-1 R11B-2 R11B-3 R11B-4 R11B-5 R12B-0 R12B-1
138R12B-2 R12B-3 R12B-4 R12B-5 R13A R13B R13B01 R13B02 R13B03 R13B04"
139
140agner_support()
141{
142    if [ -z "$KERL_DISABLE_AGNER" ]; then
143        return 1;
144    fi
145
146    for v in $KERL_NO_AGNER_SUPPORT; do
147        if [ "$v" = "$1" ]; then
148            return 1
149        fi
150    done
151
152    return 0
153}
154
155
156is_valid_release()
157{
158    check_releases
159    for rel in `cat $KERL_BASE_DIR/otp_releases`; do
160        if [ "$1" = "$rel" ]; then
161            return 0
162        fi
163    done
164    return 1
165}
166
167assert_valid_release()
168{
169    if ! is_valid_release $1; then
170        echo "$1 is not a valid Erlang/OTP release"
171        exit 1
172    fi
173    return 0
174}
175
176get_release_from_name()
177{
178    if [ -f "$KERL_BASE_DIR/otp_builds" ]; then
179        for l in `cat "$KERL_BASE_DIR/otp_builds"`; do
180            rel=`echo $l | cut -d "," -f 1`
181            name=`echo $l | cut -d "," -f 2`
182            if [ "$name" = "$1" ]; then
183                echo "$rel"
184                return 0
185            fi
186        done
187    fi
188    return 1
189}
190
191is_valid_installation()
192{
193    if [ -f "$1/activate" ]; then
194        return 0
195    fi
196    return 1
197}
198
199do_update_agner()
200{
201    rel=`get_release_from_name $1`
202    if [ "$?" -eq 1 ]; then
203        echo "Unknown build name $1"
204        exit 1
205    fi
206    TARGET="$KERL_BUILD_DIR/$1/release_$rel"
207    cd "$KERL_BUILD_DIR/$1/agner_$rel" && \
208        git pull &&
209        PATH="$KERL_BUILD_DIR/$1/otp_src_$rel/bin:$PATH" \
210            make > /dev/null 2>&1
211    if [ "$?" -eq 1 ]; then
212        return 1
213    fi
214    return 0
215}
216
217assert_build_name_unused()
218{
219    if [ -f "$KERL_BASE_DIR/otp_builds" ]; then
220        for l in `cat "$KERL_BASE_DIR/otp_builds"`; do
221            name=`echo $l | cut -d "," -f 2`
222            if [ "$name" = "$1" ]; then
223                echo "There's already a build named $1"
224                exit 1
225            fi
226        done
227    fi
228}
229
230do_git_build()
231{
232    assert_build_name_unused $3
233    mkdir -p "$KERL_BUILD_DIR/$3"
234    cd "$KERL_BUILD_DIR/$3"
235    echo "Checking Erlang/OTP git repository from $1..."
236    git clone $1 otp_src_git > /dev/null 2>&1
237    if [ "$?" -eq 1 ]; then
238        echo "Error retriving git repository"
239        exit 1
240    fi
241    if [ ! -x otp_src_git/otp_build ]; then
242        echo "Not a valid Erlang/OTP repository"
243        rm -Rf "$KERL_BUILD_DIR/$3"
244        exit 1
245    fi
246    cd otp_src_git
247    git branch -a | grep "$2" > /dev/null 2>&1
248    if [ "$?" -eq 1 ]; then
249        git checkout $2 > /dev/null 2>&1
250    else
251        git checkout -b $2 origin/$2 > /dev/null 2>&1
252    fi
253    if [ "$?" -eq 1 ]; then
254        echo "Couldn't checkout specified version"
255        rm -Rf "$KERL_BUILD_DIR/$3"
256        exit 1
257    fi
258    LOGFILE="$KERL_BUILD_DIR/$3/opt_build.log"
259    echo "Building Erlang/OTP $3 from git, please wait..."
260    ./otp_build setup -a $KERL_CONFIGURE_OPTIONS > "$LOGFILE" 2>&1
261    if [ "$?" -eq 1 ]; then
262        echo "Build error, see $LOGFILE"
263        exit 1
264    fi
265    rm -f "$LOGFILE"
266    ./otp_build release -a "$KERL_BUILD_DIR/$3/release_git" > /dev/null 2>&1
267    cd "$KERL_BUILD_DIR/$3/release_git"
268    ./Install $INSTALL_OPT "$KERL_BUILD_DIR/$3/release_git" > /dev/null 2>&1
269    echo "Erlang/OTP $3 from git has been successfully built"
270    list_add builds "git,$3"
271    if [ -z "$KERL_DISABLE_AGNER" ]; then
272        echo "Fetching and building agner..."
273        cd "$KERL_BUILD_DIR/$3" && \
274        git clone https://github.com/agner/agner.git agner_git > /dev/null 2>&1 && \
275            cd agner_git && \
276            PATH="$KERL_BUILD_DIR/$3/otp_src_git/bin:$PATH" make > /dev/null 2>&1 && \
277        if [ "$?" -eq 1 ]; then
278            echo "Agner install failed"; exit 1
279        fi
280        echo "Agner has been successfully built"
281    fi
282}
283
284do_build()
285{
286    assert_valid_release $1
287    assert_build_name_unused $2
288
289    FILENAME=otp_src_$1.tar.gz
290    if [ ! -f "$KERL_DOWNLOAD_DIR/$FILENAME" ]; then
291        echo "Downloading $FILENAME to $KERL_DOWNLOAD_DIR"
292        mkdir -p "$KERL_DOWNLOAD_DIR"
293        curl $ERLANG_DOWNLOAD_URL/$FILENAME > "$KERL_DOWNLOAD_DIR/$FILENAME"
294        update_checksum_file
295    fi
296    ensure_checksum_file
297    echo "Verifying archive checksum..."
298    SUM=`$MD5SUM "$KERL_DOWNLOAD_DIR/$FILENAME" | cut -d " " -f $MD5SUM_FIELD`
299    ORIG_SUM=`grep $FILENAME "$KERL_DOWNLOAD_DIR/MD5" | cut -d " " -f 2`
300    if [ "$SUM" != "$ORIG_SUM" ]; then
301        echo "Checksum error, check the files in $KERL_DOWNLOAD_DIR"
302        exit 1
303    fi
304    echo "Checksum verified ($SUM)"
305    mkdir -p "$KERL_BUILD_DIR/$2"
306    if [ ! -d "$KERL_BUILD_DIR/$2/otp_src_$1" ]; then
307        echo "Extracting source code"
308        cd "$KERL_BUILD_DIR/$2" && tar xfz "$KERL_DOWNLOAD_DIR/$FILENAME"
309    fi
310    echo "Building Erlang/OTP $1 ($2), please wait..."
311    cd "$KERL_BUILD_DIR/$2/otp_src_$1"
312    LOGFILE="$KERL_BUILD_DIR/$2/otp_build_$1.log"
313    if [ -n "$KERL_USE_AUTOCONF" ]; then
314        ./otp_build setup -a $KERL_CONFIGURE_OPTIONS > "$LOGFILE" 2>&1
315    else
316        ./otp_build configure $KERL_CONFIGURE_OPTIONS > "$LOGFILE" 2>&1 && \
317            ./otp_build boot -a > "$LOGFILE" 2>&1
318    fi
319    if [ "$?" -eq 1 ]; then
320        echo "Build failed, see $LOGFILE"
321        list_remove builds "$1 $2"
322        exit 1
323    fi
324    rm -f "$LOGFILE"
325    ./otp_build release -a "$KERL_BUILD_DIR/$2/release_$1" > /dev/null 2>&1
326    cd "$KERL_BUILD_DIR/$2/release_$1"
327    ./Install $INSTALL_OPT "$KERL_BUILD_DIR/$2/release_$1" > /dev/null 2>&1
328    echo "Erlang/OTP $1 ($2) has been successfully built"
329    list_add builds "$1,$2"
330    if agner_support $1; then
331        echo "Fetching and building agner..."
332        cd "$KERL_BUILD_DIR/$2" && \
333        git clone https://github.com/agner/agner.git agner_$1 > /dev/null 2>&1 && \
334            cd agner_$1 && \
335            PATH="$KERL_BUILD_DIR/$2/otp_src_$1/bin:$PATH" make > /dev/null 2>&1 && \
336        if [ "$?" -eq 1 ]; then
337            echo "Agner install failed"; exit 1
338        fi
339        echo "Agner has been successfully built"
340    fi
341}
342
343do_install()
344{
345    rel=`get_release_from_name $1`
346    if [ "$?" -eq 1 ]; then
347        echo "No build named $1"
348        exit 1
349    fi
350    mkdir -p "$2"
351    if [ ! -d "$2" ]; then
352        echo "Destination is not a directory"
353        exit 1
354    fi
355    absdir=`cd "$2" && pwd`
356    echo "Installing Erlang/OTP $rel ($1) in $absdir..."
357    cd "$KERL_BUILD_DIR/$1/otp_src_$rel"
358    ./otp_build release -a "$absdir" > /dev/null 2>&1 &&
359        cd "$absdir" && ./Install $INSTALL_OPT "$absdir" > /dev/null 2>&1
360    if [ $? -eq 1 ]; then
361        echo "Couldn't install Erlang/OTP $rel ($1) in $absdir"
362        exit 1
363    fi
364    list_add installations "$1 $absdir";
365    cat <<ACTIVATE > "$absdir/activate"
366# credits to virtualenv
367kerl_deactivate()
368{
369    if [ -n "\$_KERL_SAVED_PATH" ]; then
370        PATH="\$_KERL_SAVED_PATH"
371        export PATH
372        unset _KERL_SAVED_PATH
373    fi
374    if [ -n "\$_KERL_SAVED_AGNER_BIN" ]; then
375        AGNER_BIN="\$_KERL_SAVED_AGNER_BIN"
376        export AGNER_BIN
377        unset _KERL_SAVED_AGNER_BIN
378    fi
379    if [ -n "\$_KERL_SAVED_AGNER_EXACT_PREFIX" ]; then
380        AGNER_EXACT_PREFIX="\$_KERL_SAVED_AGNER_EXACT_PREFIX"
381        export AGNER_EXACT_PREFIX
382        unset _KERL_SAVED_AGNER_EXACT_PREFIX
383    fi
384    if [ -n "\$_KERL_SAVED_REBAR_PLT_DIR" ]; then
385        REBAR_PLT_DIR="\$_KERL_SAVED_REBAR_PLT_DIR"
386        export REBAR_PLT_DIR
387        unset _KERL_SAVED_REBAR_PLT_DIR
388    fi
389    if [ -n "\$BASH" -o -n "\$ZSH_VERSION" ]; then
390        hash -r
391    fi
392    if [ ! "\$1" = "nondestructive" ]; then
393        unset -f kerl_deactivate
394    fi
395}
396kerl_deactivate nondestructive
397_KERL_SAVED_PATH="\$PATH"
398export _KERL_SAVED_PATH
399_KERL_SAVED_AGNER_BIN="\$AGNER_BIN"
400export _KERL_SAVED_AGNER_BIN
401_KERL_SAVED_AGNER_EXACT_PREFIX="\$AGNER_EXACT_PREFIX"
402export _KERL_SAVED_AGNER_EXACT_PREFIX
403_KERL_SAVED_REBAR_PLT_DIR="\$REBAR_PLT_DIR"
404export _KERL_SAVED_REBAR_PLT_DIR
405PATH="$absdir/bin:\$PATH"
406export PATH
407AGNER_BIN="$absdir/bin"
408export AGNER_BIN
409AGNER_EXACT_PREFIX="$absdir/lib"
410export AGNER_EXACT_PREFIX
411REBAR_PLT_DIR="$absdir"
412export REBAR_PLT_DIR
413if [ -n "\$BASH" -o -n "\$ZSH_VERSION" ]; then
414    hash -r
415fi
416ACTIVATE
417    if agner_support $1; then
418        echo "Installing agner in $absdir..."
419        cp "$KERL_BUILD_DIR/$1/agner_$rel/agner" "$absdir/bin/"
420        if [ -n "$KERL_INSTALL_AGNERIZED_REBAR" ]; then
421            echo "Installing agnerized rebar in $absdir..."
422            cp "$KERL_BUILD_DIR/$1/agner_$rel/agner" "$absdir/bin/rebar"
423        fi
424        if [ -n "$KERL_AGNER_AUTOINSTALL" ]; then
425            for i in $KERL_AGNER_AUTOINSTALL; do
426                echo "Autoinstalling $i"
427                agner install $i > /dev/null 2>&1
428            done
429        fi
430    fi
431    echo "You can activate this installation running the following command:"
432    echo ". $absdir/activate"
433    echo "Later on, you can leave the installation typing:"
434    echo "kerl_deactivate"
435}
436
437list_print()
438{
439    if [ -f $KERL_BASE_DIR/otp_$1 ]; then
440        if [ "`cat "$KERL_BASE_DIR/otp_$1" | wc -l`" != "0" ]; then
441            if [ -z "$2" ]; then
442                cat "$KERL_BASE_DIR/otp_$1"
443            else
444                echo `cat "$KERL_BASE_DIR/otp_$1"`
445            fi
446            return 0
447        fi
448    fi
449    echo "There are no $1 available"
450}
451
452list_add()
453{
454    if [ -f "$KERL_BASE_DIR/otp_$1" ]; then
455        for l in `cat "$KERL_BASE_DIR/otp_$1"`; do
456            if [ "$l" = "$2" ]; then
457                return 1
458            fi
459        done
460        echo "$2" >> "$KERL_BASE_DIR/otp_$1"
461    else
462        echo "$2" > "$KERL_BASE_DIR/otp_$1"
463    fi
464}
465
466list_remove()
467{
468    if [ -f "$KERL_BASE_DIR/otp_$1" ]; then
469        sed $SED_OPT -i -e "/^.*$2$/d" "$KERL_BASE_DIR/otp_$1"
470    fi
471}
472
473list_has()
474{
475    if [ -f "$KERL_BASE_DIR/otp_$1" ]; then
476        grep $2 "$KERL_BASE_DIR/otp_$1" > /dev/null 2>&1 && return 0
477    fi
478    return 1
479}
480
481list_usage()
482{
483    echo "usage: $0 list <releases|builds|installations>"
484}
485
486delete_usage()
487{
488    echo "usage: $0 delete <build|installation> <build_name or path>"
489}
490
491update_usage()
492{
493    echo "usage: $0 $1 <releases|agner>"
494}
495
496do_active()
497{
498    if [ -n "$_KERL_SAVED_PATH" ]; then
499        echo "The current active installation is:"
500        echo `echo $PATH | cut -d ":" -f 1 | sed 's/\(.*\)..../\1/'`
501        return 0
502    else
503        echo "No Erlang/OTP kerl installation is currently active"
504        return 1
505    fi
506}
507
508case "$1" in
509    build)
510        if [ "$2" = "git" ]; then
511            if [ $# -ne 5 ]; then
512                echo "usage: $0 $1 $2 <git_url> <git_version> <build_name>"
513                exit 1
514            fi
515            do_git_build $3 $4 $5
516        else
517            if [ $# -lt 3 ]; then
518                echo "usage: $0 $1 <release> <build_name>"
519                exit 1
520            fi
521            do_build $2 $3
522        fi
523        ;;
524    install)
525        if [ $# -lt 2 ]; then
526            echo "usage: $0 $1 <build_name> [directory]"
527            exit 1
528        fi
529        if [ $# -eq 3 ]; then
530            do_install $2 "$3"
531        else
532            do_install $2 .
533        fi
534        ;;
535    update)
536        if [ $# -lt 2 ]; then
537            update_usage
538            exit 1
539        fi
540        case "$2" in
541            releases)
542                rm -f "$KERL_BASE_DIR/otp_releases"
543                check_releases
544                echo "The available releases are:"
545                list_print releases spaces
546                ;;
547            agner)
548                if [ $# -ne 3 ]; then
549                    echo "usage: $0 $1 $2 <build_name>"
550                    exit 1
551                fi
552                if agner_support $3; then
553                    echo "Updating agner for build $3..."
554                    if do_update_agner $3; then
555                        echo "agner has been updated successfully"
556                    else
557                        echo "failed to update agner"
558                        exit 1
559                    fi
560                fi
561                ;;
562            *)
563                update_usage
564                exit 1
565                ;;
566        esac
567        ;;
568    list)
569        if [ $# -ne 2 ]; then
570            list_usage
571            exit 1
572        fi
573        case "$2" in
574            releases)
575                check_releases
576                list_print $2 space
577                echo "Run \"$0 update releases\" to update this list from erlang.org"
578                ;;
579            builds)
580                list_print $2
581                ;;
582            installations)
583                list_print $2
584                ;;
585            *)
586                echo "Cannot list $2"
587                list_usage
588                exit 1
589                ;;
590        esac
591        ;;
592    delete)
593        if [ $# -ne 3 ]; then
594            delete_usage
595            exit 1
596        fi
597        case "$2" in
598            build)
599                rel=`get_release_from_name $3`
600                if [ -d "$KERL_BUILD_DIR/$3" ]; then
601                    rm -Rf "$KERL_BUILD_DIR/$3"
602                    list_remove $2s "$rel,$3"
603                    echo "The $3 build has been deleted"
604                else
605                    echo "No build named $3"
606                    exit 1
607                fi
608                ;;
609            installation)
610                if is_valid_installation "$3"; then
611                    rm -Rf "$3"
612                    escaped=`echo "$3" | sed $SED_OPT -e 's#/$##' -e 's#\/#\\\/#g'`
613                    list_remove $2s "$escaped"
614                    echo "The installation in $3 has been deleted"
615                else
616                    echo "$3 is not a kerl-managed Erlang/OTP installation"
617                    exit 1
618                fi
619                ;;
620            *)
621                echo "Cannot delete $2"
622                delete_usage
623                exit 1
624                ;;
625        esac
626        ;;
627    active)
628        if ! do_active; then
629            exit 1;
630        fi
631        ;;
632    status)
633        echo "Available builds:"
634        list_print builds
635        echo "----------"
636        echo "Available installations:"
637        list_print installations
638        echo "----------"
639        do_active
640        exit 0
641        ;;
642    *)
643        echo "unkwnown command: $1"; usage; exit 1
644        ;;
645esac
646