basechip 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +32 -0
- data/LICENSE.txt +14 -0
- data/README.rdoc +19 -0
- data/VERSION +1 -0
- data/bin/basechip +25 -0
- data/collateral/block/block.rb.erb +20 -0
- data/collateral/configuration/configuration.rb.erb +19 -0
- data/collateral/project/Gemfile +19 -0
- data/collateral/project/gitignore +6 -0
- data/collateral/project/project.rb.erb +76 -0
- data/collateral/project/settings.rb.erb +26 -0
- data/collateral/recipes/icarus.rb +73 -0
- data/collateral/recipes/icarus.rb.erb +88 -0
- data/collateral/recipes/local_cluster.rb +27 -0
- data/lib/array.rb +26 -0
- data/lib/base_chip/action.rb +309 -0
- data/lib/base_chip/base.rb +105 -0
- data/lib/base_chip/block.rb +75 -0
- data/lib/base_chip/bom.rb +75 -0
- data/lib/base_chip/bom_file.rb +45 -0
- data/lib/base_chip/cli.rb +371 -0
- data/lib/base_chip/cluster.rb +93 -0
- data/lib/base_chip/cluster_type.rb +45 -0
- data/lib/base_chip/code_area.rb +30 -0
- data/lib/base_chip/configuration.rb +257 -0
- data/lib/base_chip/dsl.rb +593 -0
- data/lib/base_chip/exit_error.rb +20 -0
- data/lib/base_chip/generator_menu.rb +64 -0
- data/lib/base_chip/git.rb +32 -0
- data/lib/base_chip/hierarchy.rb +84 -0
- data/lib/base_chip/install_menu.rb +89 -0
- data/lib/base_chip/ipc.rb +50 -0
- data/lib/base_chip/list_menu.rb +134 -0
- data/lib/base_chip/menu.rb +70 -0
- data/lib/base_chip/out_file.rb +68 -0
- data/lib/base_chip/permutation.rb +26 -0
- data/lib/base_chip/permute.rb +25 -0
- data/lib/base_chip/post.rb +26 -0
- data/lib/base_chip/problem.rb +33 -0
- data/lib/base_chip/project.rb +472 -0
- data/lib/base_chip/requirement.rb +26 -0
- data/lib/base_chip/runable.rb +36 -0
- data/lib/base_chip/source_language.rb +40 -0
- data/lib/base_chip/source_type.rb +24 -0
- data/lib/base_chip/statistic.rb +27 -0
- data/lib/base_chip/task.rb +21 -0
- data/lib/base_chip/task_master.rb +50 -0
- data/lib/base_chip/taskable.rb +77 -0
- data/lib/base_chip/tasker.rb +260 -0
- data/lib/base_chip/test.rb +202 -0
- data/lib/base_chip/test_list.rb +120 -0
- data/lib/base_chip/tool.rb +51 -0
- data/lib/base_chip/tool_version.rb +34 -0
- data/lib/base_chip/top_menu.rb +203 -0
- data/lib/base_chip/track_state.rb +61 -0
- data/lib/base_chip.rb +215 -0
- data/lib/dir.rb +30 -0
- data/lib/reporting.rb +97 -0
- metadata +215 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
# Copyright 2011 Tommy Poulter
|
2
|
+
#
|
3
|
+
# This file is part of basechip.
|
4
|
+
#
|
5
|
+
# basechip is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License version 3 as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# basechip is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with basechip. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'yaml'
|
18
|
+
# require 'ipc'
|
19
|
+
YAML::ENGINE.yamler = 'psych'
|
20
|
+
|
21
|
+
module BaseChip
|
22
|
+
module TaskMaster
|
23
|
+
TASKER = Tasker
|
24
|
+
def self.included mod
|
25
|
+
mod.extend TaskMaster::ClassMethods
|
26
|
+
mod.class_eval do
|
27
|
+
include TaskMaster::InstanceMethods
|
28
|
+
attr_accessor :tasker
|
29
|
+
end
|
30
|
+
end
|
31
|
+
module ClassMethods
|
32
|
+
end
|
33
|
+
module InstanceMethods
|
34
|
+
def initialize(*args)
|
35
|
+
super(*args)
|
36
|
+
@tasker = TASKER.new
|
37
|
+
@tasker.task_master = self
|
38
|
+
end
|
39
|
+
def tasker_run_task
|
40
|
+
raise "Please extend tasker_run_task routine"
|
41
|
+
end
|
42
|
+
def tasker_handle_results(action, result)
|
43
|
+
raise "Please extend tasker_handle_results routine"
|
44
|
+
end
|
45
|
+
def tasker_empty
|
46
|
+
raise "Please extend tasker_run_task routine"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Copyright 2011 Tommy Poulter
|
2
|
+
#
|
3
|
+
# This file is part of basechip.
|
4
|
+
#
|
5
|
+
# basechip is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License version 3 as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# basechip is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with basechip. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
module BaseChip
|
18
|
+
module Taskable
|
19
|
+
def self.included mod
|
20
|
+
mod.extend Taskable::ClassMethods
|
21
|
+
mod.class_eval do
|
22
|
+
include Taskable::InstanceMethods
|
23
|
+
attr_accessor :task # for pointers to real tasks
|
24
|
+
attr_accessor :wait_count
|
25
|
+
attr_accessor :next_tasks
|
26
|
+
attr_accessor :task_name
|
27
|
+
attr_accessor :bundle_name
|
28
|
+
attr_accessor :bundle_tgz
|
29
|
+
attr_accessor :worker_command
|
30
|
+
attr_accessor :foreground
|
31
|
+
attr_accessor :totals
|
32
|
+
attr_accessor :state
|
33
|
+
end
|
34
|
+
end
|
35
|
+
module ClassMethods
|
36
|
+
end
|
37
|
+
module InstanceMethods
|
38
|
+
|
39
|
+
def initialize(*args)
|
40
|
+
super *args
|
41
|
+
initialize_taskable
|
42
|
+
end
|
43
|
+
def initialize_taskable
|
44
|
+
@wait_count = 0
|
45
|
+
@next_tasks = []
|
46
|
+
@totals = {}
|
47
|
+
end
|
48
|
+
def random_name
|
49
|
+
BaseChip.random_string
|
50
|
+
end
|
51
|
+
|
52
|
+
# nonportable but helpful to be here:
|
53
|
+
def deep_depends
|
54
|
+
# FIXME circular dependencies
|
55
|
+
return @deep_depends if @deep_depends
|
56
|
+
return @deep_depends = [] unless self.depends
|
57
|
+
|
58
|
+
@deep_depends = []
|
59
|
+
self.depends.each do |depend|
|
60
|
+
depend2 = depend.to_s.split(/:/)
|
61
|
+
while depend2.size < 3
|
62
|
+
depend2.unshift nil
|
63
|
+
end
|
64
|
+
depend2[0] ||= self.block .name.to_s
|
65
|
+
depend2[1] ||= self.configuration.name.to_s
|
66
|
+
@deep_depends += self.project.dereference_workload([depend2.join(':')])
|
67
|
+
end
|
68
|
+
@deep_depends.each do |d|
|
69
|
+
d.deep_configure
|
70
|
+
@deep_depends += d.deep_depends
|
71
|
+
end
|
72
|
+
@deep_depends.uniq!
|
73
|
+
@deep_depends
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
# Copyright 2011 Tommy Poulter
|
2
|
+
#
|
3
|
+
# This file is part of basechip.
|
4
|
+
#
|
5
|
+
# basechip is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License version 3 as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# basechip is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with basechip. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'yaml'
|
18
|
+
# require 'ipc'
|
19
|
+
YAML::ENGINE.yamler = 'psych'
|
20
|
+
|
21
|
+
module BaseChip
|
22
|
+
class Tasker
|
23
|
+
include Ipc
|
24
|
+
|
25
|
+
CLEAR = "\e[0K"
|
26
|
+
attr_accessor :task_master
|
27
|
+
|
28
|
+
attr_accessor :foreground
|
29
|
+
|
30
|
+
attr_accessor :clusters
|
31
|
+
|
32
|
+
attr_accessor :workers
|
33
|
+
|
34
|
+
attr_accessor :pending_tasks
|
35
|
+
attr_accessor :running_tasks
|
36
|
+
attr_accessor :complete_tasks
|
37
|
+
|
38
|
+
attr_accessor :client_of
|
39
|
+
attr_accessor :client_id
|
40
|
+
|
41
|
+
def initialize(*args)
|
42
|
+
@workers = {}
|
43
|
+
|
44
|
+
@pending_tasks = []; @tasks_pending = 0
|
45
|
+
@running_tasks = []; @tasks_running = 0
|
46
|
+
@complete_tasks = []; @tasks_complete = 0
|
47
|
+
@tasks_passed = 0
|
48
|
+
@tasks_failed = 0
|
49
|
+
|
50
|
+
@mutex = Mutex.new
|
51
|
+
|
52
|
+
@server = self
|
53
|
+
end
|
54
|
+
def tasks_total
|
55
|
+
@tasks_pending + @tasks_running + @tasks_complete
|
56
|
+
end
|
57
|
+
|
58
|
+
def ready
|
59
|
+
init_test_sockets(:server)
|
60
|
+
end
|
61
|
+
|
62
|
+
def run
|
63
|
+
STDOUT.sync = true
|
64
|
+
if @client_of || @clusters.nil?
|
65
|
+
begin
|
66
|
+
if @client_of
|
67
|
+
init_test_sockets(:client)
|
68
|
+
end
|
69
|
+
while(t = @server.get_task(@client_id))
|
70
|
+
@task_master.tasker_run_task t
|
71
|
+
end
|
72
|
+
rescue DRb::DRbConnError
|
73
|
+
# raise if @options.debug
|
74
|
+
end
|
75
|
+
else
|
76
|
+
DRb.thread.join
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def register_results(t, result, *additional)
|
81
|
+
if @client_of
|
82
|
+
@server.register_results(t, result, *additional)
|
83
|
+
return
|
84
|
+
end
|
85
|
+
@mutex.lock
|
86
|
+
inner_register_results(t, result, *additional)
|
87
|
+
@mutex.unlock
|
88
|
+
end
|
89
|
+
def inner_register_results(t, result, *additional)
|
90
|
+
return if @complete_tasks.select {|t2| t2.task_name == t.task_name}[0]
|
91
|
+
original_task = (@pending_tasks.select {|t2| t2.task_name == t.task_name}[0])
|
92
|
+
original_task ||= (@running_tasks.select {|t2| t2.task_name == t.task_name}[0])
|
93
|
+
raise "INTERNAL ERROR: couldn't find #{t.task_name}" unless original_task
|
94
|
+
|
95
|
+
if result == :cancel
|
96
|
+
@tasks_pending -= 1; @pending_tasks.delete original_task
|
97
|
+
else @tasks_running -= 1; @running_tasks.delete original_task
|
98
|
+
end
|
99
|
+
@complete_tasks << t
|
100
|
+
@tasks_complete += 1
|
101
|
+
|
102
|
+
if result == 'pass'
|
103
|
+
@tasks_passed += 1
|
104
|
+
original_task.next_tasks.each { |nt| nt.wait_count -= 1 }
|
105
|
+
else original_task.next_tasks.each { |nt| inner_register_results(nt,:cancel) }
|
106
|
+
@tasks_failed += 1 unless result == :cancel
|
107
|
+
end
|
108
|
+
@task_master.tasker_handle_results(t, result, *additional)
|
109
|
+
status_line
|
110
|
+
|
111
|
+
finish if (BaseChip.options.max_fails && @tasks_failed >= BaseChip.options.max_fails ) ||
|
112
|
+
(BaseChip.options.max_passes && @tasks_passed >= BaseChip.options.max_passes)
|
113
|
+
end
|
114
|
+
def status_line
|
115
|
+
return if @foreground
|
116
|
+
wr = workers_running
|
117
|
+
wa = workers_alive
|
118
|
+
wp = wa > 0 ? (100*wr/wa).round : 0
|
119
|
+
raise "Workload is empty" if tasks_total == 0
|
120
|
+
print "#{Tasker::CLEAR}complete:#{@tasks_complete}/#{tasks_total}(#{(100*@tasks_complete/tasks_total).round}%) workers:#{wr}/#{wa}(#{wp}%) pass:#{@tasks_passed} fail:#{@tasks_failed} run:#{@tasks_running} pend:#{@tasks_pending}\r"
|
121
|
+
end
|
122
|
+
def available_slots
|
123
|
+
count = 0
|
124
|
+
@clusters.each do |c|
|
125
|
+
count += c.available_slots
|
126
|
+
end
|
127
|
+
count
|
128
|
+
end
|
129
|
+
def spawn_worker(command)
|
130
|
+
@clusters.each do |c|
|
131
|
+
if c.available_slots > 0
|
132
|
+
c.slots_used += 1
|
133
|
+
return c, c.submit(command)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
@@last_client_id = 0
|
138
|
+
def new_client_id
|
139
|
+
@@last_client_id += 1
|
140
|
+
end
|
141
|
+
def maintain_workers
|
142
|
+
ready = @pending_tasks.select {|t| t.wait_count == 0}
|
143
|
+
if @clusters
|
144
|
+
slots = available_slots
|
145
|
+
foo = ready.size - workers_spawned
|
146
|
+
foo = slots if slots < foo
|
147
|
+
if foo > 0
|
148
|
+
foo.times do |i|
|
149
|
+
client_id = new_client_id
|
150
|
+
cluster, uid = spawn_worker(ready[0].worker_command.call(client_id))
|
151
|
+
raise "spawn_worker response wasn't unique" if @workers[uid]
|
152
|
+
@workers[client_id] = {:uid => uid, :cluster=> cluster, :started=>Time.now, :tasks=>[], :state=>:spawned, :worker_command=>ready[i].worker_command.call(0)}
|
153
|
+
status_line
|
154
|
+
end
|
155
|
+
end
|
156
|
+
else
|
157
|
+
@workers[0] = {:started=>Time.now, :tasks=>[], :state=>:running, :worker_command=>ready[0].worker_command} if ready[0]
|
158
|
+
end
|
159
|
+
|
160
|
+
# puts "ready=#{(ready.*.task_name).inspect}"
|
161
|
+
ready
|
162
|
+
end
|
163
|
+
|
164
|
+
def submit_name(t_name,worker_command=nil)
|
165
|
+
task = Task.new
|
166
|
+
task.task_name = t_name
|
167
|
+
task.worker_command = worker_command if @clusters
|
168
|
+
submit(task)
|
169
|
+
end
|
170
|
+
def submit(task)
|
171
|
+
task.foreground = self.foreground
|
172
|
+
@pending_tasks << task
|
173
|
+
@tasks_pending += 1
|
174
|
+
maintain_workers
|
175
|
+
status_line
|
176
|
+
end
|
177
|
+
def submit_workload_chain(chain)
|
178
|
+
@pending_tasks = chain
|
179
|
+
@tasks_pending = chain.size
|
180
|
+
maintain_workers
|
181
|
+
status_line
|
182
|
+
end
|
183
|
+
def get_task(client_id)
|
184
|
+
@mutex.lock
|
185
|
+
ready = maintain_workers
|
186
|
+
|
187
|
+
w = @workers[client_id]
|
188
|
+
raise "Could not find worker based on unique id #{client_id}" unless w
|
189
|
+
|
190
|
+
t = nil
|
191
|
+
ready.each do |rt|
|
192
|
+
if rt.worker_command.nil? || rt.worker_command.call(0) == w[:worker_command]
|
193
|
+
t = rt
|
194
|
+
break
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
if t
|
199
|
+
@pending_tasks.delete t
|
200
|
+
@running_tasks << t
|
201
|
+
@tasks_pending -= 1
|
202
|
+
@tasks_running += 1
|
203
|
+
|
204
|
+
w[:tasks] << t
|
205
|
+
w[:state] = :running
|
206
|
+
else
|
207
|
+
w[:state] = :stopped
|
208
|
+
w[:cluster].slots_used -= 1 if w[:cluster]
|
209
|
+
end
|
210
|
+
|
211
|
+
finish if @pending_tasks.empty? && @running_tasks.empty? && ready.empty?
|
212
|
+
|
213
|
+
if @pending_tasks.size > 0 && @running_tasks.empty? && ready.empty?
|
214
|
+
raise("Could not build tasks because their dependencies never cleared: " + (@pending_tasks.map{|t|t.task_name}.join(" ")))
|
215
|
+
end
|
216
|
+
|
217
|
+
status_line
|
218
|
+
@mutex.unlock
|
219
|
+
t
|
220
|
+
end
|
221
|
+
|
222
|
+
def finish
|
223
|
+
return if @finishing
|
224
|
+
@finishing = true
|
225
|
+
|
226
|
+
kill
|
227
|
+
@task_master.tasker_finish
|
228
|
+
DRb.stop_service
|
229
|
+
end
|
230
|
+
|
231
|
+
def kill
|
232
|
+
locked = @mutex.try_lock
|
233
|
+
@workers.each do |id,w|
|
234
|
+
next if w[:stopped]
|
235
|
+
if w[:cluster] && (w[:state] != :stopped)
|
236
|
+
kill_message
|
237
|
+
w[:cluster].kill(w[:uid])
|
238
|
+
end
|
239
|
+
end
|
240
|
+
(@running_tasks + @pending_tasks).each do |t|
|
241
|
+
inner_register_results t, :cancel
|
242
|
+
end
|
243
|
+
@mutex.unlock if locked
|
244
|
+
end
|
245
|
+
def kill_message
|
246
|
+
return if @kill_message
|
247
|
+
@kill_message = true
|
248
|
+
puts "#{Tasker::CLEAR}\rClosing down all workers. Please be patient."
|
249
|
+
end
|
250
|
+
|
251
|
+
def workers_alive; c=0; @workers.each_value{|w| c+=1 if w[:state] != :stopped}; c end
|
252
|
+
def workers_running; c=0; @workers.each_value{|w| c+=1 if w[:state] == :running}; c end
|
253
|
+
def workers_spawned; c=0; @workers.each_value{|w| c+=1 if w[:state] == :spawned}; c end
|
254
|
+
def workers_stopped; c=0; @workers.each_value{|w| c+=1 if w[:state] == :stopped}; c end
|
255
|
+
|
256
|
+
def clear_line
|
257
|
+
print "#{Tasker::CLEAR}\r"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,202 @@
|
|
1
|
+
# Copyright 2011 Tommy Poulter
|
2
|
+
#
|
3
|
+
# This file is part of basechip.
|
4
|
+
#
|
5
|
+
# basechip is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License version 3 as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# basechip is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with basechip. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'base_chip/action'
|
18
|
+
|
19
|
+
module BaseChip
|
20
|
+
class Test
|
21
|
+
include Taskable
|
22
|
+
include TrackState
|
23
|
+
include Runable
|
24
|
+
include Dsl
|
25
|
+
include Base
|
26
|
+
define_settings({:zip_failing_test => [ Boolean ],
|
27
|
+
:zip_passing_test => [ Boolean ],
|
28
|
+
:clean_passing_test => [ Boolean ],
|
29
|
+
:run_test_in_tmp => [ Boolean ],
|
30
|
+
:test_actions => [ Symbol , Array ]}.merge(Action.settings))
|
31
|
+
define_children(Action.child_types)
|
32
|
+
|
33
|
+
attr_accessor :original_actions
|
34
|
+
attr_accessor :action_extensions
|
35
|
+
# def actions
|
36
|
+
# parent.actions
|
37
|
+
# end
|
38
|
+
|
39
|
+
def configure
|
40
|
+
return if @configured
|
41
|
+
name_it
|
42
|
+
@directory ||= "#{parent.directory}/#{@name}"
|
43
|
+
super
|
44
|
+
end
|
45
|
+
def deep_configure
|
46
|
+
super
|
47
|
+
|
48
|
+
return if @deep_configured
|
49
|
+
@deep_configured = true
|
50
|
+
|
51
|
+
@test_actions = [@test_actions] unless @test_actions.is_a? Array
|
52
|
+
# @original_actions = @block.dereference_workload([@actions])[0]
|
53
|
+
fault "No test_actions exist for test list '#{@test_list}' to run in '#{@configuration.full_name}'" unless @configuration.actions
|
54
|
+
unless (@original_actions = @configuration.dereference_workload(@test_actions)) && @original_actions.size > 0
|
55
|
+
fault "Test list '#{@test_list.name}' in block:configuration '#{@block.name}:#{@configuration.name}' specified nonexistant action(s) '#{@test_actions}'. #{@test_list.file}"
|
56
|
+
end
|
57
|
+
|
58
|
+
@action_extensions = @original_actions.map do |a|
|
59
|
+
append_depends a.depends
|
60
|
+
a2 = a.clone
|
61
|
+
a2.clear
|
62
|
+
a2.parent = self # don't think I need to set foster here, because test list is a peer to action
|
63
|
+
a2.deep_configure
|
64
|
+
a2
|
65
|
+
end
|
66
|
+
|
67
|
+
@action_extensions.sort! do |a1,a2|
|
68
|
+
if a1.deep_depends.map{|d|d.name}.include? a2.name
|
69
|
+
1
|
70
|
+
else
|
71
|
+
-1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
# def find_parent_values
|
76
|
+
# super
|
77
|
+
|
78
|
+
# # @original_actions = @block.dereference_workload([@action])[0]
|
79
|
+
# @original_actions = @block.actions[@action]
|
80
|
+
|
81
|
+
# @original_actions. settings.each {|n,s| @children_settings[n] = s if s.value_set and not @children_settings[n].value_set }
|
82
|
+
# @original_actions.children_settings.each {|n,s| @children_settings[n] = s if s.value_set and not @children_settings[n].value_set }
|
83
|
+
|
84
|
+
# @action_extensions = Action.new
|
85
|
+
#
|
86
|
+
# # FIXME support outfile definition in Test
|
87
|
+
# @original_actions .out_files.each do |n,f|
|
88
|
+
# @action_extensions.out_files[n] = f.dup
|
89
|
+
# end
|
90
|
+
|
91
|
+
# @action_extensions.find_parent_values
|
92
|
+
|
93
|
+
# @action_extensions.name_it
|
94
|
+
# @name = @action_extensions.name
|
95
|
+
# end
|
96
|
+
# def find_parent_values
|
97
|
+
# super
|
98
|
+
# find_parent_values_of_underlying_action
|
99
|
+
# end
|
100
|
+
|
101
|
+
def name_it
|
102
|
+
if BaseChip.options.random_bundle_names
|
103
|
+
@name ||= random_name
|
104
|
+
elsif parent.autoname and not @name
|
105
|
+
if parent.autoname.respond_to? :each
|
106
|
+
parent.autoname.each do |an|
|
107
|
+
if md = /#{an}/.match(@args)
|
108
|
+
@name ||= (md[1] || md.to_s)
|
109
|
+
break
|
110
|
+
end
|
111
|
+
end
|
112
|
+
else
|
113
|
+
if md = /#{parent.autoname}/.match(@args)
|
114
|
+
@name ||= (md[1] || md.to_s)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
#def depends(dep=nil) ;(@action_extensions && @action_extensions.depends ) || super(dep) end
|
120
|
+
def bundle_name ; name end
|
121
|
+
def bundle_tgz ; "#{@directory}.tgz" end
|
122
|
+
def totals
|
123
|
+
return @totals if @totals
|
124
|
+
@totals = {}
|
125
|
+
@action_extensions.each do |a|
|
126
|
+
@totals.merge! a.totals
|
127
|
+
end
|
128
|
+
end
|
129
|
+
def run
|
130
|
+
if @run_test_in_tmp
|
131
|
+
bundle_name = random_string
|
132
|
+
run_directory = "/tmp/#{bundle_name}"
|
133
|
+
else
|
134
|
+
bundle_name = name
|
135
|
+
run_directory = @directory
|
136
|
+
end
|
137
|
+
FileUtils.rm_rf run_directory
|
138
|
+
FileUtils.mkdir_p run_directory
|
139
|
+
Dir.pushd run_directory
|
140
|
+
|
141
|
+
File.open('seed','w') do |f|
|
142
|
+
f.write random_generator.seed
|
143
|
+
end
|
144
|
+
File.open('rerun.yaml','w') do |f|
|
145
|
+
f.write rerun_data.to_yaml
|
146
|
+
end
|
147
|
+
|
148
|
+
@action_extensions.each do |a|
|
149
|
+
a.random_generator = Random.new(random_generator.rand(0x1_0000_0000))
|
150
|
+
a.foreground = @foreground
|
151
|
+
a.inner_run
|
152
|
+
take_state(a)
|
153
|
+
return unless pass?
|
154
|
+
end
|
155
|
+
|
156
|
+
Dir.chdir '..'
|
157
|
+
if (@clean_passing_test && pass? && !@foreground)
|
158
|
+
FileUtils.rm_rf run_directory
|
159
|
+
else
|
160
|
+
bundle_tgz = nil
|
161
|
+
if @zip_failing_test || (@zip_passing_test && pass?)
|
162
|
+
bundle_tgz = run_directory + ".tgz"
|
163
|
+
@bundle_tgz = @directory + ".tgz"
|
164
|
+
tgz = Zlib::GzipWriter.new(File.open(bundle_tgz, 'wb'))
|
165
|
+
Archive::Tar::Minitar.pack(bundle_name, tgz)
|
166
|
+
FileUtils.rm_rf bundle_name
|
167
|
+
end
|
168
|
+
if @run_test_in_tmp
|
169
|
+
FileUtils.mkdir_p "#{@directory}/../"
|
170
|
+
FileUtils.mv((bundle_tgz || run_directory), "#{@directory}/../")
|
171
|
+
end
|
172
|
+
end
|
173
|
+
Dir.popd
|
174
|
+
|
175
|
+
puts "Debug information here: #{@bundle_tgz || @directory}" if @foreground
|
176
|
+
end
|
177
|
+
# SAFE TO DELETE? def configuration_hash
|
178
|
+
# SAFE TO DELETE? super.merge @action_extensions.configuration_hash
|
179
|
+
# SAFE TO DELETE? end
|
180
|
+
|
181
|
+
def clean
|
182
|
+
end
|
183
|
+
def clobber
|
184
|
+
FileUtil.rm_rf directory
|
185
|
+
if Dir.empty? test_list.directory
|
186
|
+
FileUtil.rm_rf test_list.directory
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
# one random generator per test, all subordinate actions use it
|
191
|
+
def random_generator
|
192
|
+
@random_generator ||= BaseChip.new_random_generator
|
193
|
+
end
|
194
|
+
|
195
|
+
def rerun_data
|
196
|
+
{ 'full_name' => full_name ,
|
197
|
+
'seed' => random_generator.seed ,
|
198
|
+
'append_arguments' => BaseChip.options. append_arguments ,
|
199
|
+
'replace_arguments' => BaseChip.options.replace_arguments }
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# Copyright 2011 Tommy Poulter
|
2
|
+
#
|
3
|
+
# This file is part of basechip.
|
4
|
+
#
|
5
|
+
# basechip is free software: you can redistribute it and/or modify
|
6
|
+
# it under the terms of the GNU General Public License version 3 as
|
7
|
+
# published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# basechip is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with basechip. If not, see <http://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'base_chip/test'
|
18
|
+
require 'base_chip/permute'
|
19
|
+
require 'base_chip/requirement'
|
20
|
+
require 'base_chip/post'
|
21
|
+
module BaseChip
|
22
|
+
class TestList
|
23
|
+
include Dsl
|
24
|
+
include Base
|
25
|
+
define_settings({:autoname => [ Regexp , Array ]})
|
26
|
+
define_children({:test => Test ,
|
27
|
+
:permute => Permute ,
|
28
|
+
:requirement => Requirement,
|
29
|
+
:post => Post })
|
30
|
+
|
31
|
+
def initialize
|
32
|
+
super
|
33
|
+
@num_tests = 0
|
34
|
+
end
|
35
|
+
# def actions
|
36
|
+
# parent.actions
|
37
|
+
# end
|
38
|
+
alias old_requirement requirement
|
39
|
+
alias old_post post
|
40
|
+
def requirement(name=:no_name,&blk); old_requirement(name,&blk) end
|
41
|
+
def post( name=:no_name,&blk); old_post( name,&blk) end
|
42
|
+
def configure
|
43
|
+
return if @configured
|
44
|
+
@directory ||= "#{configuration.out_directory}/#{name}"
|
45
|
+
super
|
46
|
+
return unless @tests
|
47
|
+
return unless @permutes
|
48
|
+
tests = @tests.values
|
49
|
+
@permutes.each_value do |permute|
|
50
|
+
permute.configure
|
51
|
+
next unless permute.permutations
|
52
|
+
tests.map! do |t|
|
53
|
+
permute.permutations.values.map do |permutation|
|
54
|
+
test = t.dup
|
55
|
+
test.name = "#{test.name}_#{permute.name}#{permutation.name}".to_sym
|
56
|
+
test.blks += permutation.blks
|
57
|
+
test
|
58
|
+
end
|
59
|
+
end
|
60
|
+
tests.flatten!
|
61
|
+
end
|
62
|
+
|
63
|
+
if @posts
|
64
|
+
tests.each do |t|
|
65
|
+
@posts.each_value do |p|
|
66
|
+
p.blks.each do |b|
|
67
|
+
b.call(t)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
if @requirements
|
73
|
+
new_tests = []
|
74
|
+
tests.each do |t|
|
75
|
+
t.configure
|
76
|
+
ditch = false
|
77
|
+
@requirements.each_value do |m|
|
78
|
+
m.blks.each do |b|
|
79
|
+
ditch = !(b.call t)
|
80
|
+
break if ditch
|
81
|
+
end
|
82
|
+
break if ditch
|
83
|
+
end
|
84
|
+
next if ditch
|
85
|
+
new_tests << t
|
86
|
+
end
|
87
|
+
tests = new_tests
|
88
|
+
end
|
89
|
+
@tests = {}
|
90
|
+
tests.each do |t|
|
91
|
+
name = t.name
|
92
|
+
i = 0
|
93
|
+
while @tests[name]
|
94
|
+
name = "#{t.name}_#{i+=1}"
|
95
|
+
end
|
96
|
+
t.name = name.to_sym
|
97
|
+
@tests[name] = t
|
98
|
+
end
|
99
|
+
end
|
100
|
+
def dereference_workload(tests = nil,passive = false)
|
101
|
+
configure
|
102
|
+
tests ||= ['all']
|
103
|
+
out = []
|
104
|
+
return out unless @tests
|
105
|
+
tests.each do |t|
|
106
|
+
if t == 'all'
|
107
|
+
out += @tests.values
|
108
|
+
else
|
109
|
+
if foo = @tests[t.to_sym]
|
110
|
+
out << foo
|
111
|
+
else
|
112
|
+
fault "Could not find test #{t.inspect} in list #{@name.inspect} in block #{@block.name.inspect}" unless passive
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
out
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|