普段 Scala でプログラミングをするときにビルドツールとして sbt を使用していて不便に感じることのひとつが
build.sbt
のあるディレクトリ(=プロジェクトのルートディレクトリ)で sbt を起動しないといけない こと。
プロジェクト配下のサブディレクトリに移動して作業していたりすると、
いちいちルートディレクトリに移動してから sbt を起動しないといけなくてめんどくさい。
Python のコマンドラインツール Fabric なんかだと、カレントディレクトリから親ディレクトリに向かって
fabfile.py
を探してくれて便利なので、同じようなことを sbt でもできるようにしたい。
sbt 自体にはそのようなオプションはないようなので、ちょっとしたシェルスクリプトを書いて実現しました。
- あるファイルを、カレントディレクトリから親ディレクトリに向かって再帰的に探すシェルスクリプトを作成。
- そのシェルスクリプトを使って
build.sbt
を探し、見つかったディレクトリで sbt を起動するシェル関数を定義。 - 定義したシェル関数で sbt を起動。
親ディレクトリからファイルを探すスクリプトを作成
まずは、カレントディレクトリから親ディレクトリに向かって再帰的にファイルを探すシェルスクリプトを作成し、
パスが通っている場所(/usr/local/bin
とか)にお好みの名前で置いて実行権限を付けておきます。
ここでは /usr/local/bin/pfind
(Parent FIND) と言う名前で、↓な感じでシェルスクリプトを作ります。
特に特定のライブラリなどは使ってないので、Bashさえ動く環境であれば使えるはずです。
ちなみに、このシェルスクリプトは sbt 専用でもないので汎用的に使えます。
シェルプログラミングが得意な方ならもっとシンプルに書けると思いますが...
と言うか親ディレクトリからファイルを探すコマンドってないのかな
#!/bin/bash
find_in_parents () {
slashes=${PWD//[^\/]/}
directory=$BASE_DIR
for (( n=${#slashes}; n>0; --n ))
do
test -e "$directory/$FILE" && echo "$directory" && return
directory="$directory../"
done
# Not found.
exit -1
}
show_usage() {
echo "Find file recursively in the parent directory."
echo ""
echo "Usage: "
echo " pfind -f FILE -b BASE_DIR -p"
echo " -f: Target file name."
echo " -b: Base directory for starting search. (OPTIONAL Default current directory)"
echo " -p: With file name.(OPTIONAL Default direcotry only)"
echo "Exampe:"
echo " pfind -f foobar.txt"
echo " pfind -f foobar.txt -b /foo/bar"
echo " pfind -f foobar.txt -b /foo/bar -p"
echo ""
exit -1
}
while getopts f:b:p OPT
do
case $OPT in
f) FILE=$OPTARG
;;
b) BASE_DIR=$OPTARG
;;
p) WITH_FILE=true
esac
done
[ "$FILE" == "" ] && show_usage
[ "$BASE_DIR" == "" ] && BASE_DIR=`pwd`/
[ "$WITH_FILE" == "" ] && WITH_FILE=false
FOUND_DIR=`find_in_parents`
RC=$?
if [ $RC == 0 ]; then
if $WITH_FILE ; then
echo `(cd $FOUND_DIR; pwd)`/$FILE
else
echo `(cd $FOUND_DIR; pwd)`
fi
else
echo "$FILE not found." >&2
exit $RC
fi
使い方はこんな感じになります。(/Users/xxxx/work/example/build.sbt
がある例)
$ pwd
/Users/xxxx/work/example/src/main/resources
$ pfind -f build.sbt
/Users/xxxx/work/example
$ pfind -f build.sbt -p
/Users/xxxx/work/example/build.sbt
build.sbtを探してsbtを起動するシェル関数を定義
↑で作成したシェルスクリプトを使って build.sbt
を探し、見つかったディレクトリで sbt を起動するシェル関数を定義します。
これまた関数名はお好みで。ここでは ssbt
(特に意味なし) って名前にしています。
エイリアスでも良いですが、エイリアスだと sbt にパラメタを渡すことができないのでシェル関数にしておくのが吉です。
function ssbt() {
BUILDSBT_IN_DIR=`pfind -f build.sbt`
RC=$?
if [ $RC == 0 ]; then
(cd $BUILDSBT_IN_DIR; echo "build.sbt found in `pwd`"; sbt $@)
else
echo "build.sbt not found."
fi
}
-
cd
してからsbt
起動は、( )
で囲んで書いておけばbuild.sbt
の場所にカレントディレクトリが移動しないので使いやすいと思います。 -
$@
でパラメタを sbt に渡します。
zsh
な人はこんな感じ。(ifの構文が違う)
function ssbt() {
BUILDSBT_IN_DIR=`pfind -f build.sbt`
RC=$?
if [[ $RC -eq 0 ]]; then
(cd $BUILDSBT_IN_DIR; echo "build.sbt found in `pwd`"; sbt $@)
else
echo "build.sbt not found."
fi
}
sbtを起動
これで build.sbt
を置いてあるディレクトリの下からであれば、どこからでも sbt を起動できます。
$ pwd
/Users/xxxx/work/example/src/main/resources
$ ssbt
build.sbt found in /Users/xxxx/work/example
[info] Loading global plugins from /Users/xxxx/.sbt/0.13/plugins
[info] Loading project definition from /Users/xxxx/work/example/project
>
# パラメタを指定することもできます
$ ssbt clean compile
以上です。