<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -9,17 +9,27 @@ module Capistrano
     include Processable
 
     class Tree
+      attr_reader :configuration
       attr_reader :branches
+      attr_reader :fallback
+
+      include Enumerable
 
       class Branch
         attr_accessor :command, :callback
+        attr_reader :options
 
-        def initialize(command, callback)
+        def initialize(command, options, callback)
           @command = command.strip.gsub(/\r?\n/, &quot;\\\n&quot;)
           @callback = callback || Capistrano::Configuration.default_io_proc
+          @options = options
           @skip = false
         end
 
+        def last?
+          options[:last]
+        end
+
         def skip?
           @skip
         end
@@ -37,38 +47,83 @@ module Capistrano
         end
       end
 
-      class PatternBranch &lt; Branch
-        attr_accessor :pattern
+      class ConditionBranch &lt; Branch
+        attr_accessor :configuration
+        attr_accessor :condition
+
+        class Evaluator
+          attr_reader :configuration, :condition, :server
+
+          def initialize(config, condition, server)
+            @configuration = config
+            @condition = condition
+            @server = server
+          end
+
+          def in?(role)
+            configuration.roles[role].include?(server)
+          end
+
+          def result
+            eval(condition, binding)
+          end
+
+          def method_missing(sym, *args, &amp;block)
+            if server.respond_to?(sym)
+              server.send(sym, *args, &amp;block)
+            elsif configuration.respond_to?(sym)
+              configuration.send(sym, *args, &amp;block)
+            else
+              super
+            end
+          end
+        end
 
-        def initialize(pattern, command, callback)
-          @pattern = pattern
-          super(command, callback)
+        def initialize(configuration, condition, command, options, callback)
+          @configuration = configuration
+          @condition = condition
+          super(command, options, callback)
         end
 
         def match(server)
-          pattern === server.host
+          Evaluator.new(configuration, condition, server).result
         end
 
         def to_s
-          &quot;#{pattern.inspect} :: #{command.inspect}&quot;
+          &quot;#{condition.inspect} :: #{command.inspect}&quot;
         end
       end
 
-      def initialize
+      def initialize(config)
+        @configuration = config
         @branches = []
         yield self if block_given?
       end
 
-      def if(pattern, command, &amp;block)
-        branches &lt;&lt; PatternBranch.new(pattern, command, block)
+      def when(condition, command, options={}, &amp;block)
+        branches &lt;&lt; ConditionBranch.new(configuration, condition, command, options, block)
       end
 
       def else(command, &amp;block)
-        branches &lt;&lt; Branch.new(command, block)
+        @fallback = Branch.new(command, {}, block)
       end
 
-      def branch_for(server)
-        branches.detect { |branch| branch.match(server) }
+      def branches_for(server)
+        seen_last = false
+        matches = branches.select do |branch|
+          success = !seen_last &amp;&amp; !branch.skip? &amp;&amp; branch.match(server)
+          seen_last = success &amp;&amp; branch.last?
+          success
+        end
+
+        matches &lt;&lt; fallback if matches.empty? &amp;&amp; fallback
+        return matches
+      end
+
+      def each
+        branches.each { |branch| yield branch }
+        yield fallback if fallback
+        return self
       end
     end
 
@@ -131,58 +186,57 @@ module Capistrano
       def open_channels
         sessions.map do |session|
           server = session.xserver
