rcmdnk's blog

etc works

Brew-fileIssue で指摘してもらって気づいたのですが、 Homebrewでetcディレクトリを含むパッケージをインストールすると、 アップデートがきちんと行われない事態に陥る事になる事があったのでそれの解決法について。

etc.installの仕様

HomebrewでGitHubにあるレポジトリを取ってきて そのまま中にあるbinetcディレクトリの中のファイルをインストールするような場合、 通常、

bin.install "bin/brew-file"

等と書いておくと、取ってきて展開したりしたディレクトリのbin/brew-file/usr/local/Cellar/brew-file/3.9.3/bin/ 1 などへコピーし、 さらに/usr/bin/にそこへのシンボリックリンクを作ります。

lib等のディレクトリも同様。

但し、etcディレクトリに限っては、

etc.install "etc/brew-wrap"

の様にしておくと、Cellarにはコピーされず、 /usr/etc/に直接ファイルがコピーされます。

homebrew/formula.rb at master · Homebrew/homebrew: https://github.com/Homebrew/homebrew/blob/master/Library/Homebrew/formula.rb#L644

さらに、既にファイルが存在している場合、新しいファイルで上書き等はしないので、 一度インストールすると、brew upgrade等をしても新しい物に置き換わりません。 ファイルが存在している場合には代わりにbrew-wrap.defaultというファイルが作成されます。

また、brew uninstallでパッケージを消した際にも消えません。

etcに意図的に同名のファイルを事前にインストールした場合に Homebrew側では全てそのままにしておく、と言う処置ですが、 Homebrew-fileでも/usr/local/etc/brew-fileというbrewコマンドを ラップするためのファイルを置いているのでこれがアップデートされないと困ります。

etcbin等と同様に扱う

etcを他のbin等と同様にCellarにインストールしてシンボリックリンクを作る、 という扱いにするためには

(prefix/"etc").install "etc/brew-wrap"

のように(prefix/”etc”).installを使います。

ここで、prefixはパッケージの実態がインストールされるCellarの位置になるので、 Cellarの中のetcetc/brew-wrapをコピーすることになります。 さらに、この様にCellarにインストールすると 自動的に/usr/local/etcにシンボリックリンクが貼られます。

homebrew/Formula-Cookbook.md at master · Homebrew/homebrew: https://github.com/Homebrew/homebrew/blob/master/share/doc/homebrew/Formula-Cookbook.md

これで、bin以下にあるものなどと同様のインストールが出来、 さらにuninstall時にもきちんと消えてくれます。 勿論、アップデートすると新しいCellarへのリンクになるのでファイルの内容もアップデートされます。

注意として、これまでetc.installを使ってきて(prefix/”etc”).installに変更すると、 brew upgradeや再インストールする際、

==> Installing brew-file from rcmdnk/file
==> Downloading https://github.com/rcmdnk/homebrew-file/archive/v3.9.3.tar.gz
Already downloaded: /Library/Caches/Homebrew/brew-file-3.9.3.tar.gz
Error: The `brew link` step did not complete successfully
The formula built, but is not symlinked into /usr/local
Could not symlink etc/brew-wrap
Target /usr/local/etc/brew-wrap
already exists. You may want to remove it:
  rm '/usr/local/etc/brew-wrap'

To force the link and overwrite all conflicting files:
  brew link --overwrite brew-file

To list all files that would be deleted:
  brew link --overwrite --dry-run brew-file

Possible conflicting files are:
/usr/local/etc/brew-wrap

みたいなエラーが出ます。古いファイルがシンボリックリンクではないので どう扱ってよいか戸惑ってしまう訳です。

取り敢えず他にconflictしてる物が無さそうなら

$ brew link --overwrite brew-file

を実行すればOK。他にもconflictがあってそちらは治したくない場合は

$ rm '/usr/local/etc/brew-wrap'

をして、

$ brew reinstall brew-file

等とパッケージを再インストールしてください。

Formula側で強制的に上書きしたい場合は

rm_f etc/"brew-wrap.default"
rm_f etc/"brew-wrap"
(prefix/"etc").install "etc/brew-wrap"

の様にrm_fを使ってファイルを消してやればOK。 これまでetc.installを使っていたのであれば defaultファイルも余計に出来てるはずなのでそれも削除するように。

これで快適にetcを含むパッケージを使えます。

Brew-fileでは上の設定を入れてあるのでbrew update && brew upgrade してもらえば/usr/local/etc/brew-wrapはシンボリックリンクに 変更されて、今後きちんとアップデートされるようになります。

install_symlinkについて

蛇足ですが、installの他にinstall_symlinkという関数もあり、 これを

etc.install_symlink "#{prefix}/etc/brew-wrap"

とすることとかを最初考えてたんですが、これだと /usr/local/etc/brew-fileというシンボリックリンクが出来て、 ../Cellar/brew-file/3.9.3/etc/brew-fileを指す正しいリンクなんですが、 肝心の../Cellar/brew-file/3.9.3/etc/brew-fileへ ファイルがコピーされないのでシンボリックリンクを開くと空ファイルになってしまいます。

install_symlink/usr/local下へのインストールに使う、というよりも、 Cellar内でリンクを貼る作業に使う物な感じでした。

つまり、

(prefix/"etc").install "etc/brew-wrap"
(prefix/"etc/more").install_symlink prefix/"etc/brew-wrap"

みたいにしておくと、Cellar内にetc/more/brew-wrapという、 etc/brew-wrapへのシンボリックリンクが出来、 さらに/usr/local/etc/more/brew-wrapにそのファイルに対するシンボリックリンクが出来ます。

Sponsored Links
  1. ここでは/usr/localをHomebrewのインストール場所としていますが、 以下の/usr/localは全てbrew --prefixで出てくるHomebrewをインストールした場所です。

Sponsored Links

« Homebrew-Caskの仕様が変わったので自作Caskの変更が必要だった ブログのはてブ人気リストをRSSから取得して表示する »

}