KOYAMA Yoshiaki のブログ

プログラミングについての試行錯誤をつらつら書き溜めていきます。

Homebrew をちょこっと解析、Cocoa Emacs インストール。

前回書いたように、パッケージシステムとして MacPorts から Homebrew に変更してみました。

Installation - GitHub
https://github.com/mxcl/homebrew/wiki/installation

Homebrew をインストールするには、上記ページの Installation で表示されているスクリプト

/usr/bin/ruby -e "$(curl -fsSL https://raw.github.com/gist/323731)"

をコピーし、ターミナル上でペーストして実行するだけです。ただし、上記に記載されている通り、事前に Xcode をインストールしておく必要があります。


Safari で直接、https://raw.github.com/gist/323731にアクセスすれば、Homebrew をインストールする Ruby スクリプトを見ることができます。 (curl コマンドでもダウンロードできます。)


curl は、サーバから、あるいはサーバへ、データ伝送を行うツールです。プロトコル HTTP、HTTPSFTP などに対応してます。上のスクリプトの場合、指定した URL [ https://raw.github.com/gist/323731 ] が返す Ruby スクリプトをダウンロードします。各引数は、ターミナルで man curl を使って確認してください。(man curl | col -bfx > curl.txt でファイルに変換して、open curl.txt で中身を確認すると便利です。)


その後、/usr/bin/ruby -e コマンドで Ruby スクリプトを実行します。


スクリプトの内容は、簡単に説明すると

/usr/local/.git ディレクトリの中身が空じゃない時、スクリプトを終了。

/usr/local/
	bin/
	Cellar/
	etc/
	include/
	lib/
	Library/
	sbin/
	share/
	var/
	.git/

のそれぞれのディレクトリが存在しない時、/bin/mkdir で新規作成、存在する時は属性を変更。


ディレクトリ /usr/local に移動し、https://github.com/mxcl/homebrew/tarball/master から mxcl-homebrew-xxxxxxxx.tar.gz ファイルをダウンロードして展開する。

これで終了です。


Homebrew のディレクトリのおおざっぱな中身は

/usr/local/

	bin/
		brew
	Cellar/
		
	Library/
		Aliases
		Contributions
			brew_bash_completion.sh
			brew_fish_completion.fish
			brew_zsh_completion.zsh
			examples/
				brew-bottle.rb
				brew-depstree.rb
				brew-dirty.rb
				brew-graph
				brew-grep
				brew-leaves.rb
				brew-linkapps.rb
				brew-man
				brew-missing.rb
				brew-pull.rb
				brew-readall.rb
				brew-server
				brew-switch.rb
				brew-unpack.rb
				brew-upgrade.rb
				brew-which.rb
			manpages/
		Formula/
			emacs.rb
			wget.rb
			.
			.
		Homebrew/
			blacklist.rb
			cleaner.rb
			compatibility.rb
			download_strategy.rb
			exceptions.rb
			formula.rb
			formula_installer.rb
			global.rb
			hardware.rb
			install.rb
			keg.rb
			keg_fix_install_names.rb
			utils.rb
			cmd/
				---cache.rb
				--cellar.rb
				--config.rb
				--env.rb
				--prefix.rb
				--repository.rb
				audit.rb
				cat.rb
				cleanup.rb
				create.rb
				deps.rb
				diy.rb
				doctor.rb
				edit.rb
				fetch.rb
				help.rb
				home.rb
				info.rb
				install.rb
				link.rb
				list.rb
				log.rb
				options.rb
				outdated.rb
				prune.rb
				search.rb
				test.rb
				uninstall.rb
				unlink.rb
				update.rb
				uses.rb
			extend/
				ARGV.rb
				ENV.rb
				pathname.rb
				string.rb
			test/
	share/

です。


また、キャッシュとして

~/Library/Caches/Homebrew 

フォルダが利用されます。Library フォルダは不可視になっていますが、ターミナル上で

~ $ open Library

で開くことができます。


brew コマンドのヘルプは、

man brew
brew help

で確認できます。


ここでは、wget のパッケージをインストールするコマンド

brew install wget

の動作を簡単に説明したいと思います。間違っている個所もあるかもしれません。


実行ファイル /usr/bin/brew は、rubyスクリプトです。

#--- /usr/local/ibin/brew ---

  cmd = ARGV.shift # => 'install'
  cmd = aliases[cmd] if aliases[cmd] # cmd = :install

cmd に :install が代入され

#--- /usr/local/ibin/brew ---

 elsif require? HOMEBREW_REPOSITORY/"Library/Homebrew/cmd"/cmd
    Homebrew.send cmd.to_s.gsub('-', '_')

/usr/local/Library/Homebrew/cmd/install.rb が読み込まれ、module Homebrew は /usr/local/Library/Homebrew/cmd/install.rb に宣言されています。

send (Object) - Rubyリファレンス
http://ref.xaio.jp/ruby/classes/object/send

Homebrew.send は Homebrew モジュールの install メソッドを呼ぶことになります。

#--- /usr/local/Library/Homebrew/cmd/install.rb ---

module Homebrew extend self
  def install
    ARGV.named.each do |name|
      msg = blacklisted? name
      raise "No available formula for #{name}\n#{msg}" if msg
    end unless ARGV.force?

    install_formulae ARGV.formulae
  end

ARGV は

#--- /usr/local/bin/brew ---
require 'global'

#--- /usr/local/Library/Homebrew/global.rb ---

require 'extend/pathname'
require 'extend/ARGV'
require 'extend/string'
require 'utils'
require 'exceptions'

ARGV.extend(HomebrewArgvExtension)

から /usr/local/Library/Homebrew/extend/ARGV.rb で拡張されています。

#--- /usr/local/iLibrary/Homebrew/cmd/install.rb ---

module Homebrew extend self
  def install
    ARGV.named.each do |name|
      msg = blacklisted? name
      raise "No available formula for #{name}\n#{msg}" if msg
    end unless ARGV.force?

    install_formulae ARGV.formulae
  end

/usr/local/Library/Homebrew/blacklist.rb の blacklisted? でインストールできないパッケージを判断。

#--- /usr/local/iLibrary/Homebrew/cmd/install.rb ---

 install_formulae ARGV.formulae

ARGV.formulae は Arrray 型で、インストールする Foumla が入っています。今回は Class Wget が1つ入っています。Class Wget は、/usr/local/Library/Formula/wget.rb で宣言されています。

#--- /usr/local/iLibrary/Homebrew/formula_installer.rb ---
 
 def install_formulae formulae
    formulae = [formulae].flatten.compact
    return if formulae.empty?

    check_ppc
    check_writable_install_location
    check_cc
    check_macports

    formulae.each do |f|
      begin
        installer = FormulaInstaller.new f
        installer.ignore_deps = ARGV.include? '--ignore-dependencies'
        installer.go
      rescue FormulaAlreadyInstalledError => e
        opoo e.message
      end
    end
  end

f は、Formula クラスを継承した Wget クラスが入っています。FormulaInstaller の @f にも格納されています。

#--- /usr/local/iLibrary/Homebrew/formula_installer.rb ---
 
 def go
    if @f.installed? and not ARGV.force?
      raise FormulaAlreadyInstalledError, @f
    end

    unless ignore_deps
      needed_deps = @f.recursive_deps.reject {|d| d.installed?}
      unless needed_deps.empty?
        puts "Also installing dependencies: "+needed_deps*", "
        needed_deps.each do |dep|
          FormulaInstaller.install_formula dep
        end
      end
      begin
        FormulaInstaller.check_external_deps @f
      rescue UnsatisfiedExternalDependencyError => e
        onoe e.message
        exit! 1
      end
    end
    FormulaInstaller.install_formula @f
  end

FormulaInstaller.install_formula @f を呼び出すことになります。

#--- /usr/local/iLibrary/Homebrew/formula_installer.rb ---

  def self.install_formula f
    @attempted ||= Set.new
    raise FormulaInstallationAlreadyAttemptedError, f if @attempted.include? f
    @attempted << f
    ENV['HOMEBREW_ERROR_PIPE'] = write.to_i.to_s

    fork do
      begin
        read.close
        exec '/usr/bin/nice',
             '/usr/bin/ruby',
             '-I', Pathname.new(__FILE__).dirname,
             '-rinstall',
             '--',
             f.path,
             *ARGV.options_only
      rescue Exception => e
        Marshal.dump(e, write)
        write.close
        exit! 1
      end
    end

fork、nice を使用していますが、簡単に説明すると

/usr/bin/ruby -I /usr/local/Library/Homebrew -rinstall -- /usr/local/Library/Formula/wget.rb

上記コマンド実行します。


上のスクリプトを実行する時に読み込んでいるライブラリ /usr/local/Library/Homebrew/install.rb の下のソースからプログラムが開始されます。

#--- /usr/local/iLibrary/Homebrew/installer.rb ---

at_exit do
  begin
    raise $! if $! # an exception was already thrown when parsing the formula

    require 'extend/ENV'
    require 'fileutils'
    require 'hardware'
    require 'keg'
    require 'compatibility'

    ENV.extend(HomebrewEnvExtension)
    ENV.setup_build_environment

    puts "-----"
    puts $0
    install(Formula.factory($0))
  rescue Exception => e
    if ENV['HOMEBREW_ERROR_PIPE']
      pipe = IO.new(ENV['HOMEBREW_ERROR_PIPE'].to_i, 'w')
      Marshal.dump(e, pipe)
      pipe.close
      exit! 1
    else
      onoe e
      puts e.backtrace
      exit! 2
    end
  end
end

install(Formula.factory($0)) が実行している箇所です。$0 は、/usr/local/Library/Formula/wget.rb です。

#--- /usr/local/iLibrary/Homebrew/installer.rb ---

def install f
# ・
# ・
# ・
# ・
      else
        f.prefix.mkpath
        beginning=Time.now
        f.install if not f.pourable?
        FORMULA_META_FILES.each do |filename|
# ・
# ・
# ・
end

f.install の部分が wget.rb の Class Wget で install メソッドを呼び出して実際にインストールしている箇所です。

#--- /usr/local/iLibrary/Formula/wget.rb ---

  def install
    args = ["--disable-debug",
            "--disable-dependency-tracking",
            "--with-ssl=openssl",
            "--prefix=#{prefix}"]
    args << "--disable-iri" unless ARGV.include? "--enable-iri"

    system "./configure", *args
    system "make install"
  end

これが、brew を使って wget をインストールするおおまかな流れです。


Cocoa Emacs も Homebrew を使ってインストールしてみました。Cocoa Emacs の Formula は、あらかじめインストールされているものより

Homebrew Emacs for OSX Lion with native full-screen ― Gist
https://gist.github.com/1109223

で公開されているものから、Forks されている最新版 Formula (emacs.rb : 入手先、インストール方法などが記載されています。)

Homebrew Emacs for OSX Lion with native full-screen ― Gist
https://gist.github.com/1128997

を利用しました。


Formula の URL は、ソースの右上 'raw' 文字をクリックして確認できます。また、Option で --use-git-head を使わない場合、あらかじめ bazaar をインストールしておく必要があります。(残念ながら、git を使って最新版をダウンロードすると patch をあてることができませんでした。)

~ $ brew install bazaar
~ $ brew install https://raw.github.com/gist/1128997/347bb0d97155a294d9c50b6418c9130fadec8a5b/emacs.rb --cocoa --lion
~ $ cp -pR /usr/local/Cellar/emacs/23.3a/Emacs.app /Applications


日本語入力にも対応しています。command + space で日本語入に力切り替えることができます。.emacs ファイルに

;;------- .emacs -------
;; shell
(global-set-key [f5] 'shell)

;; IM
(setq default-input-method "MacOSX")

IM を追加してください。ついでに F5 キーでシェルを起動するようにしてみました。


Emacs を学び直してみようと思い、iTunes App Store

Learning GNU Emacs, Third Edition
カテゴリ/ブック
\600
http://itunes.apple.com/jp/app/learning-gnu-emacs-third-edition/id333188827?mt=8

を購入しました。

404 Blog Not Found:perl - O'ReillyのiPhoneアプリ本からepubをぶっこぬく
http://blog.livedoor.jp/dankogai/archives/51484907.html

上記スクリプトを使って epub に変換し、iPad で読んでいます。たった 600 円でオライリー本を入手できるので、iPad を所有している人には、ぜひお勧めです。