mirror of
https://github.com/capistrano/capistrano
synced 2023-03-27 23:21:18 -04:00
Merge pull request #383 from mpapis/feature/improved_command_logging_for_parallel
Improve parallel commands logging
This commit is contained in:
commit
7b585024c2
5 changed files with 60 additions and 31 deletions
|
@ -17,7 +17,7 @@ module Capistrano
|
||||||
include Enumerable
|
include Enumerable
|
||||||
|
|
||||||
class Branch
|
class Branch
|
||||||
attr_accessor :command, :callback
|
attr_accessor :command, :callback, :condition
|
||||||
attr_reader :options
|
attr_reader :options
|
||||||
|
|
||||||
def initialize(command, options, callback)
|
def initialize(command, options, callback)
|
||||||
|
@ -43,14 +43,17 @@ module Capistrano
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s(parallel=false)
|
||||||
|
if parallel && @condition
|
||||||
|
"#{condition.inspect} :: #{command.inspect}"
|
||||||
|
else
|
||||||
command.inspect
|
command.inspect
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class ConditionBranch < Branch
|
class ConditionBranch < Branch
|
||||||
attr_accessor :configuration
|
attr_accessor :configuration
|
||||||
attr_accessor :condition
|
|
||||||
|
|
||||||
class Evaluator
|
class Evaluator
|
||||||
attr_reader :configuration, :condition, :server
|
attr_reader :configuration, :condition, :server
|
||||||
|
@ -89,9 +92,12 @@ module Capistrano
|
||||||
def match(server)
|
def match(server)
|
||||||
Evaluator.new(configuration, condition, server).result
|
Evaluator.new(configuration, condition, server).result
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def to_s
|
class ElseBranch < Branch
|
||||||
"#{condition.inspect} :: #{command.inspect}"
|
def initialize(command, options, callback)
|
||||||
|
@condition = "else"
|
||||||
|
super(command, options, callback)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -106,7 +112,7 @@ module Capistrano
|
||||||
end
|
end
|
||||||
|
|
||||||
def else(command, &block)
|
def else(command, &block)
|
||||||
@fallback = Branch.new(command, {}, block)
|
@fallback = ElseBranch.new(command, {}, block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def branches_for(server)
|
def branches_for(server)
|
||||||
|
|
|
@ -159,12 +159,26 @@ module Capistrano
|
||||||
# use, but should instead be called indirectly, via #run or #parallel,
|
# use, but should instead be called indirectly, via #run or #parallel,
|
||||||
# or #invoke_command.
|
# or #invoke_command.
|
||||||
def run_tree(tree, options={}) #:nodoc:
|
def run_tree(tree, options={}) #:nodoc:
|
||||||
if tree.branches.empty? && tree.fallback
|
options = add_default_command_options(options)
|
||||||
logger.debug "executing #{tree.fallback}" unless options[:silent]
|
|
||||||
elsif tree.branches.any?
|
if tree.branches.any? || tree.fallback
|
||||||
|
_, servers = filter_servers(options)
|
||||||
|
branches = servers.map{|server| tree.branches_for(server)}.compact
|
||||||
|
case branches.size
|
||||||
|
when 0
|
||||||
|
branches = tree.branches.dup + [tree.fallback]
|
||||||
|
case branches.size
|
||||||
|
when 1
|
||||||
|
logger.debug "no servers for #{branches.first}"
|
||||||
|
else
|
||||||
|
logger.debug "no servers for commands"
|
||||||
|
branches.each{ |branch| logger.trace "-> #{branch.to_s(true)}" }
|
||||||
|
end
|
||||||
|
when 1
|
||||||
|
logger.debug "executing #{branches.first}" unless options[:silent]
|
||||||
|
else
|
||||||
logger.debug "executing multiple commands in parallel"
|
logger.debug "executing multiple commands in parallel"
|
||||||
tree.each do |branch|
|
branches.each{ |branch| logger.trace "-> #{branch.to_s(true)}" }
|
||||||
logger.trace "-> #{branch}"
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise ArgumentError, "attempt to execute without specifying a command"
|
raise ArgumentError, "attempt to execute without specifying a command"
|
||||||
|
@ -172,8 +186,6 @@ module Capistrano
|
||||||
|
|
||||||
return if dry_run || (debug && continue_execution(tree) == false)
|
return if dry_run || (debug && continue_execution(tree) == false)
|
||||||
|
|
||||||
options = add_default_command_options(options)
|
|
||||||
|
|
||||||
tree.each do |branch|
|
tree.each do |branch|
|
||||||
if branch.command.include?(sudo)
|
if branch.command.include?(sudo)
|
||||||
branch.callback = sudo_behavior_callback(branch.callback)
|
branch.callback = sudo_behavior_callback(branch.callback)
|
||||||
|
|
|
@ -147,37 +147,43 @@ module Capistrano
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Determines the set of servers within the current task's scope and
|
# Determines the set of servers within the current task's scope
|
||||||
# establishes connections to them, and then yields that list of
|
def filter_servers(options={})
|
||||||
# servers.
|
|
||||||
def execute_on_servers(options={})
|
|
||||||
raise ArgumentError, "expected a block" unless block_given?
|
|
||||||
|
|
||||||
if task = current_task
|
if task = current_task
|
||||||
servers = find_servers_for_task(task, options)
|
servers = find_servers_for_task(task, options)
|
||||||
|
|
||||||
if servers.empty?
|
if servers.empty?
|
||||||
if ENV['HOSTFILTER'] || task.options.merge(options)[:on_no_matching_servers] == :continue
|
if ENV['HOSTFILTER'] || task.options.merge(options)[:on_no_matching_servers] == :continue
|
||||||
logger.info "skipping `#{task.fully_qualified_name}' because no servers matched"
|
logger.info "skipping `#{task.fully_qualified_name}' because no servers matched"
|
||||||
return
|
|
||||||
else
|
else
|
||||||
|
unless dry_run
|
||||||
raise Capistrano::NoMatchingServersError, "`#{task.fully_qualified_name}' is only run for servers matching #{task.options.inspect}, but no servers matched"
|
raise Capistrano::NoMatchingServersError, "`#{task.fully_qualified_name}' is only run for servers matching #{task.options.inspect}, but no servers matched"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if task.continue_on_error?
|
if task.continue_on_error?
|
||||||
servers.delete_if { |s| has_failed?(s) }
|
servers.delete_if { |s| has_failed?(s) }
|
||||||
return if servers.empty?
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
servers = find_servers(options)
|
servers = find_servers(options)
|
||||||
if servers.empty?
|
if servers.empty? && !dry_run
|
||||||
raise Capistrano::NoMatchingServersError, "no servers found to match #{options.inspect}" if options[:on_no_matching_servers] != :continue
|
raise Capistrano::NoMatchingServersError, "no servers found to match #{options.inspect}" if options[:on_no_matching_servers] != :continue
|
||||||
return
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
servers = [servers.first] if options[:once]
|
servers = [servers.first] if options[:once]
|
||||||
|
[task, servers.compact]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Determines the set of servers within the current task's scope and
|
||||||
|
# establishes connections to them, and then yields that list of
|
||||||
|
# servers.
|
||||||
|
def execute_on_servers(options={})
|
||||||
|
raise ArgumentError, "expected a block" unless block_given?
|
||||||
|
|
||||||
|
task, servers = filter_servers(options)
|
||||||
|
return if servers.empty?
|
||||||
logger.trace "servers: #{servers.map { |s| s.host }.inspect}"
|
logger.trace "servers: #{servers.map { |s| s.host }.inspect}"
|
||||||
|
|
||||||
max_hosts = (options[:max_hosts] || (task && task.max_hosts) || servers.size).to_i
|
max_hosts = (options[:max_hosts] || (task && task.max_hosts) || servers.size).to_i
|
||||||
|
|
|
@ -27,6 +27,10 @@ class ConfigurationActionsInvocationTest < Test::Unit::TestCase
|
||||||
@options.fetch(*args)
|
@options.fetch(*args)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def filter_servers(options = {})
|
||||||
|
[nil, @servers]
|
||||||
|
end
|
||||||
|
|
||||||
def execute_on_servers(options = {})
|
def execute_on_servers(options = {})
|
||||||
yield @servers
|
yield @servers
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,7 @@ class ConfigurationConnectionsTest < Test::Unit::TestCase
|
||||||
class MockConfig
|
class MockConfig
|
||||||
attr_reader :original_initialize_called
|
attr_reader :original_initialize_called
|
||||||
attr_reader :values
|
attr_reader :values
|
||||||
|
attr_reader :dry_run
|
||||||
attr_accessor :current_task
|
attr_accessor :current_task
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue