basechip 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,472 @@
|
|
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/block'
|
18
|
+
require 'base_chip/cluster_type'
|
19
|
+
|
20
|
+
module BaseChip
|
21
|
+
class Project
|
22
|
+
include TaskMaster
|
23
|
+
include Dsl
|
24
|
+
include Base
|
25
|
+
include Hierarchy
|
26
|
+
|
27
|
+
# Sets/gets the shared directory for this project, which is a place to
|
28
|
+
# install tools and IP shared between workareas (usually because of size).
|
29
|
+
# Expects a full path
|
30
|
+
define_setting :shared_directory , [ String ]
|
31
|
+
|
32
|
+
# Sets/gets the order of preference for clusters. If the user specifies
|
33
|
+
# "-j 500" on the command line, it will be spread across multiple clusters
|
34
|
+
# according to their default submission setting. This setting sets the
|
35
|
+
# order to fill those clusters.
|
36
|
+
# Expects an array of cluster names
|
37
|
+
# @example use local cluster types first, then lsf cluster types
|
38
|
+
# cluster_order %w{ local lsf }
|
39
|
+
# @example use local cluster types first, then lsf medium cluster, then lsf low cluster
|
40
|
+
# cluster_order %w{ local lsf:medium lsf:low }
|
41
|
+
define_setting :cluster_order , [ Array ]
|
42
|
+
define_child :block , Block
|
43
|
+
define_child :subproject , Project
|
44
|
+
define_child :cluster_type , ClusterType
|
45
|
+
|
46
|
+
attr_accessor :workload
|
47
|
+
|
48
|
+
def initialize()
|
49
|
+
super
|
50
|
+
@project = self
|
51
|
+
@pwd = Dir.pwd
|
52
|
+
end
|
53
|
+
# def configure_blocks(block_names)
|
54
|
+
# block_names.each do |name|
|
55
|
+
# self.blocks[name.to_sym].configure
|
56
|
+
# end
|
57
|
+
# end
|
58
|
+
def figure_directory_prefix
|
59
|
+
# if @directory == @pwd
|
60
|
+
# return nil
|
61
|
+
# elsif @pwd.length > @directory.length
|
62
|
+
configure
|
63
|
+
if @blocks
|
64
|
+
@blocks.each do |bname,block|
|
65
|
+
block.configure
|
66
|
+
if @pwd =~ /^#{block.directory}\b/
|
67
|
+
block.configurations.each do |cname,configuration|
|
68
|
+
configuration.configure
|
69
|
+
return "#{bname}:#{cname}" if @pwd =~ /^#{configuration.directory}\b/
|
70
|
+
end
|
71
|
+
return bname.to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
# end
|
76
|
+
nil
|
77
|
+
# fault "'base_chip' should be run from a block's work directory or the top level of the project."
|
78
|
+
end
|
79
|
+
def block_names
|
80
|
+
return @block_names if @block_names
|
81
|
+
# \@block_names = Dir.glob("#\{@directory}/*")
|
82
|
+
# \@block_names.map!{|path| path.split(/\//).pop}
|
83
|
+
# \@block_names.delete 'settings.yaml'
|
84
|
+
# \@block_names
|
85
|
+
end
|
86
|
+
DEFINED_SUBCOMMANDS = %W{all gate}
|
87
|
+
def ready(targets=nil) #,available_only=false)
|
88
|
+
configure
|
89
|
+
@orig_targets = targets
|
90
|
+
if @directory_prefix
|
91
|
+
# no map! here because @orig_targets needs to stay true to the original command
|
92
|
+
targets = targets.map { |t| "#{@directory_prefix}:#{t}" }
|
93
|
+
end
|
94
|
+
@workload = dereference_workload targets
|
95
|
+
@workload.delete_if {|w|w.nil?}
|
96
|
+
if @workload.empty?
|
97
|
+
if diffgate(targets)
|
98
|
+
puts "diffgate returned no targets needing to run"
|
99
|
+
exit
|
100
|
+
else
|
101
|
+
fault "Could not determine anything to run based on the targets #{targets}. Did you mean to run this from another directory?"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
w_names = @workload.map{|w|w.name}
|
106
|
+
@workload.each do |w|
|
107
|
+
w.configure
|
108
|
+
if w.depends
|
109
|
+
w.deep_depends.each do |d|
|
110
|
+
if @workload.include? d
|
111
|
+
w.wait_count += 1
|
112
|
+
d.next_tasks << w
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
def diffgate(targets)
|
119
|
+
targets.each do |t|
|
120
|
+
return false unless t =~ /\bdiffgate$/
|
121
|
+
end
|
122
|
+
true
|
123
|
+
end
|
124
|
+
def run_all_readied
|
125
|
+
# @report_hash = {}
|
126
|
+
FileUtils.mkdir_p "#{@directory}/reports"
|
127
|
+
@report_name = "#{@directory}/reports/workload.#{BaseChip.random_string}"
|
128
|
+
@report_file = File.new(@report_name,'w')
|
129
|
+
if @tasker.clusters
|
130
|
+
@tasker.ready
|
131
|
+
else
|
132
|
+
@foreground = @workload.size == 1
|
133
|
+
end
|
134
|
+
begin
|
135
|
+
@tasker.submit_workload_chain workload_chain
|
136
|
+
@tasker.run
|
137
|
+
rescue Interrupt
|
138
|
+
@tasker.finish
|
139
|
+
end
|
140
|
+
end
|
141
|
+
def workload_chain
|
142
|
+
@workload.each do |w|
|
143
|
+
w.task = t = Task.new
|
144
|
+
t.task_name = w.full_name
|
145
|
+
t.foreground = @foreground
|
146
|
+
t.worker_command = if @tasker.clusters
|
147
|
+
lambda { |client_id|
|
148
|
+
# The "@drb_uri ||=" is necessary because Drb.uri can change for some reason, and a command compare happens later
|
149
|
+
"#{$0} #{@orig_targets.join(' ')} --client-of #{@drb_uri ||= DRb.uri} --client-id #{client_id} --work-dir #{@pwd} #{
|
150
|
+
'--modes ' + BaseChip.options.modes if BaseChip.options.modes } #{
|
151
|
+
(['--' ] + BaseChip.options. append_arguments).join(' ') if BaseChip.options. append_arguments } #{
|
152
|
+
(['---'] + BaseChip.options.replace_arguments).join(' ') if BaseChip.options.replace_arguments }" }
|
153
|
+
else
|
154
|
+
nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
@workload.map do |w|
|
158
|
+
t = w.task
|
159
|
+
t.next_tasks = w.next_tasks.map { |nt| nt.task }
|
160
|
+
t.wait_count = w.wait_count
|
161
|
+
w.next_tasks.uniq!
|
162
|
+
t
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def block_dereference(name,names,passive)
|
167
|
+
if block = @blocks[name.to_sym]
|
168
|
+
block.configure
|
169
|
+
block.dereference_workload(names,passive)
|
170
|
+
else
|
171
|
+
fault "Could not find block #{name} in project #{@name}" # FIXME say who wanted it, and if shortcut occurred
|
172
|
+
end
|
173
|
+
end
|
174
|
+
def dereference_workload(targets)
|
175
|
+
configure
|
176
|
+
fault "project '#{name}' has no blocks defined" unless @blocks
|
177
|
+
targets ||= ['all']
|
178
|
+
out = []
|
179
|
+
|
180
|
+
workload_hash = Hash.new
|
181
|
+
|
182
|
+
targets.each do |t|
|
183
|
+
case t
|
184
|
+
when 'gate', 'diffgate', 'all'
|
185
|
+
self.block_names.each do |b|
|
186
|
+
out += block_dereference(b,[t],true)
|
187
|
+
end
|
188
|
+
when /^all:(.*)$/
|
189
|
+
self.block_names.each do |b|
|
190
|
+
out += block_dereference(b,[$1],true)
|
191
|
+
end
|
192
|
+
when /:/
|
193
|
+
tmp = t.split(/:/)
|
194
|
+
b = tmp.shift
|
195
|
+
out += block_dereference(b,[tmp.join(':')],true)
|
196
|
+
else
|
197
|
+
fault "Cannot determine block in order to run #{t}."
|
198
|
+
end
|
199
|
+
end
|
200
|
+
out.uniq!
|
201
|
+
out
|
202
|
+
end
|
203
|
+
def tasker_handle_results(task, result, problem_or_directory=nil, totals={})
|
204
|
+
action = @workload.select{|w|w.full_name == task.task_name}.first
|
205
|
+
# track_results(action, result, problem, totals)
|
206
|
+
if result == 'fail'
|
207
|
+
message = (problem_or_directory || "#{action.class_string} '#{action.name}' failed without an error signature").to_s
|
208
|
+
begin
|
209
|
+
error message
|
210
|
+
rescue
|
211
|
+
end
|
212
|
+
@failing ||= 0
|
213
|
+
@failing += 1
|
214
|
+
@first_error = {}
|
215
|
+
@first_error[action.class_string] ||= message
|
216
|
+
end
|
217
|
+
@results ||= {}
|
218
|
+
@results[action.class_string] ||= {}
|
219
|
+
@results[action.class_string][action.block.name] ||= {'pass' => [], 'fail' => [], :cancel =>[]}
|
220
|
+
@results[action.class_string][action.block.name][result] << action
|
221
|
+
@report_file.puts "#{result} #{action.class_string} #{task.task_name} #{problem_or_directory}"
|
222
|
+
end
|
223
|
+
def results_line(type,block,total)
|
224
|
+
blocks = block == 'all' ? @results[type].keys : [block]
|
225
|
+
if total
|
226
|
+
pass_fail_cancel = [0,0,0,0,0,0,0]
|
227
|
+
blocks.each do |b|
|
228
|
+
res_hash = @results[type][b]
|
229
|
+
pass_fail_cancel[0] += res_hash['pass'].size
|
230
|
+
pass_fail_cancel[2] += res_hash['fail'].size
|
231
|
+
pass_fail_cancel[4] += res_hash[:cancel].size
|
232
|
+
end
|
233
|
+
pass_fail_cancel[6] = pass_fail_cancel[0] + pass_fail_cancel[2] + pass_fail_cancel[4]
|
234
|
+
pass_fail_cancel[1] = (100 * pass_fail_cancel[0]/pass_fail_cancel[6]).round
|
235
|
+
pass_fail_cancel[3] = (100 * pass_fail_cancel[2]/pass_fail_cancel[6]).round
|
236
|
+
pass_fail_cancel[5] = (100 * pass_fail_cancel[4]/pass_fail_cancel[6]).round
|
237
|
+
str = pass_fail_cancel[0] > 0 ? ' [32m%6d %3d[0m |' : ' %6d %3d |'
|
238
|
+
str += pass_fail_cancel[3] > 0 ? ' [31m%6d %3d[0m |' : ' %6d %3d |'
|
239
|
+
str += pass_fail_cancel[5] > 0 ? ' [33m%6d %3d[0m |' : ' %6d %3d |'
|
240
|
+
return "#{str} %6d" % pass_fail_cancel
|
241
|
+
else
|
242
|
+
fault 'Internal error: detailed result reporting not yet supported'
|
243
|
+
end
|
244
|
+
end
|
245
|
+
def find_action(t_name)
|
246
|
+
address = t_name.split(/:/)
|
247
|
+
|
248
|
+
block_name = address.shift.to_sym
|
249
|
+
block = self.blocks[block_name] or fault("Couldn't find block '#{block_name}'")
|
250
|
+
|
251
|
+
config_name = address.shift.to_sym
|
252
|
+
config = block.configurations[config_name] or fault("Couldn't find configuration '#{config_name}' in block '#{block_name}")
|
253
|
+
|
254
|
+
thing = address.shift.to_sym
|
255
|
+
action = config.actions[thing]
|
256
|
+
return action if action
|
257
|
+
|
258
|
+
test_list = config.test_lists[thing] or fault("Could not find action or test list '#{thing}' in block:configuration '#{block_name}:#{config_name}'")
|
259
|
+
test_name = address.shift.to_sym
|
260
|
+
test = test_list.tests[test_name] or fault("Could not find test '#{test_name}' in block:configuration:list '#{block_name}:#{config_name}:#{thing}'")
|
261
|
+
return test
|
262
|
+
end
|
263
|
+
def banner_line(str)
|
264
|
+
@report_file.puts str.gsub(/\[\d+m/,'')
|
265
|
+
puts str
|
266
|
+
end
|
267
|
+
def banner
|
268
|
+
|
269
|
+
banner_line '--------------------------------- ------------ ------------ ------------ --------'
|
270
|
+
banner_line ' | PASS # % | FAIL # % | CNCL # % | TOTAL '
|
271
|
+
if @results['Action']
|
272
|
+
banner_line ( ' ACTIONS |' + results_line('Action','all',true))
|
273
|
+
@results['Action'].each_key do |block|
|
274
|
+
banner_line((' %-29s |' % block) + results_line('Action',block,true))
|
275
|
+
end
|
276
|
+
end
|
277
|
+
if @results['Test']
|
278
|
+
banner_line ( ' TESTS |' + results_line('Test','all',true))
|
279
|
+
@results['Test'].each_key do |block|
|
280
|
+
banner_line((' %-29s |' % block) + results_line('Test',block,true))
|
281
|
+
end
|
282
|
+
end
|
283
|
+
banner_line '--------------------------------- ------------ ------------ ------------ --------'
|
284
|
+
@report_file.close
|
285
|
+
|
286
|
+
puts "Full report available here: #{@report_name}"
|
287
|
+
if @first_error
|
288
|
+
fault("This workload had #{@failing} error(s).\n" +
|
289
|
+
(@first_error['Action'] ? " The first action related error encountered was:\n #{@first_error['Action']}" : '') +
|
290
|
+
(@first_error['Test' ] ? " The first test related error encountered was:\n #{ @first_error['Test' ]}" : '') ,
|
291
|
+
@first_error['Action'] || @first_error['Test']
|
292
|
+
)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
def tasker_finish
|
296
|
+
banner
|
297
|
+
end
|
298
|
+
def tasker_run_task(t_obj)
|
299
|
+
t = find_action(t_obj.task_name)
|
300
|
+
begin
|
301
|
+
t.foreground = @foreground
|
302
|
+
t.run
|
303
|
+
rescue ReportingError => e
|
304
|
+
# FIXME reuse test error states here
|
305
|
+
t.state = 'fail'
|
306
|
+
rescue Exception => e
|
307
|
+
t.problem = Problem.new
|
308
|
+
t.problem.signature = "#{t.full_name} #{e.class} --- #{e.message}"
|
309
|
+
puts e.backtrace
|
310
|
+
# FIXME reuse test error states here
|
311
|
+
t.state = 'fail'
|
312
|
+
end
|
313
|
+
#track_results(t ,t.state,t.problem ,t.totals)
|
314
|
+
@tasker.register_results(t_obj,t.state,t.problem || t.directory,t.totals)
|
315
|
+
end
|
316
|
+
# def enable_tracking(opc,opi)
|
317
|
+
# # puts "enabled tracking(#{opc},#{opi})"
|
318
|
+
# init_results_sockets(:client)
|
319
|
+
# @opc = opc
|
320
|
+
# @opi = opi
|
321
|
+
# end
|
322
|
+
# def track_complete(state,first_error = nil)
|
323
|
+
# return unless @opc
|
324
|
+
# msg = Message.new
|
325
|
+
# msg.project = 'gandalf'
|
326
|
+
# msg.type = 'complete'
|
327
|
+
# msg.state = state
|
328
|
+
# msg.data = {
|
329
|
+
# 'opc' => @opc ,
|
330
|
+
# 'opi' => @opi ,
|
331
|
+
# 'first_error' => first_error
|
332
|
+
# }
|
333
|
+
# send_work_message(msg)
|
334
|
+
# end
|
335
|
+
# def track_results(test_action,state,problem,totals)
|
336
|
+
# return unless @opc
|
337
|
+
# msg = Message.new
|
338
|
+
# msg.project = 'gandalf'
|
339
|
+
# msg.type = 'test_action'
|
340
|
+
# msg.state = state
|
341
|
+
# msg.data = {
|
342
|
+
# 'name' => test_action.bundle_name,
|
343
|
+
# 'block' => test_action.block.name,
|
344
|
+
# 'opc' => @opc,
|
345
|
+
# 'opi' => @opi,
|
346
|
+
# 'first_error' => problem && problem.signature,
|
347
|
+
# 'file' => problem && problem.file,
|
348
|
+
# 'bundle' => problem && problem.bundle,
|
349
|
+
# 'totals' => totals
|
350
|
+
# }
|
351
|
+
# # puts "sending totals #{test_action.totals.inspect}"
|
352
|
+
# puts "sending message #{msg.data.inspect}"
|
353
|
+
# if test_action.class_string == 'Action'
|
354
|
+
# msg.data['action' ] = test_action.name
|
355
|
+
# else
|
356
|
+
# msg.data['test' ] = test_action.name
|
357
|
+
# msg.data['test_list'] = test_action.test_list.name
|
358
|
+
# end
|
359
|
+
# send_work_message(msg)
|
360
|
+
# end
|
361
|
+
def shortcut(name, array)
|
362
|
+
@shortcuts ||= {}
|
363
|
+
@shortcuts[name] = array
|
364
|
+
end
|
365
|
+
|
366
|
+
def discover_subprojects ; file_glob("#{@directory}/*/base_chip/project.rb" , /(\w+)\/base_chip\/project\.rb$/ , :subproject )
|
367
|
+
file_glob("#{@directory}/base_chip/subprojects/*.rb" , /base_chip\/subprojects\/(\w+)\.rb$/ , :subproject ) end
|
368
|
+
def discover_blocks ; file_glob("#{@directory}/*/base_chip/block.rb" , /(\w+)\/base_chip\/block\.rb$/ , :block )
|
369
|
+
file_glob("#{@directory}/base_chip/block/*.rb" , /base_chip\/blocks\/(\w+)\.rb$/ , :block ) end
|
370
|
+
def discover_configurations ; file_glob("#{@directory}/base_chip/configurations/*.rb", /base_chip\/configurations\/(\w+)\.rb$/, :configuration ) end
|
371
|
+
def discover_cluster_types ; file_glob("#{@directory}/base_chip/cluster_types/*.rb" , /base_chip\/cluster_types\/(\w+)\.rb$/ , :cluster_type ) end
|
372
|
+
def use_tool(name,version)
|
373
|
+
tool :name do |t|
|
374
|
+
t.select_version version
|
375
|
+
end
|
376
|
+
end
|
377
|
+
attr_reader :registered_modes
|
378
|
+
def register_mode(name)
|
379
|
+
@registered_modes ||= []
|
380
|
+
@registered_modes << name.to_s
|
381
|
+
end
|
382
|
+
def default_modes
|
383
|
+
%w{ coverage gates fast debug profiling }.each { |m| register_mode m }
|
384
|
+
end
|
385
|
+
def configure
|
386
|
+
return if @configured
|
387
|
+
@directory = BaseChip.root
|
388
|
+
@modes += BaseChip.options.modes.split(/,/) if BaseChip.options.modes
|
389
|
+
super
|
390
|
+
@modes.each do |name|
|
391
|
+
fault "Attempted to call mode '#{name}', which isn't registered with the project. Call register_mode(#{name}) in project.rb to allow. Valid modes are #{project.registered_modes}" unless project.registered_modes.include? name.to_s
|
392
|
+
end
|
393
|
+
if self.blocks
|
394
|
+
@directory_prefix = figure_directory_prefix
|
395
|
+
@block_names = self.blocks.keys
|
396
|
+
end
|
397
|
+
end
|
398
|
+
def dereference_clusters
|
399
|
+
return nil unless cluster_names = BaseChip.options.jobs
|
400
|
+
configure
|
401
|
+
fault "Cluster submission attempted, but no cluster types are configured." unless @cluster_types
|
402
|
+
@dereferenced = []
|
403
|
+
cluster_names = cluster_names.split(/,/)
|
404
|
+
cluster_names.each do |cn|
|
405
|
+
type = nil
|
406
|
+
cluster = nil
|
407
|
+
jobs = nil
|
408
|
+
cn_orig = cn
|
409
|
+
clusters = []
|
410
|
+
|
411
|
+
if cn.sub!(/^(\d+)(?::|$)/,'')
|
412
|
+
jobs = $1.to_i
|
413
|
+
end
|
414
|
+
if cn.sub!(/:(\d+)$/,'')
|
415
|
+
fault "Multiple counts found in '#{cn_orig}'. Separate multiple cluster specifiers with commas." if jobs
|
416
|
+
jobs = $1.to_i
|
417
|
+
end
|
418
|
+
|
419
|
+
case cn
|
420
|
+
when /^([^:]+):([^:]+)$/
|
421
|
+
cluster = $2
|
422
|
+
if $1 == 'all' || $1 == ''
|
423
|
+
cluster_types.each_value do |cluster_type|
|
424
|
+
clusters += cluster_type.dereference(cluster,jobs,true)
|
425
|
+
end
|
426
|
+
elsif cluster_type = @cluster_types[$1.to_sym]
|
427
|
+
clusters += cluster_type.dereference(cluster,jobs,false)
|
428
|
+
else
|
429
|
+
fault "Could not find cluster type '#{$1}' in cluster specifier '#{cn_orig}'." if jobs
|
430
|
+
end
|
431
|
+
when /^([^:]+)$/
|
432
|
+
if cluster_type = @cluster_types[$1.to_sym]
|
433
|
+
clusters += cluster_type.dereference('all',jobs,true)
|
434
|
+
else
|
435
|
+
cluster_types.each_value do |cluster_type|
|
436
|
+
clusters += cluster_type.dereference('all',jobs,true)
|
437
|
+
end
|
438
|
+
end
|
439
|
+
when ''
|
440
|
+
cluster_types.each_value do |cluster_type|
|
441
|
+
clusters += cluster_type.dereference('all',jobs,true)
|
442
|
+
end
|
443
|
+
else
|
444
|
+
fault "Could not parse the cluster specifier '#{cn_orig}'." if jobs
|
445
|
+
end
|
446
|
+
fault "No clusters could be determined for the cluster specifier '#{cn_orig}'." if clusters.empty?
|
447
|
+
|
448
|
+
if cluster_order
|
449
|
+
cluster_order.each do |name|
|
450
|
+
tmp = clusters.delete_if {|c| c.full_name == "#{@name}:#{name}"}
|
451
|
+
try_add_clusters tmp, jobs
|
452
|
+
end
|
453
|
+
end
|
454
|
+
try_add_clusters clusters, jobs
|
455
|
+
end
|
456
|
+
@dereferenced
|
457
|
+
end
|
458
|
+
def try_add_clusters(clusters, jobs)
|
459
|
+
clusters.each do |c|
|
460
|
+
next if @dereferenced.include? c
|
461
|
+
c.configure
|
462
|
+
fault "could not determine number of jobs to run in cluster '#{c.full_name}'. Consider setting a default for this cluster." unless (c.default_jobs || c.maximum_jobs || jobs)
|
463
|
+
if (c.default_jobs || c.maximum_jobs) == nil; c.slots = jobs
|
464
|
+
elsif jobs.nil? ; c.slots = c.default_jobs || c.maximum_jobs
|
465
|
+
elsif jobs > c.maximum_jobs ; c.slots = c.maximum_jobs
|
466
|
+
else c.slots = jobs
|
467
|
+
end
|
468
|
+
@dereferenced << c
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
@@ -0,0 +1,26 @@
|
|
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
|
+
class Requirement
|
19
|
+
include Dsl
|
20
|
+
include Base
|
21
|
+
|
22
|
+
def configure
|
23
|
+
@configure = true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,36 @@
|
|
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/track_state'
|
18
|
+
require 'base_chip/taskable'
|
19
|
+
|
20
|
+
module BaseChip
|
21
|
+
module Runable
|
22
|
+
def self.included mod
|
23
|
+
mod.extend Runable::ClassMethods
|
24
|
+
mod.class_eval do
|
25
|
+
include Runable::InstanceMethods
|
26
|
+
include Taskable
|
27
|
+
include TrackState
|
28
|
+
attr_accessor :cl_args
|
29
|
+
end
|
30
|
+
end
|
31
|
+
module ClassMethods
|
32
|
+
end
|
33
|
+
module InstanceMethods
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,40 @@
|
|
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
|
+
class SourceLanguage
|
19
|
+
include Dsl
|
20
|
+
include Base
|
21
|
+
define_settings({:directories => [ Array ],
|
22
|
+
:globs => [ Array ],
|
23
|
+
:files => [ Array ]})
|
24
|
+
|
25
|
+
def configure
|
26
|
+
return if @configured
|
27
|
+
super
|
28
|
+
if @globs and @directories and not @files
|
29
|
+
@files = []
|
30
|
+
@globs.each do |e|
|
31
|
+
@directories.each do |d|
|
32
|
+
d = absolute_path d
|
33
|
+
@files += Dir.glob("#{d}/#{e}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
# @files.uniq!
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,24 @@
|
|
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/source_language'
|
18
|
+
module BaseChip
|
19
|
+
class SourceType
|
20
|
+
include Dsl
|
21
|
+
include Base
|
22
|
+
define_children({:source_language => SourceLanguage })
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
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
|
+
class Statistic
|
19
|
+
include Dsl
|
20
|
+
include Base
|
21
|
+
define_settings({:regex => [Regexp , Array],
|
22
|
+
:error_if_missing => [Boolean ],
|
23
|
+
:per_state => [Boolean ],
|
24
|
+
:across_states => [Boolean ],
|
25
|
+
:for_states => [String , Array]})
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
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
|
+
class Task
|
19
|
+
include Taskable
|
20
|
+
end
|
21
|
+
end
|