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,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
|