Homebrew の複数運用支援ツール「Maltybrew」を公開しました
既に何回か書いていますが、私はオープンソースなソフトウェアを開発環境 (Mac) にインストールするとき、 Homebrew などのパッケージ管理ツールを使わずに自前でビルドしていました(MySQL とか、 nginx とか、 Tornado とか)。フリーで仕事をしている関係上、基本システムはなるべく素の状態のままにしておきたいからです。
でも、実は Homebrew ってひとつのマシンに複数インストールしたりもできるんですよね。それなら複数の Homebrew を切り替えて使えば万事解決なんじゃないか・・・なんて以前から考えていたことをエイヤッとやってみたのが、本日ご紹介する「Maltybrew」です。なんという安直なネーミング。
rvm (rbenv) とか virtualenv とか nvm とか使うまでもなく、 Homebrew の環境ごと一気に切り替え。そんなドライなお付き合いをしたい方にお勧めです。
Homebrew とは
おそらく皆さんご存知かと思いますが、 Homebrew についても一応説明しておきます。 Homebrew は、 OS X への各種オープンソースソフトウェアのインストール・管理を支援するパッケージマネージャです。 Linux でいう RPM や APT の Mac 版といったところですね。 Homebrew さえ入れておけば、例えば以下のコマンドひとつで MySQL をインストールできます。
brew install mysql
Homebrew 自体のインストール方法や使い方は今回の趣旨ではないので省きますが、検索すれば多くの解説が見つかります。軽く探した中では、以下のページがとてもよくまとまっていました。
Mac デ Homebrew ノススメ | Kitchen Garden Blog
他のパッケージマネージャにない Homebrew の特徴のひとつとして、インストール場所が固定されていないということがあります。任意のディレクトリに Homebrew 本体をインストールすれば、後にインストールするパッケージも含めて、全てのファイルがそこに収まります。このため、複数のディレクトリに別々の Homebrew 環境をインストールすることも可能なのです。
しかし、そうして複数の Homebrew 環境を用意しても、実行パスやライブラリパスなどを適切に設定しないと実際に使うことはできません。そうした設定を自動化するのが、 Maltybrew の目的です。
Maltybrew のインストール方法
Maltybrew は Github で公開しています。といっても中身はシェルスクリプトがひとつだけです。
#! /bin/bash
# This is an utility shell-script to manage multiple homebrew installations.
# You can install new homebrew environment named "dev" by:
#
# maltybrew new dev
#
# Then switch to this environment:
#
# maltybrew switch dev
#
# Now you are in "dev" environment. You can install any formura without
# affecting your default system.
#
# brew install ruby
#
# To back to the original environment, simply exit the current shell by
# exit command or Ctrl-D.
#
# note:
# maltybrew modifies only PATH and DYLD_LIBRARY_PATH by default. you can add
# additional initialization/cleanup process in .maltybrew/<env-name>/maltyrc.
if [ -z $MALTYBREW_HOME ]; then
MALTYBREW_HOME=$HOME/.maltybrew
fi
function maltybrew_new {
local ROOT=$MALTYBREW_HOME/$1
if [ -z $1 ]; then
return 1
elif [ -e $ROOT ]; then
return 2
fi
mkdir -p $MALTYBREW_HOME && mkdir $ROOT
if [ $? -ne 0 ]; then
return 3
fi
curl -L https://github.com/mxcl/homebrew/tarball/master | tar xz --strip 1 -C $ROOT
if [ $? -ne 0 ]; then
return 4
fi
$ROOT/bin/brew update
cat <<EOF > $ROOT/maltyrc
# -*- mode:shell-script -*-
# \$1: enter or exit
# \$2: ~/.maltybrew/<env-name>
if [ \${1%%-*} == enter ]; then
:
# Put additional initializations here.
#
#export PATH=\$2/share/npm/bin:\$2/share/python:\$2/Cellar/ruby/1.9.3-p362/bin:\$PATH
#
#export ORIGINAL_LANG=\$LANG
#export LANG=C
elif [ \${1%%-*} == exit ]; then
:
# Recover the original environment.
#
## PATH and DYLD_LIBRARY_PATH are recovered implicitly.
#
#if [ \$ORIGINAL_LANG ]; then
# export LANG=\$ORIGINAL_LANG
#else
# unset LANG
#fi
#unset ORIGINAL_LANG
fi
EOF
return 0
}
function maltybrew_init {
local ROOT=$MALTYBREW_HOME/$1
if [ -z $1 ]; then
return 1
elif [ -d $ROOT ]; then
export MALTYBREW_ORIGINAL_PATH=$PATH
export MALTYBREW_ORIGINAL_LIBRARY_PATH=$DYLD_LIBRARY_PATH
export MALTYBREW_NAME=$1
export DYLD_LIBRARY_PATH=$ROOT/lib:$DYLD_LIBRARY_PATH
export PATH=$ROOT/bin:$PATH
if [ -f $ROOT/maltyrc ]; then
. $ROOT/maltyrc enter $ROOT
fi
else
return 5
fi
return 0
}
function maltybrew_cleanup {
local ROOT=$MALTYBREW_HOME/$MALTYBREW_NAME
if [ $MALTYBREW_NAME -a -d $ROOT ]; then
if [ -f $ROOT/maltyrc ]; then
. $ROOT/maltyrc exit $ROOT
fi
export PATH=$MALTYBREW_ORIGINAL_PATH
if [ $MALTYBREW_ORIGINAL_LIBRARY_PATH ]; then
export DYLD_LIBRARY_PATH=$MALTYBREW_ORIGINAL_LIBRARY_PATH
else
unset DYLD_LIBRARY_PATH
fi
unset MALTYBREW_ORIGINAL_PATH
unset MALTYBREW_ORIGINAL_LIBRARY_PATH
unset MALTYBREW_NAME
else
return 6
fi
return 0
}
function maltybrew_list {
for name in $MALTYBREW_HOME/* ; do
if [ -d $name ]; then
echo ${name##*/}
fi
done
return 0
}
function maltybrew_error {
case $1 in
0 ) return 0;;
1 ) echo "Illegal envname." >&2 ;;
2 ) echo "$MALTYBREW_HOME/$2 is already exist." >&2 ;;
3 ) echo "mkdir $MALTYBREW_HOME/$2 is failed." >&2 ;;
4 ) echo "Failed to install homebrew into $MALTYBREW_HOME/$2." >&2 ;;
5 ) echo "$MALTYBREW_HOME/$2 is not exist nor a directory." >&2 ;;
6 ) echo "You are not drunk." >&2 ;;
* ) echo "Unknown error." >&2 ;;
esac
if [ -z $3 ]; then
exit $1
fi
}
function maltybrew_help {
cat <<EOF
Create new homebrew installation named "dev":
maltybrew new dev
Switch to "dev" environment:
maltybrew switch dev
List all homebrew installations:
maltybrew list
EOF
}
if [ -z $1 ]; then
maltybrew_help
elif [ $1 == n -o $1 == new ]; then
maltybrew_new $2
maltybrew_error $? $2
elif [ $1 == s -o $1 == switch ]; then
if [ $MALTYBREW_NAME ]; then
maltybrew_cleanup
fi
maltybrew_init $2
maltybrew_error $? $2
$SHELL -i
if [ $MALTYBREW_NAME ]; then
maltybrew_cleanup
fi
elif [ $1 == l -o $1 == list ]; then
maltybrew_list
maltybrew_error $? $2
elif [ $1 == switch_inplace ]; then
if [ $MALTYBREW_NAME ]; then
maltybrew_cleanup
fi
maltybrew_init $2
maltybrew_error $? $2 no
else
maltybrew_help
fi
このファイルをパスの通ったディレクトリに保存して chmod a+x すれば、インストールは終了です。例えば、 ~/bin に実行パスが通っているなら、以下のコマンドで OK です。
cd ~/bin
curl -o maltybrew https://raw.github.com/webos-goodies/Maltybrew/master/maltybrew.sh
chmod a+x maltybrew
ただし、 Homebrew の動作には Xcode のコマンドラインツールが必要なので、なければそれも入れておいてください(方法は前述のサイトで解説されています)。
使い方
使い方は単純で、 3 つのサブコマンドがあるだけです。
書式 | 機能 |
---|---|
maltybrew new <名前> | 新しい Homebrew のインストール |
maltybrew switch <名前> | 指定した Homebrew への切り替え |
maltybrew list | インストールされている Homebrew のリストアップ |
例えば、下のコマンドを実行すると「dev」という名前で新しい Homebrew をインストールします。以降、 Maltybrew でインストールした Homebrew を「Homebrew インスタンス」と呼びます。
maltybrew new dev
<名前> はなんでもかまいませんが、スクリプトの作りこみが甘いので空白や記号を入れるとまずいです。たぶん。英数字とアンダーバー、ハイフンのみが無難です。実際にインストールされるパスは ~/.maltybrew/<名前> になります。
Homebrew インスタンスのインストールが終了したら、 switch サブコマンドでその環境に切り替えることができます。
maltybrew switch dev
サブシェルが起動し、実行パスやライブラリパスなどが適切に設定されます。 brew コマンドも使えるようになるので、それを使ってパッケージのインストールや管理が可能です。
brew install mysql
# ... インストールのメッセージ ...
mysql --version
-> mysql Ver 14.14 Distrib 5.5.29, for osx10.8 (i386) using readline 5.1
パッケージは現在の Homebrew インスタンス内にインストールされるので、外部の環境や他の Homebrew インスタンスには影響しません。当然、サブシェルを抜ければ使えなくなります。
exit
mysql --version
-> -bash: mysql: command not found
基本、これだけです。 Homebrew インスタンスを削除したいときは、単純に rm -Rf ~/.maltybrew/<名前> してください。
maltyrc ファイル
Homebrew のパッケージの中には、追加の設定を必要とするものがあります。例えば Homebrew で Ruby をインストールした場合、 gem の bin ディレクトリを実行パスに含めなければなりません。こうした追加の設定を行うために、 ~/.maltybrew/<名前>/maltyrc というファイルを用意しています。初期の内容は概ね下のようになっているはずです(コメントは変更しています)。
if [ $1 == enter ]; then
# この Homebrew に切り替えたときに実行されるコード
:
else
# Homebrew 環境から出るときに実行されるコード
:
fi
見ての通り Bash のシェルスクリプトで、該当する Homebrew インスタンスに switch したとき、もしくはそこから抜けるときに実行されます。 $1 には、前者の場合なら "enter" が、 後者なら "exit" が設定されます。 $2 には ~/.maltybrew/<名前> のパスが入っています。したがって、以下のように変更することで、 gem の bin ディレクトリに実行パスを通すことができます。
if [ $1 == enter ]; then
# この Homebrew に切り替えたときに実行されるコード
export PATH=$2/Cellar/ruby/1.9.3-p362/bin:$PATH
else
# Homebrew 環境から出るときに実行されるコード
:
fi
PATH (と DYLD_LIBRARY_PATH)は maltybrew が暗黙的に復元するので else 以降にはなにも書いていません。しかし、他の環境変数や環境変数以外のなんらかの設定を変更した場合は、元の値を退避しておき、 else 以降の部分で復元してください。例えば、 Homebrew 環境内でのみ LANG=C を設定したい場合は以下のようにします。
if [ $1 == enter ]; then
# この Homebrew に切り替えたときに実行されるコード
export PATH=$2/Cellar/ruby/1.9.3-p362/bin:$PATH
export ORIGINAL_LANG=$LANG
export LANG=C
else
# Homebrew 環境から出るときに実行されるコード
if [ $ORIGINAL_LANG ]; then
export LANG=$ORIGINAL_LANG
else
unset LANG
end
unset ORIGINAL_LANG
fi
ちょっと面倒ですね。このあたりうまく自動化したかったのですが、良い方法が思いつきませんでした。アドバイス等募集中です。
その他
標準インストールの Homebrew との共存
私自身は標準インストール(/usr/local 以下)の Homebrew は入れていないのですが、あっても大きな問題はないはずです。 maltybrew switch した後はその環境にインストールしたものが優先され、なければ標準インストールのものが使われるはず。
とはいえ、パッケージによっては誤動作するかもしれないので、できればアンインストールして Maltybrew に一本化するほうが安全ではあります。
ログインシェルで特定の Homebrew インスタンスを使う
ログインしたときから(というか、ターミナルを起動したときから)特定の Homebrew インスタンスを使いたい、ということもあるでしょう。例えば「main」という名前のインスタンスを使う場合は、.bash_profile に以下の行を追加します。
. /path/to/maltybrew switch_inplace main
この場合、 maltybrew_cleanup というコマンドで素の環境に戻すことが可能です。
maltybrew_cleanup
これらの機能(switch_inplace と maltybrew_cleanup)は取り敢えずの実装なので、今後仕様を変えたりするかもしれません。その際はご容赦ください。
以上が Maltybrew の機能ですが、いかがでしょうか。常に複数環境が必要な場合は稀でしょうが、既存の環境を変えずに新しいパッケージを試してみたいということは多いのではないでしょうか。そんなときにご活用いただければと思います。
詳しくはこちらの記事をどうぞ!
この記事にコメントする