Twitterでふぁぼったものをひたすら試します

Goでxcode-selectするコマンドラインツールを作った【Go その2 Advent Calendar 2015 7日目】

誘導

この記事はGo その2 Advent Calendar 2015 - Qiitaの7日目です。

昨日は

  1. yoppi - QiitaさんのGo - 外部APIを使うController用のTest Doubleライブラリを書いた - Qiita
  2. tienlen - Qiitaさんの記事
  3. minodisk - Qiitaさんのgolang - Exifの回転情報をピクセル情報に反映する - Qiita

だったようです。
てか、Goのカレンダー3つ走ってるのやばくない?

自己紹介

霜鳥です。学生です。趣味は札束・焼肉・寿司に殴られることです。
普段はSwiftしか書いてないので、サーバサイドもGoのこともわかってません。何か新しい発見とか解説とか実用的なものを求めていらっしゃった方がいたら、そういうことはないので適当に流してください。

本題

1度くらいGoで何かやってみようと思ってたので、作った。
鯖で使った方が美味いんだろうけど、そっちはよくわからないので、コマンドラインツールで。tcnksm/gcli · GitHubとやらを使うとすぐ作れるという話だったし。

ninjinと言います。実質「対Swift用」なのでロゴのアレの色に似せた名前*1にしたけど、冷静に考えてXcodeの青い色の名前つけるべき。

github.com

クオリティ及び有用性には欠陥があるものの、とりあえず作ったから良し。動くから良し。
でも今思い返すとなんでこんな変なの作ったのか自分でもわからない。

作った経緯・用途

作ったものとしては、一言で表すと「Xcodeenvっぽいもの」。

MacではXcodeがないと開発ができない。例えば makeXcodeに含まれているものを使うのでXcodeがなんらかの理由で消滅していると brew install 中に突然こける。

どのXcodeを使うか設定するコマンドとして xcode-select があって、

Print or change the path to the active developer directory. This directory controls which tools are used for the Xcode command line tools (for example, xcodebuild) as well as the BSD development commands (such as cc and make).

という説明がついており、

sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

と使う。 /Contents/Developer はなくてもいい。

で。このコマンドにお世話になる時がある。ここで↑で言及したSwiftがでてくる。
Swiftコンパイラは基本的にXcode付属のものを使う。つまり使用するXcodeによってSwiftのバージョンが違う。そしてSwiftは絶賛開発途上中なのでXcodeによってSwiftの仕様も違う時がある。

Xcode上で開発しているうちはそのXcodeのものを使ってくれるのでいいけど、コマンドライン上でSwiftを扱う*2となると正しいバージョンのコンパイラ(= Xcode)を指定しないといけない。

それで、 xcode-select にかぶせてrbenvとかpyenvとかそういう類のもの作ったら面白いかなーていうかそれ以外に作りたいネタないなーと思いました、まる
あとはninjin/README.md at master · S-Shimotori/ninjin · GitHubでも読んでください

わざわざツールにしなくてもシェルパワーで xcode-select をやればいいじゃんとか言わない

作ってみて思ったこと: Go編

gcliについて

早速 tcnksm/gcli · GitHub を使ってみた。噂通り楽。コマンド呼び出しのところまではやってくれるので、関数を実装すればすぐにできる。今回の目的はGoそのものであり、そっちに集中できた。
Goは初めてだったけど生成したテストをパクってある程度テストも作れた(コマンド自体のテストは作ってない)。

戻り値について

Goの戻り値が複数あるのは気に入った。わたしは忘れっぽいので戻り値の数や型などでエラーの可能性を示唆してくれるとありがたい。

import について

別パッケージを import する場合、 GOPATH 配下にあるかないかで相対パスが使えるとか使えないとか、私にとっては未知の仕様と遭遇した。それで混乱した挙句意味不明な import をしてしまった。かなしい。

文字列処理について

stringrunebyte が当たり前のように入り乱れてびびった。 びっくりしただけだが、Rubyをやった直後にGoを触ったせいでダメージが大きい。*3

OOPについて

私にとっていちばん難しかったところ。

まず、私が触ってきた言語というとクラスは大文字始まり関数は小文字始まりという奴なので、「一体なんだこれは」となる。
コンストラクタも、書いている気分としては、クラスにメソッドを増やすというより新しく関数作ってる気分。ソートの比較するやつの実装もなんか私の知ってるものと違う。

