たごもりすメモ

コードとかその他の話とか。

本番環境でのperl/ruby/nodeのセットアップ

本番環境にperlとかrubyとかnodeを入れるんだけど、もちろん system perl じゃやってられないので指定したバージョンのものを一般ユーザの管理下に突っ込みたい。
で、そういうのをこれまで perlbrew とか rvm とか rbenv とか nvm とか nodebrew とかでやってたんだけど、さすがに色々疑問が湧いてきた。バッチで単発実行するために eval "$(rbenv init -)" とかさすがにおかしくね? みたいな。

ということで tokuhirom method 的にインストール用の簡単コマンドを使って実行、あとはパスを通せばいいじゃん、ということにしようかと思う。

参考: サーバーのセットアップは perlbrew とかじゃなくてよくね? という時のライフハック - blog.64p.org

これ、今朝までは Perl::Build をどうにかしてCPANからとってきてインストールしないといけなかったのがネックでどうしようかと思ってたんだけど、なんかお願いしたら perl-build スクリプト単体で実行可能なようにパッケージングしてくれたので超簡単になった。tokuhirom++

これだけでもよかったんだけど cpanm とか carton は確実に使う + これがあればランタイムグローバルにモジュールを入れなくてもよくなるから最初から入っててほしいよねってことで、このあたりのセットアップもついでにやってくれるようなスクリプトを適当に書いた。

