Homebrewで何かをインストールする場合、デフォルトでは最新のバージョンがインストールされます。訳あって過去のバージョンのものをインストールしたい場合の説明がネット上に少なかったので記載しておきます。
もくじ
ライセンスを持っている古いSketchを使いたかった
最近Macを買い替えたのですが、アプリは移行アシスタントを使わずに一つ一つインストールし直すことにしました。Sketchというデザインアプリを使っているのですが、以前は買い切りでずっと使えていたのですが、最近のバージョンはサブスクリプションになっていました。最低限の機能が使えれば良いので、追加の費用を払って最新バージョンにするのも嫌だったので、元々使っていたバージョンをインストールすることにしました。
そのバージョンのインストール用のdmgファイルは普通に公式サイトからダウンロードできるので、手動でインストールするのは簡単です。でも今回のMacからはHomebrewでインストールにこだわりたいと思っていました。
前のMacではCUIアプリはhomebrewでインストールしていましたが、GUIアプリはHomebrewを使うものもあればそうでないものもあり、中途半端な管理をしていました。でも、今回のMacからはhomebrewでインストールできるものは必ずhomebrewでインストールして、一元化しようと考えていました。Homebrewの何が良いのかは次の記事で説明しました。
Formulaを対象のリビジョンに戻す
いくつかネットに載っていたやり方を試したのですが、以下が最も参考になりました。
でも完全にこの通りやっても上手く行かなかったので、結局これを応用して自分でやり方を考えました。使ったバージョンを記載します。
Mac OS | 13.0(22A380) |
---|---|
Homebrew | 3.6.18
※追記で4.0.26にも対応 |
まずFormulaがあるディレクトリに移動します。(Caskの場合はFormulaと呼ばないのかな?本記事ではまとめてFormulaと呼びます。)
1 |
$ cd /opt/homebrew/Library/Taps/homebrew/homebrew-cask/Casks |
homebrewのcoreに入っているアプリなら /opt/homebrew/Library/Taps/homebrew/homebrew-core/Formula となります。これらのパスはM2などのApple Silliconの場合です。従来のIntel Macをお使いの方は、パスが違うとのことなので調べてみてください。
ちなみに、Homebrewの4系以降だとこのディレクトリがローカルに存在しない可能性があります。 brew tap で確認できます。
1 2 3 4 5 6 7 |
$ brew tap buo/cask-upgrade gcenx/wine homebrew/cask homebrew/cask-drivers homebrew/core homebrew/services |
ご自身のご希望のものがなければ、
1 |
$ brew tap homebrew/core |
などのようにして、落としてくるとことが可能です。
このディレクトリでlsをする場合はとんでもない数のファイルが表示されてしまうので注意しましょう。念のため対象のアプリのFormulaが存在しているか確認します。sketchという部分はFormula名なので、対象のものに置き換えてください。
1 |
$ ls sketch.rb |
git logで対象のコミットをかくにんします。私の欲しいバージョンは51.3なので、7行目となります。このコミットIDをメモります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ git log --oneline sketch.rb (省略) 0a1e0282bb Update sketch to 52.3-67297 (#54365) a804d1b652 Update sketch to 52.2-67145 (#54080) 64a57ce5da Update sketch to 52.2-67145 (#53733) 6ef660169d Update sketch to 52.1-67048 (#52859) f50bdd7839 fix missing depends_on macos stanzas (#52821) 1d1bdaca41 Update sketch to 51.3-57544 (#51813) 5faef49903 Update sketch to 51.2-57519 (#50328) babbb4235f Update sketch to 51.1-57501 (#49745) bb367f0bfe Update sketch to 51-57462 (#49475) 645dbb8228 Remove appcast checkpoints (#48325) f156d05840 Update sketch to 50.2-55047 (#47369) f82b9e97f0 Update sketch to 50-54983 (#46908) (省略) |
Formulaを対象のリビジョンに戻します。
1 |
$ git checkout f50bdd7839 sketch.rb |
中身を確認してしてversionが狙ったものになってるか確認します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
$ cat sketch.rb cask 'sketch' do version '51.3-57544' sha256 '65b1152b90b961927894e26b1837f0328447fc0e928b4060dea935b38ad205dc' url "https://download.sketchapp.com/sketch-#{version}.zip" appcast 'https://download.sketchapp.com/sketch-versions.xml' name 'Sketch' homepage 'https://www.sketchapp.com/' auto_updates true depends_on macos: '>= :sierra' app 'Sketch.app' zap trash: [ '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.bohemiancoding.sketch3.sfl*', '~/Library/Application Support/com.bohemiancoding.sketch3', '~/Library/Caches/com.bohemiancoding.sketch3', '~/Library/Caches/com.plausiblelabs.crashreporter.data/com.bohemiancoding.sketch3', '~/Library/Logs/com.bohemiancoding.sketch3', '~/Library/Preferences/com.bohemiancoding.sketch3.LSSharedFileList.plist', '~/Library/Preferences/com.bohemiancoding.sketch3.plist', '~/Library/Cookies/com.bohemiancoding.sketch3.binarycookies', ] end |
自動アップデートとAPI経由せずにインストールする
1 2 3 4 5 6 |
$ HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_FROM_API=1 brew install sketch ==> Downloading https://download.sketchapp.com/sketch-51.3-57544.zip ==> Downloading from https://download.sketch.com/sketch-51.3-57544.zip ######################################################################## 100.0% ==> Installing Cask sketch ==> Moving App 'Sketch.app' to '/Applications/Sketch.app' |
1行目について説明します。通常 brew installすると、自動的に先に brew update が走ってしまいます。そうすると、せっかく狙っているリビジョンに戻したFormulaがまた最新のものになってしまい、狙ったバージョンではなく最新版のアプリがインストールされてしまいます。なので、 HOMEBREW_NO_AUTO_UPDATE=1 という環境変数をつけて brew update が走らないようにします。次の記事を参考にしました。
Mac Homebrewのbrew tapでも自動アップデートがかかって余計な出力が出るので注意
HOMEBREW_NO_INSTALL_FROM_API=1 は4系から必要になったオプションです。軽く上述しましたが、4系ではFormulaやCaskは基本的にローカルには配置せず、その都度APIから取得します。この環境変数をつけないで、 brew installすると、APIから取得した最新のFormulaやCask(実際はJSON形式ですが)を使って、インストールしてしまいます。なので、せっかくローカルでFormulaやCaskを過去のバージョンに戻しても使われないのです。この環境変数をつけると、ローカルのものを使ってインストールしてくれます。
4系のこの変更はかなり暴力的な変更ですよね。私の場合は、勝手にHomebrewが自動的に4系にアップグレードされて、この仕様変更がされていたので、最初、あるソフトウェアのバージョンを戻そうとした時、最新版しかインストールしてくれなくて何時間も沼にハマりました。どうやって気がついたかというと、以下のよう --debug オプションをつけてようやくヒントに至りました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ HOMEBREW_NO_AUTO_UPDATE=1 brew install --build-from-source --debug libxml2 /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading libxml2 from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading icu4c from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading readline from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading python@3.10 from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading gdbm from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading mpdecimal from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading openssl@3 from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading ca-certificates from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading sqlite from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading xz from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading pkg-config from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading python@3.11 from API /opt/homebrew/Library/Homebrew/brew.rb (Formulary::FormulaAPILoader): loading python@3.9 from API Error: You must `brew unpin icu4c` as installing libxml2 requires the latest version of pinned dependencies |
ここの loading libxml2 from APIというのを見つけて検索をしてみたら、APIから、つまりインターネット上からFormulaやCaskをロードする仕組みができたことを知りました。さらにHomebrewの4系からその挙動がデフォルトになっているということがわかりました。
調べていくとこの HOMEBREW_NO_INSTALL_FROM_API=1をつけることで従来通りの動きをしてくれることがわかりました。
確かに、多くの人は最新版さえインストールできればいいので、ローカルに大量のFormulaやCaskのファイルを配置しておくのはディスクの無駄と言えます。でもそれなら、API経由でも過去バージョンをインストールする方法を準備してくれていればいいのに、いくら探しても出てきません。仕方ないので、このローカルのFormulaやCaskを過去のものに戻す、という方法を採用しています。
ちなみに、 HOMEBREW_NO_AUTO_UPDATE=1 は、毎回のコマンドで指定するのではなく、シェルの環境変数に記載してしまった方がいいです。以下の記事に書きましたが、Hombrewのコマンドを叩くたびに自動的にソフトウェアがアップデートされると、依存関係が壊れて何かしら動かなくなる可能性が高いです。こちらはHomebrewを使うかた全員にお勧めしたいです。
そして、過去バージョンを使う可能性がある方は、 HOMEBREW_NO_INSTALL_FROM_API=1 もシェルに設定してしまった方がいいです。せっかく過去バージョンをインストールしたのに、何かのタイミングでAPIから最新版をインストールしてしまうかもしれません。
やり方としては、私の場合は、.zprofileに以下を追記しました。
1 2 |
export HOMEBREW_NO_AUTO_UPDATE=1 export HOMEBREW_NO_INSTALL_FROM_API=1 |
利用中のターミナルのセッションでこれを反映させるためには、
1 |
$ source .zprofile |
を実行します。
なお、環境変数がきちんと設定できたかを確認するには、
1 |
$ brew config |
を実行して表示される中に、
1 2 |
HOMEBREW_NO_AUTO_UPDATE: set HOMEBREW_NO_INSTALL_FROM_API: set |
が表示されていればOKです。
なお、.zprofileなどの設定ファイルを頻繁に編集するようであれば、これらをGitで管理するのがおすすめです。そのためにdotfilesというディレクトリを作って管理する方法を以下で説明しています。
あと、zshの設定をどのファイルに記載するべきかにいくつか考え方があります。それについて以下で考えてみました。
バージョンを固定する
先ほどの環境変数をシェルで指定してしまえば、勝手にアップデートされることはないですが、別に全部固定しなくても特定のものだけ固定し、それ以外は自動アップデートされてもいいという場合の方法をご紹介します。
せっかく狙ったバージョンのアプリを最新版にされないために固定します。ここからは次の記事を参考、というかそのままやりました。
Homebrewのcoreに入っているアプリなら、
1 |
$ brew pin Formula名 |
で行けますが、今回はCaskに入っているアプリなのでこれができません。
なので、Caskを管理するためのツールをインストールします。
1 |
$ brew tap buo/cask-upgrade |
brew tap でインストールできるというのがよくわからないですが、これで使えるようになります。
以下で固定されます。
1 |
$ brew cu pin sketch |
確認するには、
1 2 3 |
$ brew cu pinned Cask Current Latest 1/1 sketch 51.3-57544 94.1,156562 |
とします。
残る疑問、アンインストール時はどうなるの?
HomebrewのFormulaは何かと自動的にアップデートされる仕組みになっているので、sketch.rbもすぐに最新版になってしまうと思います。でも、Formulaには以下の16〜25行目のようにアンインストール時の処理も記載されています。設定ファイルなどを削除する処理のようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
$ cat sketch.rb cask 'sketch' do version '51.3-57544' sha256 '65b1152b90b961927894e26b1837f0328447fc0e928b4060dea935b38ad205dc' url "https://download.sketchapp.com/sketch-#{version}.zip" appcast 'https://download.sketchapp.com/sketch-versions.xml' name 'Sketch' homepage 'https://www.sketchapp.com/' auto_updates true depends_on macos: '>= :sierra' app 'Sketch.app' zap trash: [ '~/Library/Application Support/com.apple.sharedfilelist/com.apple.LSSharedFileList.ApplicationRecentDocuments/com.bohemiancoding.sketch3.sfl*', '~/Library/Application Support/com.bohemiancoding.sketch3', '~/Library/Caches/com.bohemiancoding.sketch3', '~/Library/Caches/com.plausiblelabs.crashreporter.data/com.bohemiancoding.sketch3', '~/Library/Logs/com.bohemiancoding.sketch3', '~/Library/Preferences/com.bohemiancoding.sketch3.LSSharedFileList.plist', '~/Library/Preferences/com.bohemiancoding.sketch3.plist', '~/Library/Cookies/com.bohemiancoding.sketch3.binarycookies', ] end |
当然このあたりの処理もバージョンによって違いうるということだと思います。なので、このファイルが現在インストールされているバージョンと齟齬があった場合、適切にアンインストール時の処理がされるのだろうか?という疑問が残りました。
インストールされているFormulaがどこかに保存されていて、アンインストール時に使われるのかと思ったけど、見当たりませんでした。
まぁ、基本的にこの辺りの設定ファイルが消されなかったとしても、ゴミが残るだけで大した問題はないと思いますし、より新しいバージョンにアップグレードする場合は、上書かれるということだと思うので大きな問題はないはずですが、ちょっと気持ち悪いですね。
今後この辺りのHomebrewの細かい挙動を理解できればと思います。
他に試した方法
Homebrew Cask で特定のバージョンを指定してインストールする
この方法はうまく行かなかった。
1 |
$ brew install tmp.rb |
とあるが、 tmp.rb のような適当なファイル名じゃダメで、以下の記事のように
Homebrew: How do you specify a version using brew cask?
1 |
$ brew install --cask <Formula名>.rb |
のようなファイル名にしなければなりません。また --cask が無いと余計なエラーの表示が出ます。エラーが出てもよしなにインストールはしてくれます。
とはいえ、これはわざわざFormulaのファイルを手動でダウンロードしてくるやり方なので、私が前述した方法の方がスマートだと思います。