Parent

Namespace

Included Modules

Class Index [+]

Quicksearch

Capistrano::Command

This class encapsulates a single command to be executed on a set of remote machines, in parallel.

Attributes

tree[R]
sessions[R]
options[R]

Public Class Methods

new(tree, sessions, options={}, &block) click to toggle source

Instantiates a new command object. The command must be a string containing the command to execute. sessions is an array of Net::SSH session instances, and options must be a hash containing any of the following keys:

  • logger: (optional), a Capistrano::Logger instance

  • data: (optional), a string to be sent to the command via it’s stdin

  • env: (optional), a string or hash to be interpreted as environment variables that should be defined for this command invocation.

     # File lib/capistrano/command.rb, line 146
146:     def initialize(tree, sessions, options={}, &block)
147:       if String === tree
148:         tree = Tree.new(nil) { |t| t.else(tree, &block) }
149:       elsif block
150:         raise ArgumentError, "block given with tree argument"
151:       end
152: 
153:       @tree = tree
154:       @sessions = sessions
155:       @options = options
156:       @channels = open_channels
157:     end
process(tree, sessions, options={}) click to toggle source
     # File lib/capistrano/command.rb, line 133
133:     def self.process(tree, sessions, options={})
134:       new(tree, sessions, options).process!
135:     end

Public Instance Methods

process!() click to toggle source

Processes the command in parallel on all specified hosts. If the command fails (non-zero return code) on any of the hosts, this will raise a Capistrano::CommandError.

     # File lib/capistrano/command.rb, line 162
162:     def process!
163:       elapsed = Benchmark.realtime do
164:         loop do
165:           break unless process_iteration { @channels.any? { |ch| !ch[:closed] } }
166:         end
167:       end
168: 
169:       logger.trace "command finished in #{(elapsed * 1000).round}ms" if logger
170: 
171:       if (failed = @channels.select { |ch| ch[:status] != 0 }).any?
172:         commands = failed.inject({}) { |map, ch| (map[ch[:command]] ||= []) << ch[:server]; map }
173:         message = commands.map { |command, list| "#{command.inspect} on #{list.join(',')}" }.join("; ")
174:         error = CommandError.new("failed: #{message}")
175:         error.hosts = commands.values.flatten
176:         raise error
177:       end
178: 
179:       self
180:     end
stop!() click to toggle source

Force the command to stop processing, by closing all open channels associated with this command.

     # File lib/capistrano/command.rb, line 184
184:     def stop!
185:       @channels.each do |ch|
186:         ch.close unless ch[:closed]
187:       end
188:     end

Private Instance Methods

environment() click to toggle source

prepare a space-separated sequence of variables assignments intended to be prepended to a command, so the shell sets the environment before running the command. i.e.: options[:env] = {‘PATH’ => ‘/opt/ruby/bin:$PATH’,

                       'TEST' => '( "quoted" )'}

environment returns: “env TEST=(\ "quoted"\ ) PATH=/opt/ruby/bin:$PATH“

     # File lib/capistrano/command.rb, line 277
277:       def environment
278:         return if options[:env].nil? || options[:env].empty?
279:         @environment ||= if String === options[:env]
280:             "env #{options[:env]}"
281:           else
282:             options[:env].inject("env") do |string, (name, value)|
283:               value = value.to_s.gsub(/[ "]/) { |m| "\\#{m}" }
284:               string << " #{name}=#{value}"
285:             end
286:           end
287:       end
logger() click to toggle source
     # File lib/capistrano/command.rb, line 192
192:       def logger
193:         options[:logger]
194:       end
open_channels() click to toggle source
     # File lib/capistrano/command.rb, line 196
196:       def open_channels
197:         sessions.map do |session|
198:           server = session.xserver
199:           tree.branches_for(server).map do |branch|
200:             session.open_channel do |channel|
201:               channel[:server] = server
202:               channel[:host] = server.host
203:               channel[:options] = options
204:               channel[:branch] = branch
205: 
206:               request_pty_if_necessary(channel) do |ch, success|
207:                 if success
208:                   logger.trace "executing command", ch[:server] if logger
209:                   cmd = replace_placeholders(channel[:branch].command, ch)
210: 
211:                   if options[:shell] == false
212:                     shell = nil
213:                   else
214:                     shell = "#{options[:shell] || "sh"} -c"
215:                     cmd = cmd.gsub(/'/) { |m| "'\\''" }
216:                     cmd = "'#{cmd}'"
217:                   end
218: 
219:                   command_line = [environment, shell, cmd].compact.join(" ")
220:                   ch[:command] = command_line
221: 
222:                   ch.exec(command_line)
223:                   ch.send_data(options[:data]) if options[:data]
224:                 else
225:                   # just log it, don't actually raise an exception, since the
226:                   # process method will see that the status is not zero and will
227:                   # raise an exception then.
228:                   logger.important "could not open channel", ch[:server] if logger
229:                   ch.close
230:                 end
231:               end
232: 
233:               channel.on_data do |ch, data|
234:                 ch[:branch].callback[ch, :out, data]
235:               end
236: 
237:               channel.on_extended_data do |ch, type, data|
238:                 ch[:branch].callback[ch, :err, data]
239:               end
240: 
241:               channel.on_request("exit-status") do |ch, data|
242:                 ch[:status] = data.read_long
243:               end
244: 
245:               channel.on_close do |ch|
246:                 ch[:closed] = true
247:               end
248:             end
249:           end
250:         end.flatten
251:       end
replace_placeholders(command, channel) click to toggle source
     # File lib/capistrano/command.rb, line 263
263:       def replace_placeholders(command, channel)
264:         roles = @tree.configuration && @tree.configuration.role_names_for_host(channel[:server])
265:         command = command.gsub(/\$CAPISTRANO:HOST\$/, channel[:host])
266:         command.gsub!(/\$CAPISTRANO:HOSTROLES\$/, roles.join(',')) if roles
267:         command
268:       end
request_pty_if_necessary(channel) click to toggle source
     # File lib/capistrano/command.rb, line 253
253:       def request_pty_if_necessary(channel)
254:         if options[:pty]
255:           channel.request_pty do |ch, success|
256:             yield ch, success
257:           end
258:         else
259:           yield channel, true
260:         end
261:       end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.