chrb: función wrapper de chruby y ruby-build para mksh

17 Dec
Published by antonio.hernandez in

Tags 

Desarrollo, Ruby, Shell

Para trabajar con distintas versiones de ruby hago uso de chruby y ruby-build por ser herramientas que me han sido mucho más simples de comprender en su funcionamiento y para facilitarme aún más el uso de estás herramientas he hecho una función wrapper para mksh, mi shell actualmente de uso.

La función se llama chrb y me permite actualizar a chruby/ruby-build, instalar/desinstalar definiciones de ruby así como cambiar de versión de ruby entre proyectos.

Dicha función está definida en el siguiente archivo y lo integro a mi entorno con la siguiente línea en $HOME/.mkshrc: source $HOME/.chrb.mksh

# $HOME/.chrb.mksh
# chrb = (chruby + ruby-build) / mksh
#
# Copyright © 2013 Antonio Hernández Blas <hba.nihilismus@gmail.com>
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://www.wtfpl.net/ for more details.

chrb() {
    typeset chrb_base_dir=$HOME/.chrb
    typeset chrb_install_dir=$chrb_base_dir/local
    mkdir -p $chrb_install_dir

    if [[ :$PATH: != *:$chrb_install_dir/bin:* ]];then
        PATH=$chrb_install_dir/bin:$PATH
    fi

    typeset chrb_rubies_dir=$chrb_base_dir/rubies
    mkdir -p $chrb_rubies_dir

    if [ ! -d "$HOME/.rubies" ] || [ ! -L "$HOME/.rubies" ]; then
        ln -s $chrb_rubies_dir $HOME/.rubies
    fi

    typeset chrb_tmp_dir=$chrb_base_dir/tmp
    typeset chrb_cache_dir=$chrb_base_dir/cache

    typeset chruby_source_dir=$chrb_install_dir/src/chruby/
    typeset ruby_build_source_dir=$chrb_install_dir/src/ruby-build

    source $chrb_install_dir/share/chruby/chruby.sh

    case "$1" in
        -h|--help)
cat <<EOH
chrb = (chruby + ruby-build) / mksh
An mksh wrapper function for chruby and ruby-build

Usage: chrb [OPTIONS] [RUBY]

Options:
  -h | --help
    Show this message.
  -v | --version
    Show chruby and ruby-build versions.
  -e | --environment
    Show the values of some environment variables.

  -d | --definitions
    Show ruby definitions available.

  -i | --install-definition RUBY-DEFINITION
    Install RUBY-DEFINITION.
  -r | --remove-definition RUBY-DEFINITION
    Remove installed RUBY-DEFINITION

  -u | --update
    Update chruby and ruby-build (with its ruby definitions) sources
    from github.
  -c | --changelog [NUMBER]
    Show NUMBER of last commits in chruby and ruby-build local
    repository. By default 10 last commits.

Notes:
  If RUBY is not indicated then a '.ruby-version' file will be
  searched inside the current working directory and based on its
  content a ruby definition will be selected. If for some reason
  this fail then a list of installed ruby definitions will be
  printed.
EOH
            ;;
        -v|--version)
            echo $(chruby --version) "&&" $(ruby-build 2>&1 | head -1 )
            ;;
        -e|--environment)
            cat <<EOE
RUBY_VERSION=$RUBY_VERSION
RUBY_ROOT=$RUBY_ROOT
RUBY_ENGINE=$RUBY_ENGINE
RUBYOPT=$RUBYOPT

