Skip to content

Commit 7caa6af

Browse files
committed
Don't run tasks if it depends on already invoked but failed task. Fixes ruby#189
1 parent 109dd0e commit 7caa6af

File tree

3 files changed

+53
-48
lines changed

3 files changed

+53
-48
lines changed

lib/rake/multi_task.rb

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,10 @@ module Rake
55
# parallel using Ruby threads.
66
#
77
class MultiTask < Task
8-
9-
# Same as invoke, but explicitly pass a call chain to detect
10-
# circular dependencies. This is largely copied from Rake::Task
11-
# but has been updated such that if multiple tasks depend on this
12-
# one in parallel, they will all fail if the first execution of
13-
# this task fails.
14-
def invoke_with_call_chain(task_args, invocation_chain)
15-
new_chain = Rake::InvocationChain.append(self, invocation_chain)
16-
@lock.synchronize do
17-
begin
18-
if @already_invoked
19-
if @invocation_exception
20-
if application.options.trace
21-
application.trace "** Previous invocation of #{name} failed #{format_trace_flags}"
22-
end
23-
raise @invocation_exception
24-
else
25-
return
26-
end
27-
end
28-
29-
if application.options.trace
30-
application.trace "** Invoke #{name} #{format_trace_flags}"
31-
end
32-
@already_invoked = true
33-
34-
invoke_prerequisites(task_args, new_chain)
35-
execute(task_args) if needed?
36-
rescue Exception => ex
37-
add_chain_to(ex, new_chain)
38-
@invocation_exception = ex
39-
raise
40-
end
41-
end
42-
end
43-
448
private
9+
4510
def invoke_prerequisites(task_args, invocation_chain) # :nodoc:
4611
invoke_prerequisites_concurrently(task_args, invocation_chain)
4712
end
4813
end
49-
5014
end

lib/rake/task.rb

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ def initialize(task_name, app)
103103
@scope = app.current_scope
104104
@arg_names = nil
105105
@locations = []
106+
@invocation_exception = nil
106107
end
107108

108109
# Enhance a task with prerequisites or actions. Returns self.
@@ -183,20 +184,39 @@ def invoke(*args)
183184

184185
# Same as invoke, but explicitly pass a call chain to detect
185186
# circular dependencies.
186-
def invoke_with_call_chain(task_args, invocation_chain) # :nodoc:
187-
new_chain = InvocationChain.append(self, invocation_chain)
187+
#
188+
# If multiple tasks depend on this
189+
# one in parallel, they will all fail if the first execution of
190+
# this task fails.
191+
def invoke_with_call_chain(task_args, invocation_chain)
192+
new_chain = Rake::InvocationChain.append(self, invocation_chain)
188193
@lock.synchronize do
189-
if application.options.trace
190-
application.trace "** Invoke #{name} #{format_trace_flags}"
194+
begin
195+
if application.options.trace
196+
application.trace "** Invoke #{name} #{format_trace_flags}"
197+
end
198+
199+
if @already_invoked
200+
if @invocation_exception
201+
if application.options.trace
202+
application.trace "** Previous invocation of #{name} failed #{format_trace_flags}"
203+
end
204+
raise @invocation_exception
205+
else
206+
return
207+
end
208+
end
209+
210+
@already_invoked = true
211+
212+
invoke_prerequisites(task_args, new_chain)
213+
execute(task_args) if needed?
214+
rescue Exception => ex
215+
add_chain_to(ex, new_chain)
216+
@invocation_exception = ex
217+
raise ex
191218
end
192-
return if @already_invoked
193-
@already_invoked = true
194-
invoke_prerequisites(task_args, new_chain)
195-
execute(task_args) if needed?
196219
end
197-
rescue Exception => ex
198-
add_chain_to(ex, new_chain)
199-
raise ex
200220
end
201221
protected :invoke_with_call_chain
202222

test/test_rake_multi_task.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,25 @@ def test_cross_thread_prerequisite_failures
8383
Rake::Task[:b].invoke
8484
end
8585
end
86+
87+
def test_task_not_executed_if_dependant_task_failed_concurrently
88+
multitask :default => [:one, :two]
89+
90+
task :one do
91+
raise
92+
end
93+
94+
task_two_was_executed = false
95+
task :two => :one do
96+
task_two_was_executed = true
97+
end
98+
99+
begin
100+
Rake::Task[:default].invoke
101+
rescue RuntimeError
102+
ensure
103+
sleep 0.5
104+
assert !task_two_was_executed
105+
end
106+
end
86107
end

0 commit comments

Comments
 (0)