イフブロ

イフブロ

インフラエンジニアのブログ

Capistrano: execute / captureの使い方(ハマったよ)

Capistraのexecuteとcaptureについて 仕様が明確になったので綴ります。

結論

executeやcaptureを使う時はコマンド部分と、その他を分けましょう。
まぁわかりづらいので、(<シンボル> , "args")で書くのがお作法的に良さそう。

例)
◯ execute(:echo, "test")
◯ execute("echo", "test")
✕ execute("echo test")

カッコの有無は、Rubyによると引数が無い時はわざわざつけない。引数がある時はつけよう。(だったかな) 位なのでつけておいた方がくくりがわかりやすいかも?

背景

実行コマンドによって動き方が違うかった事を不審に思った。

例えば

  • withinで括ると、本来指定したフォルダがカレントフォルダで動くはずなのに動かないことがあった。
  • default_envを設定しているのに、効いていない。

原因

第一引数と、第二引数でコマンド部分をわけないと、色々なオプションが効かない。 それは、capistranoの実装がそうなってる。

例題

デフォルトのRuby(2.2.3)を自分で上書きして、違うバージョンのRuby(2.3.0)を使う。

# :default_envをセットすると実行時にkey=valueを環境変数に入れてくれる。
# $PATHには元々別のRuby(2.2.3)が通っている。今回はそれを上書き(2.3.0に)したかった。  
set :default_env, {
        path: "/opt/user-ruby/bin:$PATH"
}

をセットした状態で、

namespace : setup do
  task :test do
    run_locally do
      puts "Ruby -v :" + capture("ruby -v")
      puts "Ruby -v :" + capture(:ruby, "-v")
    end
  end
end

を実行するとなんと、

** Execute setup:test
Ruby -v :ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-linux]
Ruby -v :ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]

結果が違う。 どうやら、コマンド部分と引数部分にわけない場合にはdefault_envを使って暗黙的にバックグラウンドで export key=valueをコマンドに足してくれるんだけど、そうじゃない場合は、to_sで返しちゃう。

この感じだと、withinとかwithとか効かなかった全部こいつのせい…。 シンボルで書くべきか、コマンドで書くべきか迷って、コマンドに寄せた時に、引数部分とわけずに書いてたのでハマってた様子。

# こんな感じでコマンドの変換をしている。
# 第一引数をコマンドだけにしないと、mapに含まれずに処理される
    def to_command
      return command.to_s unless should_map?
      within do
        umask do
          with do
            user do
              in_background do
                group do
                  to_s
                end
              end
            end
          end
        end
      end
    end

ココで事前にロード済のコマンドmapに存在するかしないかを見ている。

ココ で実際にSSHコマンドが出て行く。と思われる。