NSTaskで対話型コマンドを呼出す

ditzをCocoaから呼出す方法を調べていた。 ditzはユーザーと対話しながら実行するサブコマンドが多い。

そのためNSTaskで実装するには、ユーザーからの入力を偽装するNSPipeをNSTaskに接続し、適切なタイミングで文字列を流し込む必要がある。

その正攻法では面倒だし、コードが判りにくいと思っていたら面白いUnixコマンドを見つけた。

“expect”と呼ばれるunixコマンドです。このexpectは対話型のUnixコマンドを操作する為のunixコマンドと言うべき物でした。

詳細は以下のURLを参照してください。

Expect 入門 :
http://nsa.kpu-m.ac.jp/gijutu/expect/doc-expect.php

ditzをexceptを使って操作すれば、NSTaskへ投げっぱなしで問題なく実行出来そうだ。

例えば、以下のようなditzでissueを追加するラッパーを作った。

コマンド名 addIssue.sh
引数1 タイトル
引数2 詳細
引数3 bugか機能かタスクか
引数4 作成者名
引数5 コメント

呼出し方はこう

$ ./addIssue.sh すごいバグ 詳しく説明 b mymail@address 色々とコメント

ソースコードはこう

#!/bin/sh

TITLE=$1
DESCRIPTION=$2
BFT=$3
CREATOR=$4
COMMENT=$5

expect -c "
set timeout 5
spawn ditz add

expect \"Title:\"
send $TITLE
send \"\n\"

expect \"Description (\*):\"
send $DESCRIPTION
send \"\n\"
send \".\"
send \"\n\"


expect \"Is this a (b)ugfix, a (f)eature, or a (t)ask? \"
send $BFT
send \"\n\"


expect \"Issue creator (enter for \*):\"
send $CREATOR
send \"\n\"


expect \"Comments (\*):\"
send $COMMENT
send \"\n\"
send \".\"
send \"\n\"

interact

"

こんなコマンドをbundleに持たせて、NSTaskで呼出せばCocoaでややこしいプログラムを組まなくて良さそうです。

ついでに、issueの追加ではなくてtaskの追加専用のコマンドにしてみたり、エラーチェックを追加してみた。。

#!/bin/sh

####################
# 事前条件チェック
####################

# 引数の数をチェック
if [ $# -ne 4 ]
then
    echo "指定された引数は$#個です。" 1>&2
    echo "実行するには4個の引数が必要です。" 1>&2
    exit 1
fi

# ditzが実行パス中に有るかチェック
which ditz  >/dev/null 2>&1
if [ $? -ne 0 ]
then
    echo "ditzがインストールされていません。" 1>&2
    exit 1
fi

# ditzのバージョンをチェック
VERSION=`ditz --version | cut -d ' ' -f 2`
if [ $VERSION != "0.5" ]
then
    echo "インストールされているditzのバージョンは{$VERSION}です。" 1>&2
    echo "対応しているditzのバージョンは0.5です。" 1>&2
    exit 1
fi


# 引数を判り易い変数名にしておく
TITLE=$1
DESCRIPTION=$2
CREATOR=$3
COMMENT=$4

expect -c "
    set timeout 5
    spawn ditz add

    expect {
        default {exit 2}
        \"Title:\" {send $TITLE; send \"\n\"}
    }

    expect {
        default {exit 3}
        \"Description (\*):\" {send $DESCRIPTION; send \"\n.\n\"}
    }

    expect {
        default {exit 4}
        \"Is this a (b)ugfix, a (f)eature, or a (t)ask? \" {send \"t\n\"}
    }

    expect {
        default {exit 5}
        \"Issue creator (enter for \*):\" {send $CREATOR; send \"\n\"}
    }

    expect {
        default {exit 6}
        \"Comments (\*):\" {send $COMMENT; send \"\n.\n\"}
    }

    expect eof
"

case "$?" in
    0) exit 0 ;;
    2) echo "Titleの入力がエラーです。"         1>&2 ; exit 1 ;;
    3) echo "Descriptionの入力がエラーです。"   1>&2 ; exit 1 ;;
    4) echo "Issue typeの入力がエラーです。"    1>&2 ; exit 1 ;;
    5) echo "Issue creatorの入力がエラーです。" 1>&2 ; exit 1 ;;
    6) echo "Commentsの入力がエラーです。"      1>&2 ; exit 1 ;;
    *) echo "不明なエラーです。"                1>&2 ; exit 1 ;;
esac

exit 0

DitzのGUIフロントエンドを作るにあたって、後調べなければならない事はファイルのアップデートのタイミングを知る為の”FSEvent”を調査する必要がある。