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.
Files changed (61) hide show
  1. data/.document +5 -0
  2. data/Gemfile +20 -0
  3. data/Gemfile.lock +32 -0
  4. data/LICENSE.txt +14 -0
  5. data/README.rdoc +19 -0
  6. data/VERSION +1 -0
  7. data/bin/basechip +25 -0
  8. data/collateral/block/block.rb.erb +20 -0
  9. data/collateral/configuration/configuration.rb.erb +19 -0
  10. data/collateral/project/Gemfile +19 -0
  11. data/collateral/project/gitignore +6 -0
  12. data/collateral/project/project.rb.erb +76 -0
  13. data/collateral/project/settings.rb.erb +26 -0
  14. data/collateral/recipes/icarus.rb +73 -0
  15. data/collateral/recipes/icarus.rb.erb +88 -0
  16. data/collateral/recipes/local_cluster.rb +27 -0
  17. data/lib/array.rb +26 -0
  18. data/lib/base_chip/action.rb +309 -0
  19. data/lib/base_chip/base.rb +105 -0
  20. data/lib/base_chip/block.rb +75 -0
  21. data/lib/base_chip/bom.rb +75 -0
  22. data/lib/base_chip/bom_file.rb +45 -0
  23. data/lib/base_chip/cli.rb +371 -0
  24. data/lib/base_chip/cluster.rb +93 -0
  25. data/lib/base_chip/cluster_type.rb +45 -0
  26. data/lib/base_chip/code_area.rb +30 -0
  27. data/lib/base_chip/configuration.rb +257 -0
  28. data/lib/base_chip/dsl.rb +593 -0
  29. data/lib/base_chip/exit_error.rb +20 -0
  30. data/lib/base_chip/generator_menu.rb +64 -0
  31. data/lib/base_chip/git.rb +32 -0
  32. data/lib/base_chip/hierarchy.rb +84 -0
  33. data/lib/base_chip/install_menu.rb +89 -0
  34. data/lib/base_chip/ipc.rb +50 -0
  35. data/lib/base_chip/list_menu.rb +134 -0
  36. data/lib/base_chip/menu.rb +70 -0
  37. data/lib/base_chip/out_file.rb +68 -0
  38. data/lib/base_chip/permutation.rb +26 -0
  39. data/lib/base_chip/permute.rb +25 -0
  40. data/lib/base_chip/post.rb +26 -0
  41. data/lib/base_chip/problem.rb +33 -0
  42. data/lib/base_chip/project.rb +472 -0
  43. data/lib/base_chip/requirement.rb +26 -0
  44. data/lib/base_chip/runable.rb +36 -0
  45. data/lib/base_chip/source_language.rb +40 -0
  46. data/lib/base_chip/source_type.rb +24 -0
  47. data/lib/base_chip/statistic.rb +27 -0
  48. data/lib/base_chip/task.rb +21 -0
  49. data/lib/base_chip/task_master.rb +50 -0
  50. data/lib/base_chip/taskable.rb +77 -0
  51. data/lib/base_chip/tasker.rb +260 -0
  52. data/lib/base_chip/test.rb +202 -0
  53. data/lib/base_chip/test_list.rb +120 -0
  54. data/lib/base_chip/tool.rb +51 -0
  55. data/lib/base_chip/tool_version.rb +34 -0
  56. data/lib/base_chip/top_menu.rb +203 -0
  57. data/lib/base_chip/track_state.rb +61 -0
  58. data/lib/base_chip.rb +215 -0
  59. data/lib/dir.rb +30 -0
  60. data/lib/reporting.rb +97 -0
  61. metadata +215 -0
