社内で使う SVN(Subversion) の GUI クライアントを、macOSネイティブアプリとして自作しました。作るだけでなく「他のMacに配って警告なく起動できる」ところまでやった、その裏側の話です。
なぜ今さらSVNクライアントを作るのか
Gitが主流になった今も、SVNで回っている現場は珍しくありません。ところが定番だったGUI(SourceTree)はSVN対応をやめ、残る選択肢は古いか、コマンドライン直叩きか。「履歴をサッと辿って差分を見る」だけの快適な道具が、macOSに意外と無いのです。
無いなら作る、が一番早い。SourceTreeのようにリビジョン履歴を辿り、変更ファイルと差分を確認することに軸を置いたビューアとして、SwiftUI + MVVM で組みました。
SVN本体は作らない — OSのsvnをProcessで叩く
SVNのプロトコルを自前で実装する必要はありません。Macに入っている svn コマンドを Process で起動し、--xml 出力をパースするだけで、堅牢な結果がそのまま手に入ります。
svn log -v --xml -l 50 // 履歴+各リビジョンの変更ファイルを1回で取得 svn diff -c 1234 -- path // ファイルを選んだ時だけ、その差分を取得
履歴一覧・変更ファイル・差分の3ペイン(SourceTree的なレイアウト)で、選択のたびに必要な分だけ svn を呼ぶ。UIは薄く、重い処理はすべて実績のある svn に任せる設計です。
「Sandboxを切る」判断が、配布のハードルを上げる
ここが一番の勘所でした。外部コマンド(svn)を Process で起動するには、App Sandbox を無効にする必要があります。Sandbox内からは他プロセスを起動できないためです。
これは同時に、Mac App Store での配布を諦めることを意味します(App StoreはSandbox必須)。だから配布は「直接ダウンロード」一択。ところが Sandbox無効のアプリを他のMacに渡すと、今度は——
「"SVNClient" は壊れているため開けません。ゴミ箱に…」
これを消すのが 公証(Notarization) です。Developer ID で署名し、Appleのサーバに提出して承認を受け、その結果をアプリに貼り付ける(staple)。この一連を毎回手でやると事故るので、スクリプト1本にまとめました。
# archive → 署名書き出し → 公証 → staple → DMG化 まで自動 scripts/distribute.sh SVNClient-notary # → build/SVNClient.dmg(他のMacでも警告なく起動できる状態)
最後の落とし穴 — 会社HPに置こうとしたら弾かれた
できたDMGを、この会社サイト(Firebase Hosting)に置いて配ろうとしたところ、デプロイが丸ごと失敗しました。
Error: Executable files are forbidden on the Spark billing plan
Firebase Hostingの無料プランは 実行ファイル扱いの .dmg を拒否します。しかも厄介なことに、1ファイルでも弾かれるとそのデプロイ全体が巻き添えで失敗する。
回避策はシンプルで、DMGをzipで包んでから置くこと。Firebaseは配信ファイル自体の種別で判定し、zipの中までは見に行きません。
ditto -c -k --keepParent build/SVNClient.dmg SVNClient.dmg.zip
# → これなら通る。配布ページのリンクも .zip を指す
ユーザーは .zip を解凍 → .dmg を開く、という一手間が増えるだけ。無料プランのまま、会社サイトから自社ツールを配れるようになりました。
社内ツールも「配れる」ところまでやる
動くものを作るのと、誰かのMacで警告なく起動できる状態まで仕上げるのは別の仕事です。署名・公証・配布経路の詰めは地味ですが、ここを越えて初めて「ツール」は「渡せる道具」になります。
私たちは、こうした業務を回すための小さな道具づくりから、その配布・運用までを一貫してやっています。