LCL Engineers' Blog

バス比較なび・格安移動・バスとりっぷを運営する LCLの開発者ブログ

xcprojectlintでXcodeの些細な問題を解決して心を整える

モバイルアプリエンジニアの山下です。 Xcodeで開発を進めていく中で、以下のような小さな問題がずっと気になっていました。

  • ファイルシステムとXcodeのディレクトリ構造で差異が発生する
  • ディレクトリやファイルがアルファベット順にソートされていない
  • 空のディレクトリが放置されてままになっている

そこで今回は、XcodeのLintツールである xcprojectlint を用いて問題箇所の検出をしてみました。

インストール

ライブラリ依存管理ツールはSwift Package Managerに対応しています。
Swift Package ManagerはCocoaPodsやCarthageと比べて実行するために複数の引数を用いたり少し面倒な部分があったりするので、それを隠したMakefileを用意してくれています。

$ git clone https://github.com/americanexpress/xcprojectlint.git
$ cd xcprojectlint
$ swift package update
$ make build # このコマンドは`$ swift build`しているだけでした
swift build
Compile clibc libc.c
Compile Swift Module 'SPMLibc' (1 sources)
Compile Swift Module 'POSIX' (11 sources)
Compile Swift Module 'Basic' (37 sources)
Compile Swift Module 'Utility' (19 sources)
Compile Swift Module 'xcprojectlint_package' (12 sources)
Compile Swift Module 'xcprojectlint' (1 sources)
Linking ./.build/x86_64-apple-macosx10.10/debug/xcprojectlint

出力されたPathにxcprojectlintが設置されているのでコマンドを叩きます。

$ ./.build/x86_64-apple-macosx10.10/debug/xcprojectlint --version
xcprojectlint version 0.0.3

無事に実行できればインストールは完了です。

使い方

以下のように実行することでLintを実行することができます。

$ ./.build/x86_64-apple-macosx10.10/debug/xcprojectlint --report error --validations all --project ../xxxx.xcproject

--report

warningerrorのどちらで出力するかを指定します。

--validations

チェックしたいvalidationsを指定します。
5つのルールと、全てを適用するためのallを含めた6つのバリデーションが用意されています。

  --validations    List of validations to perform:
                     build-settings-externalized:
                       Looks for project settings defined in the project file
                       
                       Build Settingsが個別の`*.xcconfig`で管理されているかをチェックします

                     disk-layout-matches-project:
                       Validates files on disk are arranged like the project
                       file
                       
                       ファイルシステム上のディレクトリ構造とXcode上のディレクトリ構造が一致しているかチェックします

                     empty-groups:
                       Reports groups that have no children
                       
                       空のグループ(ディレクトリ)が存在するかチェックします

                     files-exist-on-disk:
                       Look for files referenced by the project that are not
                       found on disk
                       
                       ファイル参照のリンクが切れていないかチェックします

                     items-in-alpha-order:
                       Ensure groups and files are sorted alphabetically
                       
                       グループ(ディレクトリ)や ファイルがアルファベット順に並んでいるかチェックします

                     all:
                       Runs all known validations

--project

xcprojectのPathを指定します。
今回はxcprojectlintを開発ディレクトリ直下に配置しているため、1階層分戻って指定しています。

--skip-folders

除外したいフォルダを指定します。

ビルド時に実行

折角なのでswiftlintやswiftformat同様にビルド時に実行し、Xcode上で警告やエラーを表示させたいと思います。
まず、Build Phesesを開いて新しくRun Scriptを追加します。

f:id:lcl-engineer:20180827150538p:plain

次に以下のスクリプトを入力します。

if which "xcprojectlint/.build/x86_64-apple-macosx10.10/debug/xcprojectlint" >/dev/null; then
  xcprojectlint/.build/x86_64-apple-macosx10.10/debug/xcprojectlint --report error --validations disk-layout-matches-project files-exist-on-disk empty-groups items-in-alpha-order --project xxxx.xcodeproj
else
  echo "warning: xcprojectlint not installed, download from https://github.com/americanexpress/xcprojectlint"
fi

f:id:lcl-engineer:20180827150547p:plain

設定は以上です。先程とは違い、Pathの指定はプロジェクトルートから設定していることに注意してください。

Lintの結果

build-settings-externalized以外のバリデーションを実行してみた結果、合計で74件引っかかりました。

f:id:lcl-engineer:20180827150602p:plain

内訳

  • disk-layout-matches-project: 7件
error: File “xxx.swift” () is misplaced on disk, or wrong kind of reference.
  • empty-groups: 0件
  • files-exist-on-disk: 0件
  • items-in-alpha-order: 67件
error: Xcode folder “Extensions” has out-of-order children.
Expected: ["Array+.swift", "Date+.swift", "DateFormatter+.swift", "Enum+.swift", "NSObject+.swift", "String+.swift"]
Actual:   ["String+.swift", "Array+.swift", "Enum+.swift", "NSObject+.swift", "Date+.swift", "DateFormatter+.swift"]

ソートに関してはEdit -> Sort -> By Nameから並び替えが可能です。フォルダとファイルを分けたい場合は、その後にBy Typeで再度ソートするとよいです。

f:id:lcl-engineer:20180827165220p:plain

各エラー内容は具体的にちゃんと出力されているため、その通りに直していけば健康的なプロジェクト環境を維持できそうです。

おわりに

ずっと気になっていたことを解決できたので、気持ちよく開発を進めることができそうです。
長期的な開発では些細なことでも塵積で混沌とした開発環境になってしまい兼ねないので、可能な限り機械的に検出し快適な開発環境を維持できるようにしたいと思っています。 とはいえ、このようなチェックはIDE側で補って欲しいところですね。

techblog.lclco.com