arake 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/arake.rb +104 -30
- data/spec/arake_spec.rb +397 -0
- metadata +3 -2
data/lib/arake.rb
CHANGED
@@ -8,56 +8,69 @@ require 'watchr'
|
|
8
8
|
|
9
9
|
module ARake
|
10
10
|
class Application
|
11
|
-
attr_accessor :accumulated_args
|
12
|
-
|
13
11
|
def initialize(top_level_self)
|
12
|
+
@_rake = nil
|
13
|
+
@_watchr = nil
|
14
|
+
@_watchr_script = nil
|
14
15
|
@top_level_self = top_level_self
|
15
|
-
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
+
def run
|
19
|
+
original_Rake_application = Rake.application
|
20
|
+
begin
|
21
|
+
Rake.application = rake
|
22
|
+
|
23
|
+
Rake.application.run
|
24
|
+
watchr.run
|
25
|
+
ensure
|
26
|
+
Rake.application = original_Rake_application
|
27
|
+
end
|
18
28
|
end
|
19
29
|
|
20
|
-
|
21
|
-
a = self
|
22
|
-
(class << @top_level_self; self; end).class_eval do
|
23
|
-
include Rake::TaskManager
|
30
|
+
# Misc.
|
24
31
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
def rake
|
33
|
+
@_rake ||= CustomRakeAppliation.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def rake_tasks
|
37
|
+
rake.tasks
|
31
38
|
end
|
32
39
|
|
33
|
-
def
|
34
|
-
@
|
40
|
+
def watchr
|
41
|
+
@_watchr ||= _create_custom_watchr
|
35
42
|
end
|
36
43
|
|
37
|
-
def
|
44
|
+
def _create_custom_watchr
|
45
|
+
Watchr::Controller.new(watchr_script, Watchr.handler.new)
|
46
|
+
end
|
47
|
+
|
48
|
+
def watchr_rules
|
49
|
+
watchr_script.rules
|
50
|
+
end
|
51
|
+
|
52
|
+
def watchr_script
|
53
|
+
@_watchr_script ||= _create_custom_watchr_script
|
54
|
+
end
|
55
|
+
|
56
|
+
def _create_custom_watchr_script
|
38
57
|
a = self
|
39
58
|
s = Watchr::Script.new
|
40
59
|
(class << s; self; end).class_eval do
|
41
60
|
define_method :parse! do
|
42
61
|
@ec.instance_eval do
|
43
|
-
a.
|
44
|
-
|
45
|
-
watch "^#{Regexp.escape
|
62
|
+
a.rake_tasks.each do |t|
|
63
|
+
t.prerequisites.each do |p|
|
64
|
+
watch "^#{Regexp.escape p}$" do
|
65
|
+
a.rake.reenable_all_tasks
|
66
|
+
a.rake.invoke_root_tasks_of(t)
|
67
|
+
end
|
46
68
|
end
|
47
69
|
end
|
48
70
|
end
|
49
71
|
end
|
50
72
|
end
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
def load_rakefiles
|
55
|
-
CustomRakeAppliation.new.run
|
56
|
-
end
|
57
|
-
|
58
|
-
def run
|
59
|
-
load_rakefiles
|
60
|
-
create_custom_watchr.run
|
73
|
+
s
|
61
74
|
end
|
62
75
|
end
|
63
76
|
|
@@ -70,6 +83,67 @@ module ARake
|
|
70
83
|
# run whenever dependents are updated.
|
71
84
|
end
|
72
85
|
end
|
86
|
+
|
87
|
+
def reenable_all_tasks
|
88
|
+
tasks.each do |t|
|
89
|
+
t.reenable
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def invoke_root_tasks_of(task)
|
94
|
+
root_tasks_of(task).each do |t|
|
95
|
+
t.invoke
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def root_tasks_of(task)
|
100
|
+
Misc.root_tasks_of task, tasks
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
module Misc
|
105
|
+
def self.root_tasks_of(task, tasks)
|
106
|
+
tree_from_task(task, pt_table_from_tasks(tasks)).leaves
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.pt_table_from_tasks(tasks) # prerequisite-to-target table
|
110
|
+
h = Hash.new {|h, name| h[name] = []}
|
111
|
+
tasks.each do |target_task|
|
112
|
+
target_task.prerequisites.each do |prerequisite|
|
113
|
+
h[prerequisite.to_s].push target_task
|
114
|
+
end
|
115
|
+
end
|
116
|
+
h
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.tree_from_task(task, table = Hash.new {|h, key| h[key] = []})
|
120
|
+
t = Tree.new
|
121
|
+
t.value = task
|
122
|
+
t.subtrees = table[task.to_s].map {|x| tree_from_task x, table}
|
123
|
+
t
|
124
|
+
end
|
125
|
+
|
126
|
+
class Tree
|
127
|
+
attr_accessor :value
|
128
|
+
attr_accessor :subtrees
|
129
|
+
|
130
|
+
def initialize(value = nil, subtrees = [])
|
131
|
+
@value = value
|
132
|
+
@subtrees = subtrees
|
133
|
+
end
|
134
|
+
|
135
|
+
def leaf?
|
136
|
+
subtrees.empty?
|
137
|
+
end
|
138
|
+
|
139
|
+
def leaves
|
140
|
+
if leaf?
|
141
|
+
[value]
|
142
|
+
else
|
143
|
+
subtrees.map{|s| s.leaves}.inject :+
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
73
147
|
end
|
74
148
|
end
|
75
149
|
|
data/spec/arake_spec.rb
ADDED
@@ -0,0 +1,397 @@
|
|
1
|
+
#!/usr/bin/env rspec
|
2
|
+
|
3
|
+
require 'arake'
|
4
|
+
require 'stringio'
|
5
|
+
require 'tmpdir'
|
6
|
+
|
7
|
+
# $ mount
|
8
|
+
# /dev/disk0s2 on / (hfs, local, journaled)
|
9
|
+
# devfs on /dev (devfs, local)
|
10
|
+
# fdesc on /dev (fdesc, union)
|
11
|
+
# map -hosts on /net (autofs, automounted)
|
12
|
+
# map auto_home on /home (autofs, automounted)
|
13
|
+
#
|
14
|
+
# $ ruby -e 'p (Dir.glob "/a", File::FNM_CASEFOLD)'
|
15
|
+
# -e:1:in `glob': invalid byte sequence in US-ASCII (ArgumentError)
|
16
|
+
# from -e:1:in `<main>'
|
17
|
+
#
|
18
|
+
# $ ruby --version
|
19
|
+
# ruby 1.9.2p180 (2011-02-18 revision 30909) [i386-darwin9.8.0]
|
20
|
+
File::FNM_CASEFOLD = 0
|
21
|
+
|
22
|
+
def with_argv(*args, &block)
|
23
|
+
original_ARGV = ARGV.dup
|
24
|
+
|
25
|
+
ARGV.clear
|
26
|
+
ARGV.push *args
|
27
|
+
|
28
|
+
block.call
|
29
|
+
|
30
|
+
ARGV.clear
|
31
|
+
ARGV.push *original_ARGV
|
32
|
+
end
|
33
|
+
|
34
|
+
def with_rakefile(rakefile_content, &block)
|
35
|
+
Dir.mktmpdir do |d|
|
36
|
+
rakefile = "#{d}/Rakefile"
|
37
|
+
File.open rakefile, 'w' do |io|
|
38
|
+
io.write rakefile_content
|
39
|
+
end
|
40
|
+
with_argv *['-f', rakefile] do
|
41
|
+
block.call
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def with_rake_application(rake_application, &block)
|
47
|
+
original_Rake_application = Rake.application
|
48
|
+
begin
|
49
|
+
Rake.application = rake_application
|
50
|
+
block.call
|
51
|
+
ensure
|
52
|
+
Rake.application = original_Rake_application
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def with_rake(rake_application, rakefile_content, &block)
|
57
|
+
with_rakefile rakefile_content do
|
58
|
+
with_rake_application rake_application do
|
59
|
+
block.call
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def redirect(stdout = $stdout, &block)
|
65
|
+
_stdout = $stdout
|
66
|
+
begin
|
67
|
+
$stdout = stdout
|
68
|
+
block.call
|
69
|
+
ensure
|
70
|
+
$stdout = _stdout
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
top_level_self = self
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
describe ARake::CustomRakeAppliation do
|
80
|
+
it 'should read rakefiles but should not run any specified targets' do
|
81
|
+
rakefile_content = <<-"END"
|
82
|
+
p 'outer#{self.object_id}'
|
83
|
+
task :default do
|
84
|
+
p 'inner#{self.object_id}'
|
85
|
+
end
|
86
|
+
END
|
87
|
+
with_rake ARake::CustomRakeAppliation.new, rakefile_content do
|
88
|
+
s = String.new
|
89
|
+
redirect (StringIO.new s) do
|
90
|
+
Rake.application.run
|
91
|
+
end
|
92
|
+
|
93
|
+
(s.index "outer#{self.object_id}").should_not be_nil
|
94
|
+
(s.index "inner#{self.object_id}").should be_nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
describe ARake::Application do
|
103
|
+
def re(s)
|
104
|
+
"^#{Regexp.escape s}$"
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should not affect the default Rake.application' do
|
108
|
+
oa = Rake.application
|
109
|
+
a = ARake::Application.new top_level_self
|
110
|
+
with_rake_application a.rake do
|
111
|
+
oa.tasks.should be_empty
|
112
|
+
a.rake_tasks.should be_empty
|
113
|
+
|
114
|
+
block = Proc.new {}
|
115
|
+
top_level_self.instance_eval do
|
116
|
+
task 'bar1'
|
117
|
+
task 'bar2'
|
118
|
+
task 'baz1'
|
119
|
+
task 'baz2'
|
120
|
+
task 'foo1' => ['bar1', 'baz1'], &block
|
121
|
+
task 'foo2' => ['bar2', 'baz2'], &block
|
122
|
+
end
|
123
|
+
|
124
|
+
oa.tasks.should be_empty
|
125
|
+
a.rake_tasks.should_not be_empty
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should be able to refer tasks' do
|
130
|
+
a = ARake::Application.new top_level_self
|
131
|
+
with_rake_application a.rake do
|
132
|
+
a.rake_tasks.should be_empty
|
133
|
+
|
134
|
+
block = Proc.new {}
|
135
|
+
top_level_self.instance_eval do
|
136
|
+
task 'bar1'
|
137
|
+
task 'bar2'
|
138
|
+
task 'baz1'
|
139
|
+
task 'baz2'
|
140
|
+
task 'foo1' => ['bar1', 'baz1'], &block
|
141
|
+
task 'foo2' => ['bar2', 'baz2'], &block
|
142
|
+
end
|
143
|
+
|
144
|
+
a.rake_tasks.should_not be_empty
|
145
|
+
a.rake_tasks[-2].to_s.should eql 'foo1'
|
146
|
+
a.rake_tasks[-2].prerequisites.should eql ['bar1', 'baz1']
|
147
|
+
a.rake_tasks[-2].actions.should eql [block]
|
148
|
+
a.rake_tasks[-1].to_s.should eql 'foo2'
|
149
|
+
a.rake_tasks[-1].prerequisites.should eql ['bar2', 'baz2']
|
150
|
+
a.rake_tasks[-1].actions.should eql [block]
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should define a watch rule for each dependent' do
|
155
|
+
a = ARake::Application.new top_level_self
|
156
|
+
with_rake_application a.rake do
|
157
|
+
a.rake_tasks.should be_empty
|
158
|
+
a.watchr_rules.should be_empty
|
159
|
+
|
160
|
+
block = Proc.new {}
|
161
|
+
top_level_self.instance_eval do
|
162
|
+
task 'bar1'
|
163
|
+
task 'bar2'
|
164
|
+
task 'baz1'
|
165
|
+
task 'baz2'
|
166
|
+
task 'foo1' => ['bar1', 'baz1'], &block
|
167
|
+
task 'foo2' => ['bar2', 'baz2'], &block
|
168
|
+
end
|
169
|
+
a.watchr_script.parse!
|
170
|
+
|
171
|
+
a.rake_tasks.should_not be_empty
|
172
|
+
a.watchr_rules.should_not be_empty
|
173
|
+
a.watchr_rules[0].pattern.should eql re('bar1')
|
174
|
+
a.watchr_rules[1].pattern.should eql re('baz1')
|
175
|
+
a.watchr_rules[2].pattern.should eql re('bar2')
|
176
|
+
a.watchr_rules[3].pattern.should eql re('baz2')
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should invoke a rake task with proper parameters' do
|
181
|
+
a = ARake::Application.new top_level_self
|
182
|
+
with_rake_application a.rake do
|
183
|
+
passed_task = nil
|
184
|
+
block = Proc.new {|task| passed_task = task}
|
185
|
+
top_level_self.instance_eval do
|
186
|
+
task 'bar'
|
187
|
+
task 'foo' => 'bar', &block
|
188
|
+
end
|
189
|
+
a.watchr_script.parse!
|
190
|
+
r = a.watchr_rules[0]
|
191
|
+
|
192
|
+
r.pattern.should eql re('bar')
|
193
|
+
passed_task.should be_nil
|
194
|
+
|
195
|
+
r.action.call
|
196
|
+
t = a.rake_tasks[1]
|
197
|
+
|
198
|
+
t.to_s.should eql 'foo'
|
199
|
+
passed_task.should equal t
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'should execute rake tasks even if they are already executed before' do
|
204
|
+
a = ARake::Application.new top_level_self
|
205
|
+
with_rake_application a.rake do
|
206
|
+
call_count = 0
|
207
|
+
block = Proc.new {call_count += 1}
|
208
|
+
top_level_self.instance_eval do
|
209
|
+
task :dependent
|
210
|
+
task :target => :dependent, &block
|
211
|
+
end
|
212
|
+
a.watchr_script.parse!
|
213
|
+
r = a.watchr_rules[0]
|
214
|
+
|
215
|
+
r.pattern.should eql re(:dependent)
|
216
|
+
call_count.should eql 0
|
217
|
+
|
218
|
+
r.action.call
|
219
|
+
|
220
|
+
call_count.should eql 1
|
221
|
+
|
222
|
+
r.action.call
|
223
|
+
|
224
|
+
call_count.should eql 2
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'should execute chained tasks properly' do
|
229
|
+
a = ARake::Application.new top_level_self
|
230
|
+
with_rake_application a.rake do
|
231
|
+
calling_history = []
|
232
|
+
block = Proc.new {|t| calling_history.push t.to_s}
|
233
|
+
top_level_self.instance_eval do
|
234
|
+
# t1a t1b t1c
|
235
|
+
# |\ | |
|
236
|
+
# | \ | |
|
237
|
+
# | \| |
|
238
|
+
# t2a t2b t2c
|
239
|
+
# | | /|
|
240
|
+
# | | / |
|
241
|
+
# | |/ |
|
242
|
+
# t3a t3b t3c
|
243
|
+
task :t1a => [:t2a, :t2b], &block
|
244
|
+
task :t1b => [:t2b], &block
|
245
|
+
task :t1c => [:t2c], &block
|
246
|
+
task :t2a => [:t3a], &block
|
247
|
+
task :t2b => [:t3b], &block
|
248
|
+
task :t2c => [:t3b, :t3c], &block
|
249
|
+
task :t3a => [], &block
|
250
|
+
task :t3b => [], &block
|
251
|
+
task :t3c => [], &block
|
252
|
+
end
|
253
|
+
a.watchr_script.parse!
|
254
|
+
rules_table = Hash.new {|h, key| h[key] = []}
|
255
|
+
a.watchr_rules.each do |r|
|
256
|
+
rules_table[r.pattern].push r
|
257
|
+
end
|
258
|
+
def rules_table.trigger(task_name)
|
259
|
+
self[task_name].each do |r|
|
260
|
+
r.action.call
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
rules_table.keys.sort.should eql [
|
265
|
+
re(:t2a),
|
266
|
+
re(:t2b),
|
267
|
+
re(:t2c),
|
268
|
+
re(:t3a),
|
269
|
+
re(:t3b),
|
270
|
+
re(:t3c),
|
271
|
+
]
|
272
|
+
calling_history.should be_empty
|
273
|
+
|
274
|
+
calling_history.clear
|
275
|
+
rules_table.trigger re(:t3c)
|
276
|
+
|
277
|
+
calling_history.sort.should eql %w[t1c t2c t3b t3c]
|
278
|
+
|
279
|
+
calling_history.clear
|
280
|
+
rules_table.trigger re(:t2c)
|
281
|
+
|
282
|
+
calling_history.sort.should eql %w[t1c t2c t3b t3c]
|
283
|
+
|
284
|
+
calling_history.clear
|
285
|
+
rules_table.trigger re(:t3b)
|
286
|
+
|
287
|
+
calling_history.sort.should eql %w[
|
288
|
+
t1a t1b t1c t2a t2b t2c t3a t3b t3b t3c
|
289
|
+
]
|
290
|
+
|
291
|
+
calling_history.clear
|
292
|
+
rules_table.trigger re(:t2b)
|
293
|
+
|
294
|
+
calling_history.sort.should eql %w[t1a t1b t2a t2b t2b t3a t3b t3b]
|
295
|
+
|
296
|
+
calling_history.clear
|
297
|
+
rules_table.trigger re(:t3a)
|
298
|
+
|
299
|
+
calling_history.sort.should eql %w[t1a t2a t2b t3a t3b]
|
300
|
+
|
301
|
+
calling_history.clear
|
302
|
+
rules_table.trigger re(:t2a)
|
303
|
+
|
304
|
+
calling_history.sort.should eql %w[t1a t2a t2b t3a t3b]
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
|
310
|
+
|
311
|
+
|
312
|
+
describe ARake::Misc do
|
313
|
+
Tree = ARake::Misc::Tree
|
314
|
+
|
315
|
+
it 'should create an empty instance' do
|
316
|
+
t = Tree.new
|
317
|
+
t.value.should be_nil
|
318
|
+
t.subtrees.should be_empty
|
319
|
+
|
320
|
+
t.leaf?.should be_true
|
321
|
+
t.leaves.should eql [nil]
|
322
|
+
end
|
323
|
+
|
324
|
+
it 'should return values of leaves' do
|
325
|
+
t = Tree.new(
|
326
|
+
1,
|
327
|
+
[
|
328
|
+
Tree.new(2),
|
329
|
+
Tree.new(
|
330
|
+
3,
|
331
|
+
[Tree.new(4)]
|
332
|
+
),
|
333
|
+
Tree.new(5),
|
334
|
+
]
|
335
|
+
)
|
336
|
+
|
337
|
+
t.leaves.should eql [2, 4, 5]
|
338
|
+
end
|
339
|
+
|
340
|
+
it 'should return a tree of tasks based on their dependencies' do
|
341
|
+
def task(name, *prerequisites)
|
342
|
+
t = Rake::Task.new name, Rake::Application.new
|
343
|
+
t.enhance prerequisites
|
344
|
+
t
|
345
|
+
end
|
346
|
+
|
347
|
+
# t1a t1b t1c
|
348
|
+
# \ /| |
|
349
|
+
# X | |
|
350
|
+
# / \| |
|
351
|
+
# t2a t2b t2c
|
352
|
+
# | | /|
|
353
|
+
# | | / |
|
354
|
+
# | |/ |
|
355
|
+
# t3a t3b t3c
|
356
|
+
# |
|
357
|
+
# |
|
358
|
+
# |
|
359
|
+
# t4b
|
360
|
+
t4b = task 't4b'
|
361
|
+
t3c = task 't3c'
|
362
|
+
t3b = task 't3b', t4b
|
363
|
+
t3a = task 't3a'
|
364
|
+
t2c = task 't2c', t3b, t3c
|
365
|
+
t2b = task 't2b', t3b
|
366
|
+
t2a = task 't2a', t3a
|
367
|
+
t1c = task 't1c', t2c
|
368
|
+
t1b = task 't1b', t2a, t2b
|
369
|
+
t1a = task 't1a', t2b
|
370
|
+
|
371
|
+
tasks = [
|
372
|
+
t1a,
|
373
|
+
t1b,
|
374
|
+
t1c,
|
375
|
+
t2a,
|
376
|
+
t2b,
|
377
|
+
t2c,
|
378
|
+
t3a,
|
379
|
+
t3b,
|
380
|
+
t3c,
|
381
|
+
t4b,
|
382
|
+
]
|
383
|
+
|
384
|
+
ARake::Misc.root_tasks_of(t1a, tasks).should eql [t1a]
|
385
|
+
ARake::Misc.root_tasks_of(t1b, tasks).should eql [t1b]
|
386
|
+
ARake::Misc.root_tasks_of(t1c, tasks).should eql [t1c]
|
387
|
+
ARake::Misc.root_tasks_of(t2a, tasks).should eql [t1b]
|
388
|
+
ARake::Misc.root_tasks_of(t2b, tasks).should eql [t1a, t1b]
|
389
|
+
ARake::Misc.root_tasks_of(t2c, tasks).should eql [t1c]
|
390
|
+
ARake::Misc.root_tasks_of(t3a, tasks).should eql [t1b]
|
391
|
+
ARake::Misc.root_tasks_of(t3b, tasks).should eql [t1a, t1b, t1c]
|
392
|
+
ARake::Misc.root_tasks_of(t3c, tasks).should eql [t1c]
|
393
|
+
ARake::Misc.root_tasks_of(t4b, tasks).should eql [t1a, t1b, t1c]
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
__END__
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: arake
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Kana Natsuno
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-05-
|
13
|
+
date: 2011-05-06 00:00:00 +09:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -59,6 +59,7 @@ files:
|
|
59
59
|
- arake.gemspec
|
60
60
|
- bin/arake
|
61
61
|
- lib/arake.rb
|
62
|
+
- spec/arake_spec.rb
|
62
63
|
has_rdoc: true
|
63
64
|
homepage: http://github.com/kana/ruby-arake
|
64
65
|
licenses: []
|