@@ -0,0 +1,371 @@
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 'ostruct'
18
+ require 'reporting'
19
+ class String
20
+ def titleize!
21
+ self.downcase!
22
+ self.gsub!(/_/, ' ')
23
+ self.gsub!(/(^| )([a-z])/) do
24
+ $1+$2.upcase
25
+ end
26
+ self
27
+ end
28
+ def titleize
29
+ self.dup.titleize!
30
+ end
31
+ def modelize!
32
+ self[0] = self[0].downcase
33
+ self.gsub!(/([A-Z])/) do
34
+ "_#{$1.downcase}"
35
+ end
36
+ self
37
+ end
38
+ def modelize
39
+ self.dup.modelize!
40
+ end
41
+ end
42
+ module BaseChip
43
+ module Cli
44
+ def self.included mod
45
+ mod.extend Cli::ClassMethods
46
+ mod.class_eval do
47
+ include BaseChip::Reporting
48
+ include Cli::InstanceMethods
49
+
50
+ @cli = Cli::Data.new
51
+
52
+ desc "Show usage information"
53
+ example ""
54
+ example " #{cli.tasks[1]}" if cli.tasks[1]
55
+ def help(command = nil,*subcommands)
56
+ puts ''
57
+ if command
58
+ command = command.to_sym
59
+ if (sc = cli.sub_commands[command])
60
+ sc.new.help(*subcommands)
61
+ return
62
+ elsif t_cli = cli.tasks[command]
63
+ puts "#{cli.full_command(command)} #{t_cli.usage}:"
64
+ else
65
+ fault "could not find help topic \"#{command}\""
66
+ end
67
+ else
68
+ t_cli = cli
69
+
70
+ puts "#{cli.full_command(command,false)}: "
71
+ end
72
+
73
+ if t_cli.description
74
+ puts ''
75
+ puts " #{t_cli.description}"
76
+ end
77
+ if t_cli.long_description
78
+ puts ''
79
+ puts " #{t_cli.long_description}"
80
+ end
81
+
82
+ unless command
83
+ array = []
84
+ cli.tasks.each_value do |t|
85
+ if t.full_usage
86
+ array << [t.full_usage ,t.description]
87
+ else
88
+ array << ["#{cli.full_command(t.name.to_s)} #{t.usage}",t.description]
89
+ end
90
+ end
91
+ cli.sub_commands.each do |name,sc|
92
+ array << ["#{sc.cli.full_command(nil,'false')} #{name} ...",sc.cli.description]
93
+ end
94
+ puts ''
95
+ puts " Commands:"
96
+ cli.table(array,nil," ")
97
+
98
+ end
99
+
100
+ t_cli.options_table
101
+ puts ''
102
+ end
103
+ end
104
+ end
105
+ class TaskOrData
106
+ include BaseChip::Reporting
107
+
108
+ attr_accessor :name
109
+ attr_accessor :options
110
+ attr_accessor :description
111
+ attr_accessor :long_description
112
+ def initialize
113
+ @options = {}
114
+ end
115
+ def s2o(arg)
116
+ arg = arg.to_s
117
+ arg = (arg.length > 1 ? '--' : '-') + arg
118
+ arg.gsub!(/_/,'-')
119
+ arg
120
+ end
121
+ def option(name,hash)
122
+ hash.merge! :name=>name
123
+ @options[s2o name] = hash
124
+ if hash[:alias]
125
+ hash[:alias].each do |a|
126
+ @options[s2o a] = hash
127
+ end
128
+ end
129
+ end
130
+ def option_usage(o)
131
+ name = s2o o[:name]
132
+ alt = o[:alias] ? " (#{ o[:alias].map{|a|s2o a}.join('|') })" : ''
133
+ case o[:type]
134
+ when :boolean; return name + alt
135
+ else return "#{name}#{alt} <#{o[:type]}>"
136
+ end
137
+ end
138
+ def options_table
139
+ return if self.options.size == 0
140
+ array = []
141
+ self.options.values.uniq.each do |t|
142
+ array << [self.option_usage(t),t[:description]]
143
+ end
144
+ puts ''
145
+ puts " #{ self.name ? self.name.to_s.titleize : 'Global' } Options:"
146
+ table(array,nil," ")
147
+ end
148
+ def mine_options(ostruct, arguments, unknown_check = false)
149
+ found = true
150
+ while found
151
+ found = false
152
+ arguments.size.times do |i|
153
+ a = arguments[i]
154
+ case a
155
+ when *(self.options.keys.map{|k|k.to_s})
156
+ h = self.options[a]
157
+ case h[:type]
158
+ when :boolean; ostruct.send("#{h[:name]}=",true )
159
+ when :string ; ostruct.send("#{h[:name]}=",arguments[i+1].to_s); arguments.delete_at(i+1) # TODO error if i+1 doesn't exist
160
+ when :integer; ostruct.send("#{h[:name]}=",arguments[i+1].to_i); arguments.delete_at(i+1) # TODO error if i+1 doesn't exist
161
+ end
162
+ arguments.delete_at(i)
163
+ found = true
164
+ break
165
+ end
166
+ end
167
+ end
168
+ if unknown_check
169
+ arguments.each do |a|
170
+ fault "#{self.name || 'base_chip'} didn't understand the option #{a}" if a =~ /^\-/
171
+ end
172
+ end
173
+ end
174
+ def table(array,delimiter=' : ',indent='')
175
+ delimiter ||= ' : '
176
+ widths = []
177
+ array.each do |array2|
178
+ array2.size.times do |i|
179
+ widths[i] ||= 0
180
+ array2[i] ||= ''
181
+ len = array2[i].length + 2
182
+ widths[i] = len if widths[i] < len
183
+ end
184
+ end
185
+ format = indent + widths.map{ |w| "%-#{w}s" }.join(delimiter)
186
+ array.each do |array2|
187
+ puts format % array2
188
+ end
189
+ end
190
+ end
191
+ class Task < TaskOrData
192
+ attr_accessor :usage
193
+ attr_accessor :full_usage
194
+ attr_accessor :examples
195
+ attr_accessor :required_argument_size
196
+ def initialize
197
+ super
198
+ @examples = []
199
+ end
200
+ end
201
+ class Data < TaskOrData
202
+ attr_accessor :map
203
+ attr_accessor :current_task
204
+ attr_accessor :default_task
205
+ attr_accessor :tasks
206
+
207
+ attr_accessor :parent_command
208
+ attr_accessor :sub_commands
209
+ def initialize
210
+ super
211
+ @map = {}
212
+ @sub_commands = {}
213
+ @tasks = {}
214
+ @current_task = self
215
+ @default_task = nil
216
+ end
217
+ def save_task(name,prc)
218
+ return if self == @current_task
219
+ @current_task.required_argument_size = 0
220
+ @current_task.usage ||=
221
+ prc.parameters.map do |pa|
222
+ case pa[0]
223
+ when :req ; @current_task.required_argument_size += 1 ; "<#{pa[1]}>"
224
+ when :opt ; "[#{pa[1]}]"
225
+ when :rest ; "[#{pa[1]}]+"
226
+ end
227
+ end.join(' ') + ' [options]'
228
+ @current_task.name = name
229
+ @tasks[name] = @current_task
230
+ @current_task = self
231
+ end
232
+ def sub_command(name,klass)
233
+ @sub_commands[name] = klass
234
+ klass.cli.parent_command = self
235
+ klass.cli.name = name
236
+ klass.cli.description = @current_task.description
237
+ klass.cli.long_description = @current_task.long_description
238
+ @current_task = self
239
+ end
240
+ def full_command(task = nil, with_options=true)
241
+ task = task.to_s if task
242
+ n = if self.parent_command
243
+ self.parent_command.full_command((task.nil? ? nil : self.name),with_options)
244
+ else
245
+ File.basename($0)
246
+ end
247
+ if task
248
+ n + ' ' + task
249
+ else
250
+ n
251
+ end
252
+ end
253
+ end
254
+ module ClassMethods
255
+ def cli=(a); @cli = a end; def cli; @cli end; @cli = Cli::Data.new
256
+ def options; BaseChip.options end
257
+
258
+ # documentation routines
259
+ def desc(description, usage=nil)
260
+ cli.current_task = Cli::Task.new
261
+ cli.current_task.description = description
262
+ end
263
+ def long(description)
264
+ cli.current_task.long_description = description
265
+ end
266
+ def usage ( usage ); cli.current_task. usage = usage end
267
+ def full_usage ( usage ); cli.current_task.full_usage = usage end
268
+ def example ( example ); cli.current_task.examples << example end
269
+ def option ( name, hash = {} ); cli.current_task.option(name, hash ) end
270
+ def sub_command ( name, klass ); cli.sub_command( name, klass) end
271
+ def default ; cli.default_task = cli.current_task end
272
+
273
+ def map ( name,rename ); cli.map[name] = rename end
274
+ def method_added(name)
275
+ cli.save_task(name,instance_method(name))
276
+ end
277
+ def first(function,hash = {})
278
+ puts "call #{function} first"
279
+ end
280
+
281
+ end
282
+ module InstanceMethods
283
+ def cli ; self.class.cli end
284
+ def options ; self.class.options end
285
+ def run_cli_no_command
286
+ puts "\nPlease specify a sub command" + ( cli.name ? " for #{cli.name}" : '' )
287
+ help
288
+ exit 1
289
+ end
290
+ def run_cli(arguments = ARGV)
291
+ run_cli_no_command if arguments.size == 0
292
+ pass_through = nil
293
+ options. append_arguments = nil
294
+ options.replace_arguments = nil
295
+ arguments.keep_if do |a|
296
+ case a
297
+ when '--' ; pass_through = (options. append_arguments ||= []); false
298
+ when '---' ; pass_through = (options.replace_arguments ||= []); false
299
+ else
300
+ if pass_through
301
+ pass_through << a
302
+ false
303
+ else
304
+ true
305
+ end
306
+ end
307
+ end
308
+ cli.options.each do |o,h|
309
+ if h[:value]
310
+ options.send("#{h[:name]}=",h[:value])
311
+ end
312
+ end
313
+ cli.mine_options(options,arguments)
314
+ arguments.size.times do |i|
315
+ case a = arguments[i].to_sym
316
+ when *(cli.sub_commands.keys)
317
+ arguments.delete_at i
318
+ cli.sub_commands[a].new.run_cli(arguments)
319
+ exit
320
+ when *(cli.tasks.keys)
321
+ arguments.delete_at i
322
+ task = cli.tasks[a]
323
+ task.mine_options(options,arguments,true)
324
+ if task.required_argument_size > arguments.size
325
+ help task.name
326
+ fault "\n#{task.name} is missing required arguments"
327
+ end
328
+ send a, *arguments
329
+ break
330
+ else
331
+ if a[0] == '-'
332
+ fault("Could not determine what to run from \"#{arguments.join(' ')}\". Please consider placing dash options at the end of the command line.")
333
+ end
334
+ task = cli.default_task or fault("Could not determine what to run from \"#{arguments.join(' ')}\".")
335
+ task.mine_options(options,arguments,true)
336
+ if task.required_argument_size > arguments.size
337
+ puts "\n#{task.name} is missing required arguments"
338
+ help task.name
339
+ exit 1
340
+ end
341
+ send task.name, *arguments
342
+ break
343
+ end
344
+ end
345
+ end
346
+ def print_table(table, delimeter="\t")
347
+ column = 0
348
+ table2 = []
349
+ sizes = []
350
+
351
+ # determine size
352
+ table.each do |row|
353
+ column = 0
354
+ table2 << row.map do |c|
355
+ tmp = c.to_s
356
+ tmpsize = tmp.size
357
+ sizes[column] = tmpsize if sizes[column].nil? or tmpsize > sizes[column]
358
+ column += 1
359
+ tmp
360
+ end
361
+ end
362
+
363
+ # map to sized columns
364
+ table2.each do |row|
365
+ column = 0
366
+ puts (row.map! { |c| "%-#{sizes[(column += 1) - 1]}s" % c }).join(" => ").strip
367
+ end
368
+ end
369
+ end
370
+ end
371
+ end
@@ -0,0 +1,93 @@
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 Cluster
19
+ include Dsl
20
+ include Base
21
+
22
+ define_settings({:foreground_allowed => [ Integer ],
23
+ :background_allowed => [ Integer ],
24
+ :maximum_jobs => [ Integer ],
25
+ :default_jobs => [ Integer ],
26
+ :id_regex => [ Regexp ],
27
+ :id_variable => [ String ],
28
+ :id_procedure => [ Proc ],
29
+ :submit_procedure => [ Proc ],
30
+ :submit_command => [ String ],
31
+ :kill_procedure => [ Proc ],
32
+ :kill_command => [ String ],
33
+ :cluster_args => [ String ]})
34
+
35
+ attr_accessor :ids
36
+ attr_accessor :slots
37
+ attr_accessor :slots_used
38
+
39
+ def initialize
40
+ super
41
+ @ids = []
42
+ @slots = 0
43
+ @slots_used = 0
44
+ end
45
+
46
+ def available_slots
47
+ @slots - @slots_used
48
+ end
49
+
50
+ def submit(command)
51
+ fault "Cluster submission requires a way to kill spawned jobs. Please specify kill_procedure or kill_command for #{full_name}" unless @kill_procedure || @kill_command
52
+
53
+ if submit_procedure
54
+ return submit_procedure.call command
55
+ elsif submit_command
56
+ output = `#{submit_command} #{command}`
57
+ if id_regex
58
+ if result = id_regex.match(output)
59
+ captures = result[1..-1]
60
+ if id = (captures.select{|c| (c!=nil) && (c!='') }.first)
61
+ @ids << id
62
+ return id
63
+ else
64
+ fault "Regex /#{id_regex}/ matched '#{result}' but no useful capture was found in output of submit_command:\n#{output}"
65
+ end
66
+ else
67
+ fault "Regex /#{id_regex}/ could not be matched in output of submit_command:\n#{output}"
68
+ end
69
+ elsif id_procedure
70
+ return id_procedure.call(output)
71
+ else
72
+ fault "job id is required for job tracking. Please specify id_regex, id_variable or id_procedure for cluster #{full_name}" unless id_variable or id_procedure
73
+ end
74
+ else
75
+ fault "No submit_procedure or submit_command defined for cluster #{full_name}"
76
+ end
77
+ end
78
+ def kill_all
79
+ @ids.each do |id|
80
+ kill id
81
+ end
82
+ end
83
+ def kill(id)
84
+ if kill_procedure
85
+ kill_procedure.call(id)
86
+ elsif kill_command
87
+ system "#{kill_command} #{id}"
88
+ else
89
+ fault "kill_procedure and kill_command for #{full_name} are both missing at time of kill. This should have been flagged on submit." unless kill_procedure or kill_command
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,45 @@
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/cluster'
18
+
19
+ module BaseChip
20
+ class ClusterType
21
+ include Dsl
22
+ include Base
23
+
24
+ define_children({:cluster => Cluster})
25
+
26
+ def dereference(name,jobs,passive)
27
+ configure
28
+ clusters = []
29
+ unless @clusters
30
+ fault "No clusters are specified for the cluster type '#{@name}'" unless passive
31
+ return clusters
32
+ end
33
+
34
+ if name == 'all' || name == ''
35
+ clusters = @clusters.values
36
+ elsif cluster = @clusters[name.to_s]
37
+ clusters << cluster
38
+ else
39
+ fault "No clusters could be found named '#{name}' of type '#{@name}'" unless passive
40
+ end
41
+
42
+ clusters
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,30 @@
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_type'
18
+
19
+ module BaseChip
20
+ class CodeArea
21
+ include Dsl
22
+ include Base
23
+ define_children({:source_type=> SourceType})
24
+ def verilog(&blk); source_type(:verilog,blk); end
25
+ def inc( &blk); source_type(:inc ,blk); end
26
+ def class( &blk); source_type(:class ,blk); end
27
+ def vhdl( &blk); source_type(:vhdl ,blk); end
28
+ def systemc(&blk); source_type(:systemc,blk); end
29
+ end
30
+ end