ツナワタリマイライフ

日常ネタから技術ネタ、音楽ネタまで何でも書きます。

capistranoソースコードリーディング bin編

はじめに

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を見ていきます!