GW暇だったので、Swift製CLIを作ってた。
現状あるのは open
と list
というコマンドだけだけど、とりあえず実用を始めることができるレベルにはなったかなと思ったので、公開した。
動機
構想自体は3ヶ月くらい前からあったが、SwiftPM Utility周りの理解がおぼつかなくて、実際にロジックを組み始めるまでの時間がかかってしまった。
最近、working directory構成を
- Documents - workspace - github.com - Swift - others - gitlab.com - Swift - others
みたいな感じにしてみた。
(golangは~/go/src/github.com/yutailang0119/
にあるので、ちょっと歪ではあるんだけど)
これはこれで事故が起こりにくくてよいなと思う反面、「あのファイルどこに置いたっけ?」となったり、リポジトリをforkしつつ、オリジナルのリポジトリも手元に置いていた時に、混乱することが多々あった。
たぶん各々効率的なやり方があるとは思うんだけど、我々iOSアプリケーションエンジニアはpcを開いている間の90%はXcodeと戯れることとなると思うので、Xcodeに特化したものを作ろうと思った。
ということで、
- .xcodeproj
- .xcworkspace
- .playground
といったXcodeで扱うであろうファイルを簡単に開いたり、リスト表示したりするツールを作った。
また、xcopen という名のツールはいくつか存在する https://github.com/search?utf8=✓&q=xcopen&type= が、自分が想定しているユースケースではないこと、メンテされていないことを鑑みて、この名前のツールの覇権を奪いに行くつもりで付けた。
所感
前に xccache-sweeper というCLIも作ったが、これはgolangで作った。
この時はSwift PM Package.swiftでかなり疲弊して、Swiftで作るのを断念したので、今回はSwiftで作るぞ!とやった。
ツール自体のロジックは、普段使い慣れているSwiftなので、非常に書きやすかった。
一方で、普段iOSアプリでは扱うことがないDarwinモジュール使ってみたりと、初めてのことも多々あり、新鮮だった。
Swift CLIでThread止める方法調べてて、NSThread.sleepだと都合悪いなーと思ってたけど、Darwinモジュール使うってこともできるのか。pause()とか直接使うのがありなのか否か
— Yutaro Muta (@yutailang0119) 2018年5月3日
謝辞
今回のツールを作るにあたり、岸川さんがSwift PM Utility ArgumentParserについて解説してくれた。
ありがとうございました! 🙇♂️
SwiftPMのはParserにさらにBindの機構が入ってるから、初見だとよくわからないですね。 https://t.co/Iszz3Otnxk まずこれが基本形で、Parserにオプションの構造を定義して、起動時引数をparse()します。
— kishikawa katsumi (@k_katsumi) 2018年4月5日
引数の構造が合ってるとResultが返ります。必須パラメータ(OptionalでないPositional引数など)がないなど、構造と合ってない場合はcatchに入ります。Resultのgetに対して、addの戻り値を渡すと実際のオプションが取れます。
— kishikawa katsumi (@k_katsumi) 2018年4月5日
例えばさっきのコードはこのスクリーンショットのような引数をparse()できます。これをベースに色々変えてみると分かると思います。 pic.twitter.com/ekTrqpZbYE
— kishikawa katsumi (@k_katsumi) 2018年4月5日
で、さっきのにArgumentBinderの仕組みを使うと https://t.co/TNcJh6sZs1 こうなります。parser.add()の戻り値を使う代わりにbinder.bind()に渡します。
— kishikawa katsumi (@k_katsumi) 2018年4月5日
binder.bind()はparserの型に合ったクロージャを取るので(get()が返す型)、そこでオプションの値を適当なオブジェクトにバインドします。get()で取って別のオブジェクトに詰めるというのさらに型を利用して宣言的にやる感じ。
— kishikawa katsumi (@k_katsumi) 2018年4月5日
swift testやswift packageのようなサブコマンドを使うにはsubparserを使います。 https://t.co/yzjGTtJNWe と https://t.co/DgHWQfsllP を見るとわかります。
— kishikawa katsumi (@k_katsumi) 2018年4月5日