mono0926/LicensePlist という、Carthage・CocoaPodsおよび手動指定ライブラリから、iOS設定アプリに載せられるplist形式のライセンスファイル群を生成するコマンドラインツールを作りまして、それをHomebrewに登録したのでやり方を共有します。
結果的にはまあまあ簡単ですが、Homebrew登録自体が初めてだったので、多少手こずりました。
前提
- Swift Package Manager(SwiftPM)で作ったコマンドラインツールのHomebrew登録
- 本家Homebrewリポジトリへの登録ではなく、
brew tap
方式 - Bottlesという、バイナリ配布対応はスキップしたため、インストール先で都度ビルドが必要
対応手順
Makefile を作成
本体のコマンドラインツールリポジトリで Makefile を用意します。SwiftPM ではHomebrew対応せずとも簡単なMakefileを用意するのがわりと一般的なので、Homebrew対応前からすでに作成済みだったりもすると思います。
PREFIX?=/usr/local
build:
swift build -c release -Xswiftc -static-stdlib
install: build
mkdir -p "$(PREFIX)/bin"
cp -f ".build/release/LicensePlist" "$(PREFIX)/bin/license-plist"
install
にて、次に作るFormulaファイルから渡す$(PREFIX)
を使うように設定するのが肝です。そのディレクトリを生成してビルドされたバイナリファイルをコピーしています。PREFIX
に?=
で/usr/local
を代入しているので、普通にmake install
した場合は、/usr/local/bin
配下にコピーされます。
Homebrew対応の本筋とは外れますが、swift build -c release -Xswiftc -static-stdlib
の -Xswiftc -static-stdlib
オプションも大事です。標準ライブラリおよび依存ライブラリとstatic linkしてくれるので、単一実行バイナリが生成できます。
以下の記事で紹介されていました。このオプション指定以外にも大いに参考にさせていただきました🙇
Building a command line tool using the Swift Package Manager
参考に、こちらがLicensePlistのMakefileです。
出来たら、Pushしてタグを打っておきましょう。以下では1.3.5
タグを打ったとして説明していきます。
[2019/04/13 追記]
macOS High Sierra以降では --disable-sandbox
指定が必要
Xcode 10.2(Swift 5.0)以降では -Xswiftc -static-stdlib
は不要(むしろ指定するとビルドエラー)
Formulaファイル作成
https://github.com/mono0926/LicensePlist がコマンドラインツール本体ですが、それに対応する
https://github.com/mono0926/homebrew-license-plist というbrew tap
用のリポジトリを作成します本体のコマンドラインツールリポジトリがキャメルケースだったので、ちょっと揺れが出てしまっています…)。
今回は名前を合わせましたが、合わせなくても良いです。mono0926/taps
などのリポジトリ名の方が今後他の時にも流用出来て良かったかも、と今思っています…。
まずは以下を実行してひな形を生成します。
$ brew create https://github.com/mono0926/LicensePlist/archive/1.3.5.tar.gz
https://github.com/mono0926/LicensePlist/archive/1.3.5.tar.gz 部分は、リポジトリのURL
/archive/タグ
.tar.gz という構成になっています。これは、タグを打つと、その時点のスナップショットとそのURLをGitHubが自動生成してくれるようになっています(Releasesに載っているダウンロードURLと同じです)。
Editing /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/licenseplist.rb
というメッセージとともにひな形の編集画面が開きます。
ひな形はこうなっています。
# Documentation: http://docs.brew.sh/Formula-Cookbook.html
# http://www.rubydoc.info/github/Homebrew/brew/master/Formula
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
class LicensePlist < Formula
desc "A license list generator of all your dependencies for iOS applications"
homepage ""
url "https://github.com/mono0926/LicensePlist/archive/1.3.5.tar.gz"
sha256 "bae83138b45e062cf1cfa8ee627d7cf0912147e56a9bd93f643b63125d6dd182"
# depends_on "cmake" => :build
def install
# ENV.deparallelize # if your formula fails when building in parallel
# Remove unrecognized options if warned by configure
system "./configure", "--disable-debug",
"--disable-dependency-tracking",
"--disable-silent-rules",
"--prefix=#{prefix}"
# system "cmake", ".", *std_cmake_args
system "make", "install" # if this fails, try separate make/make install steps
end
test do
# `test do` will create, run in and delete a temporary directory.
#
# This test will fail and we won't accept that! It's enough to just replace
# "false" with the main program this formula installs, but it'd be nice if you
# were more thorough. Run the test with `brew test LicensePlist`. Options passed
# to `brew install` such as `--HEAD` also need to be provided to `brew test`.
#
# The installed folder is not in the path, so use the entire path to any
# executables being tested: `system "#{bin}/program", "do", "something"`.
system "false"
end
end
PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
と書かれた通り消しましょう(brew tap
形式なので残ってても問題無いですが)。
class LicensePlist < Formula
desc "A license list generator of all your dependencies for iOS applications"
homepage ""
url "https://github.com/mono0926/LicensePlist/archive/1.3.5.tar.gz"
sha256 "bae83138b45e062cf1cfa8ee627d7cf0912147e56a9bd93f643b63125d6dd182"
def install
system "./configure", "--disable-debug",
"--disable-dependency-tracking",
"--disable-silent-rules",
"--prefix=#{prefix}"
system "make", "install"
end
test do
system "false"
end
end
そして、SwiftPMのコマンドラインツールをうまくビルドできるように編集して、以下が完成系です。
class LicensePlist < Formula
desc "A license list generator of all your dependencies for iOS applications"
homepage ""
url "https://github.com/mono0926/LicensePlist/archive/1.3.5.tar.gz"
sha256 "bae83138b45e062cf1cfa8ee627d7cf0912147e56a9bd93f643b63125d6dd182"
def install
system "make", "install", "PREFIX=#{prefix}"
end
depends_on :xcode => ["8.3", :build]
end
先ほどのMakefile
で参照できるように、install
メソッドで, "PREFIX=#{prefix}"
にてPREFIX
環境変数を渡すのが肝です。ちなみに、以下のようなログが出て、/usr/local/Cellar/license-plist/1.3.5
がセットされていることが分かります。
$ make install PREFIX=/usr/local/Cellar/license-plist/1.3.5
testは使わずで良いと思ったのでカットしましたが、必要に応じて記述してください。
depends_on
は無くとも動きますが、 @ikesyo さんに指摘していただき、付け足しました。あった方が親切ですね。
うまくインストールできるか試します(ローカルではFormula以下にあるので普通にインストールできます)。
$ brew install license-plist
また。ls -l
で詳細情報を見ると、先ほどのPREFIX
配下に実態があって、シンボリックリンクが張られていることが分かります。
$ ls -l /usr/local/bin/license-plist
$ lrwxr-xr-x 1 mono admin 47 May 20 20:51 /usr/local/bin/license-plist -> ../Cellar/license-plist/1.3.5/bin/license-plist
うまくいったら、以下のようにbrew tap
用のリポジトリに移動してPushしましょう。
$ mv /usr/local/Homebrew/Library/Taps/homebrew/homebrew-core/Formula/licenseplist.rb "homebrew-license-plist をチェックアウトした場所"
こちらがhomebrew-license-plistのFormulaです。
確認
以下のコマンドを実行して、インストール成功すればOKです。エラー出たら、解決がんばりましょう💪
$ brew install mono0926/license-plist/license-plist
オーナー名
/brew tap用に作ったリポジトリからhomebrew-の接頭辞を省いた名前
/Formula名
という構成です。
ちなみに、以下の短縮形です。
$ brew tap mono0926/license-plist
$ brew install license-plist
アップデート作業
本体リポジトリでのリリースの度に次のような操作が必要です。
- 本体リポジトリでタグを打つ
- brew tap用のリポジトリで
url
に記述してあるタグ部分を書き換え、さらにsha256
も更新してPush -
brew upgrade license-plist
を実行して確認
さらに
sha256
も更新
これが地味に面倒なのですが、愚直にダウンロードしてsha256計算するしか無いのですかね?🤔良いやり方ご存じでしたら教えてください🙇
とりあえず以下のスクリプトを作ったので、./copy_sha256.sh 1.3.5
を実行するとダウンロード・sha256の計算に加えて、さらにクリップボードにコピーまでしてくれて面倒さは解消しました(スクリプト用意しなくて良い楽な方法があれば不要になってしまいますが…)。
if [ $# -eq 0 ]; then
echo "A tag argument is needed!(ex: ./copy_sha256 1.2.3)"
exit 1
fi
tag=$1
echo "Tag: '${tag}'"
filename="${tag}.tar.gz"
echo "Filename: '${filename}'"
curl -LOk "https://github.com/mono0926/LicensePlist/archive/${filename}"
result=$(shasum -a 256 $filename)
echo "Result: '${result}'"
sha256=$(echo ${result} | cut -d ' ' -f 1)
echo $sha256 | tr -d '\n' | pbcopy
echo "sha256('${sha256}') was copied to your clipboard🎉"
rm $filename
今後の更新作業がスムーズになるようにこれもリポジトリに含めました。アップデート更新作業全体を自動化したいなどとも思っています。
その他
Bottles対応を省いた理由
単純にBottlesやその他解説記事の通りにやってみたら、各プラットフォーム向けにバイナリファイル生成したり、さらにそれを更新していくのが手間(手動にしても自動スクリプト書くにしても)だと思ったからです。
@_mono 初回は苦戦した記憶がありますが、1度やれば簡単だった気がします。参考になるかわかりませんが、当時のメモを貼っておきますね。 https://t.co/OBZtRlwl1S
— ishkawa (@_ishkawa) May 14, 2017
@_mono それは試したことないですね。自分はbrewで入ればなんでも良いか〜って思ってCarthageの真似で済ませちゃいました。
— ishkawa (@_ishkawa) May 14, 2017
Bottles対応を省くと以下のデメリットはあります。
- インストール・アップデート時に、ビルド時間が少しかかる
- Bottles対応しておけばバイナリファイルダウンロード時間だけで済む
- 過去バージョンのバイナリをインストールできず、常に最新版のタグになってしまう
過去の版欲しい場合(デグレなどで最新版で動かなくなってしまった時など)は、一応Releasesからダウンロードする方法も提供していますし、あるいは過去のタグでビルドしてもらっても一応何とかなるので、まあ良いかなと今のところ思っています。
参考リンク
- SwiftPM
- Homebrew
-
Swiftで書いたコマンドラインツールをHomebrewでインストールできるようにする
- これは
SwiftPM
ではなくxcodebuild
を使ったものですが、それ以外はほぼ同じです
- これは
-
Homebrewで自作のプロジェクト(ライブラリ)を公開する - Qiita
- Bottles対応
-
Swiftで書いたコマンドラインツールをHomebrewでインストールできるようにする
LicensePlistのロゴ
ロゴ作っちゃいました( ´・‿・`)
設定アプリに載るライセンスファイル一覧生成なので、設定アプリアイコンっぽい感じにして、さらにCopyright @ mono
でライセンスっぽさを加えました( ´・‿・`)