……などなど、混乱して設計が悲惨なことになってしまった。いきなり書いていい言語じゃなかった。ちゃんとサンプルや慣れた人のコードを見てからやるべきだった。動くからいいけど、やるからにはGoらしく書かないと意味がない。

気になったこととして、
「privateなクラスを戻り値とするpublicなメソッドはありなのか?そういうものなのか?」
というのがある。Goは仕様としてOKだったので思い切り使ってしまったが……実は知らなかっただけで他の言語でもOKとかある?

Swiftはだめって言ってる。
f:id:S_Shimotori:20151130121153p:plain

というわけで今回は「動けばいいや!」だったけど、ちゃんと作ることがあったら、Go用の設計とか規約とか気をつけるつもり。どうしたらいいんだって開発中ずっと迷走してて気分悪かった。

作ってみて思ったこと: その他

/Applications からのXcode発掘

インストール済みのXcodeをリストアップするには /Applications からXcodeを探さなくちゃいけない。ディレクトリ名に「Xcode」と「.app」を含むものをXcodeと判定するのがいちばん単純だが、それだとつまらないのと、あくまでディレクトリ名なのでリネームされている可能性を考えてInfo.plistから判断することにした。

で、この.plistがなかなかの曲者。3形態(xmljsonとバイナリ)があるらしく、要するにパースがめんどい。
なぜかplistをいじる用コマンドの plutil があったので面白そうだったから使ってみることにした。こいつは.plistを書き換えたり標準出力したりファイル出力したりしてくれる。

はじめは -pjsonをやろうとしたのだが、どういうわけかパースに失敗するので、よくヘルプ読んだらなんか違った。

print property list in a human-readable fashion (not for machine parsing! this 'format' is not stable)

↑何これ。
ちなみにInfo.plistの各項目の中で完全一致で"Xcode"を取れるのは2つある。Mac画面左上に出るアプリケーション名と、実行ファイル名である。前者は変更される可能性がある*4ので後者にした。ま、どっち選んでも手間は変わらないし。

パースとか変なことしたせいで処理速度悪い。

バージョンの取得

pyenv・rbenvみたいなことがしたいのでXcodeのバージョンを取る必要がある。short version表記におけるバージョン(7.0.0といったよく見る表記)はInfo.plistに書いてあるので取れるのだが、Swiftコンパイラの判別はこの表記では足りないのでversion.plist*5からproduct build version(7A1001みたいな表記をする)を取得することにした。

この関係で文字列処理が発生した。めんどかった。

IntelliJ上でのGoファイルアイコン

常に大量のGopherくんに見張られてしんどかった。

まとめ

ディレクトリ一覧とったりexecしたり正規表現したりxmlパースしたりテストしたり無駄なことしまくってたのしかったです。
実用性を求めなかったので見ての通り好き放題です。
ちゃんと書き方勉強してサーバサイドやったほうがもっと楽しかったかなあ……

終わりの言葉

以上、Go その2 Advent Calendar 2015 - Qiitaの7日目でした。

7日の記事は

  1. n0bisuke - Qiitaさんの記事
  2. ここの記事
  3. nyamadandan - Qiitaさんの記事

です。
明日は

  1. kawaken - Qiitaさんの記事
  2. otiai10 - Qiitaさんの記事
  3. warashi - Qiitaさんの記事

になるようです。

*1:http://www.colordic.org/colorsample/4006.html

*2:https://github.com/Carthage/Carthage とか。開発中のプロジェクトはSwift2.xで書いてて、拾ってきたライブラリのSwift2.x版はどこにあって、それでもって自分のxcode-selectはどのXcodeを指してるんだっけ。前にアンインストールしたXcode指したままかもしれない……なんてこと、ないですか?さすがにそんな雑なXcodeの扱い方してる人いないですよね……。

*3:もちろん文字列やるならRubyの方がメソッドは揃っている。参考: http://blogger.ukai.org/2011/02/rubygo.html

*4:長いアプリ名でメニューバーが苦しい人などが書き換える可能性がある

*5:Info.plistのなかま。なぜかApple製アプリケーションには含まれている。頻繁にベータ版が出ているためshort versionが同じでproduct build versionが違うXcodeが存在し、version.plistを見ないと判別がつかない。たぶん。