All Articles

SwiftLint の Run Script は結局どう書くのが適切なのか

SwiftLint をビルド時に Run Script で実行する設定は、様々な記事で紹介されています。

しかし、微妙に間違っていたり、シェルスクリプトをよく書く自分からすると、もっとこう書いた方がいいと思ったりする点があったりします。

この記事では、あまりシェルスクリプトに慣れていない iOS エンジニアの方に向けて、SwiftLint の Run Script を通してシェルスクリプトのコツを解説します。

結論

最初に SwiftLint の Run Script の書き方の結論を載せます。

SwiftLint を CocoaPods でインストールしている場合

SWIFT_LINT="${PODS_ROOT}/SwiftLint/swiftlint"

if which "${SWIFT_LINT}" >/dev/null; then
  "${SWIFT_LINT}" autocorrect --format
  "${SWIFT_LINT}"
else
  echo "warning: SwiftLint not installed."
fi

SwiftLint を Homebrew などで Mac にインストールしている場合 (非推奨)

SWIFT_LINT="swiftlint"

if which "${SWIFT_LINT}" >/dev/null; then
  "${SWIFT_LINT}" autocorrect --format
  "${SWIFT_LINT}"
else
  echo "warning: SwiftLint not installed."
fi

解説

シェルスクリプトはなかなか癖のある文法をしているので、このコードの意味・意図を解説していきます。

SWIFT_LINT="${PODS_ROOT}/SwiftLint/swiftlint"

if which "${SWIFT_LINT}" >/dev/null; then
  "${SWIFT_LINT}" autocorrect --format
  "${SWIFT_LINT}"
else
  echo "warning: SwiftLint not installed."
fi

SwiftLint の有無による分岐

if which "${SWIFT_LINT}" >/dev/null; then

シェルスクリプトに慣れていない方にとって、一番分かりにくいのはこの部分だと思います。 雰囲気的に SwiftLint があるかどうかで分岐していることは分かると思いますが、ここをちゃんと解説してみます。

まず、この部分は ifwhich "${SWIFT_LINT}" >/dev/null;then に分けて読む必要があります。 単純な話ですが、 which "${SWIFT_LINT}" >/dev/null の部分が if で条件分岐するための判定です。

which "${SWIFT_LINT}" >/dev/null は何をしているかと言うと、which "${SWIFT_LINT}" コマンドを実行し、その際に画面 (標準出力) に表示される内容を捨てています。 which "${SWIFT_LINT}" コマンドは、SwiftLint の有無を調べるコマンドですが、なぜその結果を捨てているのでしょうか ?

その理由は、シェルスクリプトの if が表示内容ではなく、終了コードを見ていることにあります。

which コマンドは指定したコマンドが見つかったか場合は終了コード 0 を、見つからなかった場合は終了コード 1 を返します。 if はその値を見て分岐しているのです。

SWIFT_LINT 変数の定義

ざっと調べたところ全く見かけなかったのですが、${PODS_ROOT}/SwiftLint/swiftlint という部分は上記のように変数に SWIFT_LINT のような変数にまとめた方が良いです。 理由はもちろん、使用する swiftlint コマンドのパスが変わった際に、1 箇所の修正で済むようにするためです。

これはシェルスクリプトではよく見かけるテクニックです。

"" の挙動

SWIFT_LINT という変数を使用する際、それを "" で括っています。 "" で括った部分は、シェルスクリプトでは 1 つの文字列として扱われます。

なので、もし "${SWIFT_LINT}" autocorrect --format の部分を "${SWIFT_LINT} autocorrect --format" のように書いてしまうと、${SWIFT_LINT} autocorrect --format という空白を含んだコマンドを実行しようとしてしまい、正しい結果が得られません。 "" でどこまで括るべきかは注意しましょう。

ちなみに ${} で変数を呼び出す箇所を "" で括ることは、Google の Shell Style Guide で推奨されています。

SwiftLint を Homebrew でインストールすべきでない理由

最後に、SwiftLint を Homebrew でインストールするケースを非推奨としている理由ですが、これは SwiftLint のバージョンが開発者間で統一されなくなってしまうためです。

インフラ系の仕事をする機会が多い自分にとって環境間のバージョン違いをなくすことは自然なことなのですが、こちらも実施していない記事が多いです。

このことについては「iOSアプリを開発する人はもっとRubyとgemの管理に慎重になって、かつ有効に使って欲しいという気持ちの記事を書いた。」というブログ記事とそのリンク先で、なぜそうすべきか、具体的にどう設定すればいいのか、が解説されています。

おわりに

先日参加した Swift の勉強会で色々初心者的な質問をさせていただいたので、この記事の内容のように、自分が比較的得意な分野 (シェルスクリプト) で Swift のコミュニティに貢献できればと思います。

シェルスクリプトのすすめ

シェルスクリプトは非常に便利ですし、学ぶ価値は非常に高いです。 興味を持った方が勉強する最初の一冊にはこちらの本がオススメです。