(3/28追記: githubに上げた https://github.com/tagomoris/xbuild )

こんな感じで使う。

xbuild/perl-install 5.16.3 ~/local/perl-5.16
xbuild/ruby-install 2.0.0-p0 ~/local/ruby-2.0.0
xbuild/node-install v0.10.1 ~/local/node-v0.10

export PATH=$HOME/local/perl-5.16/bin:$PATH

cd myproject1
cpanm -Lextlib -n --installdeps . # or carton install ...
perl -Iextlib/lib/perl5 -Ilib my_script.pl # carton exec ...

export PATH=$HOME/local/ruby-2.0.0/bin:$PATH

cd myproject2
bundle install --path vendor
bundel exec ruby my_script.rb

なお以下のスクリプトはすべてスクリプト自身があるディレクトリに bin/ や var/ を掘って使うので xbuild/ 以下に隔離して置いておくのがよい。コードの最新版については github を参照のこと。

#!/bin/bash

TARGET_VERSION=$1
LOCATION=$2

if [ "x"$TARGET_VERSION = "x-h" -o "x"$TARGET_VERSION = "x--help" -o "x"$LOCATION = "x" ]; then
    echo "[usage] perl-install VERSION LOCATION"
    echo "  ex: perl-install 5.16.3 ~/local/perl-5.16"
    exit 0
fi

cd $(dirname $0)

mkdir -p ./bin
curl -s https://raw.github.com/tokuhirom/Perl-Build/master/perl-build > ./bin/perl-build
curl -s -L http://cpanmin.us/ > ./bin/fatpack_cpanm

perl ./bin/perl-build $TARGET_VERSION $LOCATION > /tmp/perl-install.log 2>&1
RETVAL=$?
if [ $RETVAL != 0 ]; then
    echo "perl-build failed. see log: /tmp/perl-install.log"
    exit 1
fi

$LOCATION/bin/perl ./bin/fatpack_cpanm --notest App::cpanminus Carton App::pmuninstall > /tmp/perl-install-cpanm.log 2>&1
RETVAL=$?
if [ $RETVAL != 0 ]; then
    echo "failed to install cpanm/carton. see log: /tmp/perl-install-cpanm.log"
    exit 2
fi

echo "perl $TARGET_VERSION (and cpanm/carton) successfully installed on $LOCATION"
echo "To use this perl, do 'export PATH=$LOCATION/bin:\$PATH'."

rubyについてもrbenvとかいらねーよ、ruby-buildでいいんだけどruby-buildのインストールをいちいちやるのがめんどくさいよ、ということで完全に同じインターフェイスでえいやと書いた。

#!/bin/bash

TARGET_VERSION=$1
LOCATION=$2

if [ "x"$TARGET_VERSION = "x-h" -o "x"$TARGET_VERSION = "x--help" -o "x"$LOCATION = "x" ]; then
    echo "[usage] ruby-install VERSION LOCATION"
    echo "  ex: ruby-install 1.9.3-p392 ~/local/ruby-1.9.3"
    exit 0
fi

cd $(dirname $0)
XBUILD_PATH=$(pwd)

if [ ! -d ./var/ruby-build ]; then
    (
        set -e
        mkdir -p var
        cd var
        git clone -q git://github.com/sstephenson/ruby-build.git ruby-build-repo
        cd ruby-build-repo
        PREFIX=$XBUILD_PATH/var/ruby-build ./install.sh >/dev/null 2>&1
    ) || (echo "failed to download ruby-build" && exit 1)
fi

./var/ruby-build/bin/ruby-build $TARGET_VERSION $LOCATION > /tmp/ruby-install.log 2>&1
RETVAL=$?
if [ $RETVAL != 0 ]; then
    echo "ruby-build failed. see log: /tmp/ruby-install.log"
    exit 1
fi

$LOCATION/bin/gem install --no-rdoc --no-ri bundler pry > /tmp/ruby-install-bundler.log 2>&1
RETVAL=$?
if [ $RETVAL != 0 ]; then
    echo "gem install failed. see log /tmp/ruby-install-bundler.log"
    exit 2
fi

echo "ruby $TARGET_VERSION successfully installed on $LOCATION"
echo "To use this ruby, do 'export PATH=$LOCATION/bin:\$PATH'."

node.jsの場合は各OSおよびCPUアーキテクチャごとにバイナリが細かく用意されててそいつを落としてきて展開するだけでいいんだけど、まあついでなのでこれも。なおこういう形にしておけば v0.10.0 -> v0.10.1 へのアップデートを同じ ~/local/node-v0.10/ というパス上で行う、というような用途のときにインストールコマンドを叩き直すだけで実行できる、というメリットもある。(これはperl/rubyも同じ)

#!/bin/bash

TARGET_VERSION=$1
LOCATION=$2
ARCH=$3

if [ "x"$TARGET_VERSION = "x-h" -o "x"$TARGET_VERSION = "x--help" -o "x"$LOCATION = "x" ]; then
    echo "[usage] node-install VERSION LOCATION [arch]"
    echo "  ex: node-install v0.10.1 ~/local/node-v0.10"
    echo "  ex: node-install v0.10.1 ~/local/node-v0.10 darwin-x86"
    echo "  default arch is 'linux-x64'"
    exit 0
fi

if [ "x"$ARCH = "x" ]; then
    ARCH="linux-x64"
fi

cd $(dirname $0)

ARCHIVE_FILENAME="node-"$TARGET_VERSION"-"$ARCH".tar.gz"
ARCHIVE_DIRNAME="node-"$TARGET_VERSION"-"$ARCH

set -e
mkdir -p var/node-archive
cd var/node-archive
curl -s -O http://nodejs.org/dist/$TARGET_VERSION/$ARCHIVE_FILENAME

cd ..
tar xzf node-archive/$ARCHIVE_FILENAME

if [ -d $LOCATION ]; then
    [[ -d $LOCATION.replaced ]] && rm -rf $LOCATION.replaced
    mv $LOCATION $LOCATION.replaced
else
    mkdir -p $LOCATION && rmdir $LOCATION
fi
mv $ARCHIVE_DIRNAME $LOCATION

echo "node $TARGET_VERSION successfully installed on $LOCATION"
echo "To use this node, do 'export PATH=$LOCATION/bin:\$PATH'."

もうこのくらいシンプルでいいじゃんね。使うときはPATHを通す。以上。