はじめに
capistranoをよく使っているのでソースコードを読んでいます。できればコミットできるようになりたいね。
bin/cap
capコマンドを実行するときはこのbinフォルダ以下のcapが実行されている。
capistrano/bin at master · capistrano/capistrano · GitHub
#!/usr/bin/env ruby require "capistrano/all" Capistrano::Application.new.run
Capistrano::Aplicationオブジェクトをnewしてrunを実施しているので、本体はそっちだ。
なおcapifyは2系で存在し、現在は廃止になったコマンド。わざわざファイル作ってhelp出してるところが可愛い。
take@MacBook-Air ~/capistrano> capify -------------------------------------------------------------------------------- Capistrano 3.x is incompatible with Capistrano 2.x. This command has become `cap install` in Capistrano 3.x For more information see http://www.capistranorb.com/ --------------------------------------------------------------------------------
capistrano/lib/capistrano/application.rb
capistrano/application.rb at master · capistrano/capistrano · GitHub
結構量ありますね。必要なときに戻ってくるとして、まずはinitializeとrunを見てみましょう。
initializeとrun
module Capistrano class Application < Rake::Application def initialize super @rakefiles = %w{capfile Capfile capfile.rb Capfile.rb} << capfile end def name "cap" end def run Rake.application = self super end (省略) end end
Rake::Applicationを継承してますね。
class Rake::Application (Ruby 1.9.3)
Rake実装
initializeとrunを見てみると。
Rake::Applicationのrunは
run
Rake アプリケーションを実行します。
このメソッドは以下の 3 ステップを実行します。
Rake::Applicationの実装は以下。
rake/application.rb at master · ruby/rake · GitHub
initializeは単に初期化しているだけっぽいですね。上記の説明通り、initとload_rakefileとtop_levelのメソッドが呼ばれています。
capistranoのinitialize
capiのinitializeではcapfileから、謎にcapfile Capfile capfile.rb Capfile.rbの4つの文字の配列を作ってから、capfileメソッドの戻り値を追加しています。
capfileは
def capfile File.expand_path(File.join(File.dirname(__FILE__), "..", "Capfile")) end
これも難しい。File.dirname(FILE)は現在のファイルのディレクトリの相対パスを返す。それを..とCapfileで連結する。(join)
最後にexpand_pathで相対パスを出す。つまりこれは1つ上の階層のCapfileを返すメソッドになっている。
capistranoのrun
まだまだピンと来ないのでrunを見てみよう。
handle_optionをオーバーライドしている。
Rake::applicationではここで呼ばれてる。
# Initialize the command line parameters and app name. def init(app_name='rake') standard_exception_handling do @name = app_name args = handle_options collect_command_line_tasks(args) end end
def handle_options options.rakelib = ["rakelib"] options.trace_output = $stderr OptionParser.new do |opts| opts.banner = "See full documentation at http://capistranorb.com/." opts.separator "" opts.separator "Install capistrano in a project:" opts.separator " bundle exec cap install [STAGES=qa,staging,production,...]" opts.separator "" opts.separator "Show available tasks:" opts.separator " bundle exec cap -T" opts.separator "" opts.separator "Invoke (or simulate invoking) a task:" opts.separator " bundle exec cap [--dry-run] STAGE TASK" opts.separator "" opts.separator "Advanced options:" opts.on_tail("-h", "--help", "-H", "Display this help message.") do puts opts exit end standard_rake_options.each { |args| opts.on(*args) } opts.environment("RAKEOPT") end.parse! end
OptionParserはじめまして。きっと引数を解釈してくれる何かであろう。
class OptionParser (Ruby 2.1.0)
bannarとseparator。
banner -> String サマリの最初に表示される文字列を返します。
separator(sep) -> () サマリにオプションを区切るための文字列 sep を挿入します。 オプションにいくつかの種類がある場合に、サマリがわかりやすくなります。 サマリには on メソッドを呼んだ順にオプションが表示されるので、区切りを挿入したい ところでこのメソッドを呼びます。
サマリがどうやって見えてくるか分かりませんが、ここでつけておくのでしょう。
on_tail(*arg, &block) -> self オプションを取り扱うためのブロックを自身の持つリストの最後に登録します。 --version や --help の説明をサマリの最後に表示したい時に便利です。
最後にon_tail
次にstandard_rake_optionsに、これらのoptionを登録する。なるほど。
sort_optionでオプションを追加してますね。
version以下5つのメソッドはオプション追加のためにありますね。
例えばHostFileter
def hostfilter ["--hosts HOSTS", "-z", "Run SSH commands only on matching hosts", lambda do |value| Configuration.env.add_cmdline_filter(:host, value) end] end
--hostでHOSTを受け付けます。Configurationのほうを次は見ていけば良さそう。
おわりに
今回はcapコマンド実行後にオプションがどう解釈するかを追っていきました。rakeがよく分かってないとダメですね。あと実際にはdeploy.rb内のタスクが呼ばれるのですが、rake taskがどう作られるかもここでは分かりませんでした。実際にはCapfileで作られるはずなんですが、capfileはlib以下の.rakeファイルしか読み込んでないので、別の場所でconfig以下のファイル群を読み取る場所があるはず。
次はcapistrano/lib/capistrano/configuration.rbを見ていきます!