$(gem env)
EOE
            ;;
        -d|--definitions)
            # Installed ruby will be prefixed with "[*]", no installed ruby with "[ ]"
            # previews and release-candidates will be filtered
            typeset installed_rubies="$(ls $chrb_rubies_dir | sed 's:$:\$:' | xargs | sed 's: :\\|:g')"
            if [ -n "$installed_rubies" ]; then
                ruby-build --definitions | grep -v 'preview\|-rc' | \
                    sed "s:\($installed_rubies\):[*] \1:" | \
                    sed '/\[/!s/^/[ ] /g' | COLUMNS=100 column
            else
                ruby-build --definitions | grep -v 'preview\|-rc' | \
                    sed 's/^/[ ] /' | COLUMNS=100 column
            fi
            ;;
        -i|--install-definition)
            if [ -z "$2" ]; then
                echo "chrb: Error, you must indicate wich ruby definition to install."
                return 1
            fi

            if [ ! -f "$chrb_install_dir/share/ruby-build/$2" ]; then
                echo "chrb: Error, '$2' is not available as a ruby definition."
                return 1
            fi

            if [ -d "$chrb_tmp_dir" ]; then
                export TMPDIR=$chrb_tmp_dir
            fi

            if [ -d "$chrb_cache_dir" ]; then
                export RUBY_BUILD_CACHE_PATH=$chrb_cache_dir
            fi

            # Number of (online) CPUs
            typeset cpus=$(expr $(lscpu -b | egrep '^CPU\(s\):' | sed 's/^.* //') + 1)
            export MAKE_OPTS="-j $cpus"

            echo "chrb: ruby-build -v $2 $chrb_rubies_dir/$2"
            sleep 3
            ruby-build -v $2 "$chrb_rubies_dir/$2"
            return $?
            ;;
        -r|--remove-definition)
                if [ -z "$2" ]; then
                    echo "chrb: Error, you must indicate wich ruby definition to delete."
                    return 1
                fi
                if [ -d "$chrb_rubies_dir/$2" ]; then
                    echo "chrb: rm -rf $chrb_rubies_dir/$2"
                    rm -rf "$chrb_rubies_dir/$2" && return 0
                fi
                return 1
            ;;
        -u|--update)
            (
                cd $ruby_build_source_dir || exit 1
                echo "chrb: Updating $(pwd)"
                git checkout master 1>/dev/null
                git reset --hard HEAD 1>/dev/null
                git clean -f -d 1>/dev/null
                git pull origin master 1>/dev/null || return 1

                rm -rf $chrb_install_dir/local/share/ruby-build/*
                echo "chrb: PREFIX='$chrb_install_dir' ./install.sh"
                PREFIX=$chrb_install_dir ./install.sh 1>/dev/null || return 1

                # Remove rbenv integration
                rm -rf $chrb_install_dir/bin/rbenv*
            )
            (
                cd $chruby_source_dir || exit 1
                echo
                echo "chrb: Updating $(pwd)"
                git checkout master 1>/dev/null
                git reset --hard HEAD 1>/dev/null
                git clean -f -d 1>/dev/null
                git pull origin master 1>/dev/null || return 1

                # mksh support
                git checkout mksh 1>/dev/null || return 1
                git pull origin mksh 1>/dev/null || return 1

                rm -rf $chrb_install_dir/local/share/doc/chruby*
                echo "chrb: PREFIX='$chrb_install_dir' make install"
                PREFIX=$chrb_install_dir make install 1>/dev/null || return 1
            )
            ;;
        -c|--changelog)
            typeset number_of_commits=10
            if [ "$2" -gt 0 ]; then
                number_of_commits=$2
            fi
            (
                cd $ruby_build_source_dir || exit 1
                echo "chrb: ruby-build last $number_of_commits commits:"
                git log --graph --oneline -$number_of_commits --parents | sed 's/^/  /'
            )
            echo
            (
                cd $chruby_source_dir || exit 1
                echo "chrb: chruby last $number_of_commits commits:"
                git log --graph --oneline -$number_of_commits --parents | sed 's/^/  /'
            )
            ;;
        *)
            typeset installed_rubies="$(ls $chrb_rubies_dir 2>/dev/null | \
                sed 's:$:\$:' | xargs | sed 's: :\\|:g')"
            if [ -z "$installed_rubies" ]; then
                echo "chrb: Error, there is not any ruby definition installed"
                echo "      at $chrb_rubies_dir"
                return 1
            fi
            if [ $# -eq 0 ]; then
                # If there is a .ruby-version file in the current working directory
                # check if there is a ruby definition installed with *exactly* the same name.
                # This will disable the "fuzzy matching of rubies by name" feature
                # in chruby.
                typeset ruby_version_file="$(pwd)/.ruby-version"
                typeset selected_ruby=""
                if [ -f "$ruby_version_file" ]; then
                    echo "chrb: Detected $ruby_version_file"
                    # To get the first line, first word.
                    typeset ruby_version=$(head -1 "$ruby_version_file" | cut -d ' ' -f 1)
                    if [ -z "$ruby_version" ]; then
                        echo "chrb: Error, '$ruby_version_file' seems to be empty."
                        return 1
                    fi
                    for ruby in $(ls $chrb_rubies_dir); do
                        if [ "$ruby_version" == "$ruby" ]; then
                            selected_ruby="$ruby";
                            chrb $selected_ruby || return 1

                            # These are the only interesting lines from chgems
                            eval `ruby - <<EOF
require 'rubygems'
puts "ruby_engine=#{defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'}"
puts "ruby_version=#{RUBY_VERSION}"
puts "gem_path=\"#{Gem.path.join(':')}\""
EOF`
                            gem_dir="$PWD/.gem/$ruby_engine/$ruby_version"
                            export GEM_HOME="$gem_dir"
                            export GEM_PATH="$gem_dir:$gem_path"

                            if [[ :$PATH: != *:$gem_dir/bin:* ]];then
                                export PATH="$gem_dir/bin:$PATH"
                            fi
                            return 0
                        fi
                    done
                    echo "chrb: Error ruby definition '$ruby_version' is not installed."
                    return 1
                fi
                # In other case let just have the default behaviour of chruby
                # wich is to show a list of *installed rubies*.
                chruby
                return $?
            fi
            # The only way to have the "fuzzy matching of rubies by name" feature in chruby is
            # through its parameters.
            echo "chrb: chruby $@"
            chruby $@ || return 1
            # A workaround, so 'gem' respects the '--no-user-install' at $HOME/.gemrc
            unset GEM_HOME
    esac

    # Clear environment
    unset -f $(typeset -f | grep -E '^chruby.*\(' | sed 's/(.*//')
    unset TMPDIR
    unset RUBY_BUILD_CACHE_PATH
    unset MAKE_OPTS
    PATH="$(echo $PATH | sed 's:'$chrb_install_dir/bin'\:::gi')"
}

# EOF

Y todo empezó con un script de mksh mucho más pequeño, https://gist.github.com/nihilismus/5698450, ;)