-          branch = tree.branch_for(server)
-          next if branch.skip?
-
-          session.open_channel do |channel|
-            channel[:server] = server
-            channel[:host] = server.host
-            channel[:options] = options
-            channel[:branch] = branch
-
-            request_pty_if_necessary(channel) do |ch, success|
-              if success
-                logger.trace &quot;executing command&quot;, ch[:server] if logger
-                cmd = replace_placeholders(channel[:branch].command, ch)
-
-                if options[:shell] == false
-                  shell = nil
+          tree.branches_for(server).map do |branch|
+            session.open_channel do |channel|
+              channel[:server] = server
+              channel[:host] = server.host
+              channel[:options] = options
+              channel[:branch] = branch
+
+              request_pty_if_necessary(channel) do |ch, success|
+                if success
+                  logger.trace &quot;executing command&quot;, ch[:server] if logger
+                  cmd = replace_placeholders(channel[:branch].command, ch)
+
+                  if options[:shell] == false
+                    shell = nil
+                  else
+                    shell = &quot;#{options[:shell] || &quot;sh&quot;} -c&quot;
+                    cmd = cmd.gsub(/[$\\`&quot;]/) { |m| &quot;\\#{m}&quot; }
+                    cmd = &quot;\&quot;#{cmd}\&quot;&quot;
+                  end
+
+                  command_line = [environment, shell, cmd].compact.join(&quot; &quot;)
+
+                  ch.exec(command_line)
+                  ch.send_data(options[:data]) if options[:data]
                 else
-                  shell = &quot;#{options[:shell] || &quot;sh&quot;} -c&quot;
-                  cmd = cmd.gsub(/[$\\`&quot;]/) { |m| &quot;\\#{m}&quot; }
-                  cmd = &quot;\&quot;#{cmd}\&quot;&quot;
+                  # just log it, don't actually raise an exception, since the
+                  # process method will see that the status is not zero and will
+                  # raise an exception then.
+                  logger.important &quot;could not open channel&quot;, ch[:server] if logger
+                  ch.close
                 end
-
-                command_line = [environment, shell, cmd].compact.join(&quot; &quot;)
-
-                ch.exec(command_line)
-                ch.send_data(options[:data]) if options[:data]
-              else
-                # just log it, don't actually raise an exception, since the
-                # process method will see that the status is not zero and will
-                # raise an exception then.
-                logger.important &quot;could not open channel&quot;, ch[:server] if logger
-                ch.close
               end
-            end
 
-            channel.on_data do |ch, data|
-              ch[:branch].callback[ch, :out, data]
-            end
+              channel.on_data do |ch, data|
+                ch[:branch].callback[ch, :out, data]
+              end
 
-            channel.on_extended_data do |ch, type, data|
-              ch[:branch].callback[ch, :err, data]
-            end
+              channel.on_extended_data do |ch, type, data|
+                ch[:branch].callback[ch, :err, data]
+              end
 
-            channel.on_request(&quot;exit-status&quot;) do |ch, data|
-              ch[:status] = data.read_long
-            end
+              channel.on_request(&quot;exit-status&quot;) do |ch, data|
+                ch[:status] = data.read_long
+              end
 
-            channel.on_close do |ch|
-              ch[:closed] = true
+              channel.on_close do |ch|
+                ch[:closed] = true
+              end
             end
           end
-        end.compact
+        end.flatten
       end
 
       def request_pty_if_necessary(channel)</diff>
      <filename>lib/capistrano/command.rb</filename>
    </modified>
    <modified>
      <diff>@@ -28,7 +28,7 @@ module Capistrano
 
         def parallel(options={})
           raise ArgumentError, &quot;parallel() requires a block&quot; unless block_given?
-          tree = Command::Tree.new { |t| yield t }
+          tree = Command::Tree.new(self) { |t| yield t }
           run_tree(tree)
         end
 
@@ -50,7 +50,7 @@ module Capistrano
         # stdout), and the data that was received.
         def run(cmd, options={}, &amp;block)
           block ||= self.class.default_io_proc
-          tree = Command::Tree.new { |t| t.else(cmd, block) }
+          tree = Command::Tree.new(self) { |t| t.else(cmd, block) }
           run_tree(tree, options)
         end
 
@@ -59,7 +59,7 @@ module Capistrano
             logger.debug &quot;executing #{tree.branches.first}&quot;
           else
             logger.debug &quot;executing multiple commands in parallel&quot;
-            tree.branches.each do |branch|
+            tree.each do |branch|
               logger.trace &quot;-&gt; #{branch}&quot;
             end
           end
@@ -169,8 +169,8 @@ module Capistrano
           if tree.branches.length == 1
             continue_execution_for_branch(tree.branches.first)
           else
-            tree.branches.each { |branch| branch.skip! unless continue_execution_for_branch(branch) }
-            tree.branches.any? { |branch| !branch.skip? }
+            tree.each { |branch| branch.skip! unless continue_execution_for_branch(branch) }
+            tree.any? { |branch| !branch.skip? }
           end
         end
 </diff>
      <filename>lib/capistrano/configuration/actions/invocation.rb</filename>
    </modified>
    <modified>
      <diff>@@ -38,6 +38,10 @@ module Capistrano
       @static_servers.clear
     end
 
+    def include?(server)
+      servers.include?(server)
+    end
+
     protected
 
     # This is the combination of a block, a hash of options, and a cached value.</diff>
      <filename>lib/capistrano/role.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>c70fcd595e68f576002ba0b7d75e49872fba2447</id>
    </parent>
  </parents>
  <author>
    <name>Jamis Buck</name>
    <email>jamis@37signals.com</email>
  </author>
  <url>http://github.com/jamis/capistrano/commit/c70e595c36ae7cd3f63c1212ddf566efe50e2b5d</url>
  <id>c70e595c36ae7cd3f63c1212ddf566efe50e2b5d</id>
  <committed-date>2008-08-21T09:59:35-07:00</committed-date>
  <authored-date>2008-08-21T09:59:35-07:00</authored-date>
  <message>replace condition#if with when and made it support multiple matches by default.</message>
  <tree>37ae7ee59ba204ea8466f711c2071a58442adf67</tree>
  <committer>
    <name>Jamis Buck</name>
    <email>jamis@37signals.com</email>
  </committer>
</commit>
