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,309 @@
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 'zlib'
18
+ require 'base_chip/runable'
19
+ require 'base_chip/statistic'
20
+ require 'base_chip/out_file'
21
+
22
+ module BaseChip
23
+ class Action
24
+ include Taskable
25
+ include TrackState
26
+ include Runable
27
+ include Dsl
28
+ include Base
29
+
30
+ define_settings({:zip_failing_action => [ Boolean ],
31
+ :zip_passing_action => [ Boolean ],
32
+ :clean_passing_action => [ Boolean ],
33
+ :run_action_in_tmp => [ Boolean ],
34
+ :depends => [ String , Array, Symbol ],
35
+ :before => [ Proc ],
36
+ :after => [ Proc ],
37
+ :environment => [ Hash ],
38
+ :command => [ String ],
39
+ :command_prefix => [ String ],
40
+ :command_suffix => [ String ],
41
+ :pre_commands => [ Array ],
42
+ :post_commands => [ Array ],
43
+ :name_regex => [ Regexp ],
44
+ :seed_options => [ String , Array ],
45
+ :args => [ String ],
46
+ :log_to => [ String ],
47
+ :stdout_to => [ String ],
48
+ :stderr_to => [ String ],
49
+ :echo_stdin => [ Boolean ],
50
+ :needs_clobber => [ Boolean ],
51
+ :clean_proc => [ Proc ]})
52
+
53
+ define_children({:out_file => OutFile })
54
+
55
+ def configure
56
+ return if @configured
57
+ unless @test
58
+ @bundle_name ||= if BaseChip.options.random_bundle_names
59
+ random_string
60
+ else
61
+ @name.to_s
62
+ end
63
+ @directory ||= @configuration.out_directory + "/#{@bundle_name}"
64
+ end
65
+ super
66
+ end
67
+ def run
68
+ if @run_action_in_tmp
69
+ bundle_name = random_string
70
+ run_directory = "/tmp/#{bundle_name}"
71
+ else
72
+ bundle_name = @bundle_name
73
+ run_directory = @directory
74
+ end
75
+ FileUtils.rm_rf run_directory
76
+ FileUtils.mkdir_p run_directory
77
+ Dir.pushd run_directory
78
+
79
+ File.open('seed','w') do |f|
80
+ f.write random_generator.seed
81
+ end
82
+ File.open('rerun.yaml','w') do |f|
83
+ f.write rerun_data.to_yaml
84
+ end
85
+
86
+ # Where the magic happens
87
+ inner_run
88
+
89
+ FileUtils.touch "#{run_directory}/.fail_detected" unless self.pass?
90
+
91
+ Dir.chdir '..'
92
+ if (@clean_passing_action && pass? && !@foreground)
93
+ FileUtils.rm_rf run_directory
94
+ else
95
+ bundle_tgz = nil
96
+ if @zip_failing_action || (@zip_passing_action && pass?)
97
+ bundle_tgz = run_directory + ".tgz"
98
+ @bundle_tgz = @directory + ".tgz"
99
+ tgz = Zlib::GzipWriter.new(File.open(bundle_tgz, 'wb'))
100
+ Archive::Tar::Minitar.pack(bundle_name, tgz)
101
+ FileUtils.rm_rf bundle_name
102
+ end
103
+ if @run_action_in_tmp
104
+ FileUtils.mkdir_p "#{@directory}/.."
105
+ FileUtils.mv((bundle_tgz || run_directory), "#{@directory}/..")
106
+ end
107
+ end
108
+
109
+ puts "Debug information here: #{@bundle_tgz || @directory}" if @foreground
110
+
111
+ # p @totals if @foreground
112
+ Dir.popd
113
+ end
114
+ def inner_run
115
+ # puts "#{full_name} started"
116
+ script_file = "#{@name}.bash"
117
+ script = File.open(script_file,'w')
118
+ script.puts "#!/bin/bash"
119
+ # $environment.each do |n,v|
120
+ # script.puts "export #{n}=#{v}"
121
+ # end
122
+ if @environment
123
+ @environment.each do |n,v|
124
+ script.puts "export #{n}=#{v}"
125
+ end
126
+ end
127
+
128
+ script.puts "NAME=#{@name}"
129
+ script.puts "BLOCK=#{@block.name}"
130
+ if @args
131
+ script.puts "ARGS='#{@args.gsub(/'/,"\\'")}'"
132
+ end
133
+
134
+ # FIXME fault if commands and command both exist
135
+ if @commands
136
+ script.puts @commands
137
+ elsif @command
138
+ script.puts @pre_commands if @pre_commands
139
+ script.puts "#{@command_prefix} #{@command} #{@command_suffix} $*"
140
+ script.puts @post_commands if @post_commands
141
+ else
142
+ fault "Action #{@name} has no command(s) specified to run"
143
+ end
144
+
145
+ script.chmod 0777
146
+ script.close
147
+ process_status = nil
148
+ errmsg = ''
149
+
150
+ STDOUT.sync = true
151
+ STDERR.sync = true
152
+
153
+ @before.call if @before
154
+
155
+ script_call = (@foreground || @log_to || @stdout_to) ? script.path : "#{script.path} > /dev/null"
156
+
157
+ log_storage = ( @log_to ) ? File.open( @log_to, 'w') : nil
158
+ stdout_storage = (@stdout_to && @stdout_to != @log_to) ? File.open(@stdout_to, 'w') : nil
159
+ stderr_storage = (@stderr_to && @stderr_to != @log_to) ? File.open(@stderr_to, 'w') : nil
160
+
161
+ # stdin, stdout, stderr, wait_thr = Open3.popen3([env,] cmd... [, opts])
162
+ Open3.popen3(script_call) do |stdin, stdout, stderr, wait_thr|
163
+
164
+ to = Thread.new(stdout) do |pipe|
165
+ out_data = nil
166
+ loop do
167
+ begin
168
+ out_data = pipe.readpartial(4096)
169
+ rescue EOFError, IOError
170
+ break
171
+ end
172
+ STDOUT.print out_data if @foreground
173
+ log_storage.print out_data if log_storage
174
+ stderr_storage.print out_data if stderr_storage
175
+ end
176
+ end
177
+ ti = Thread.new(STDIN) do |pipe|
178
+ in_data = nil
179
+ loop do
180
+ begin
181
+ in_data = pipe.readpartial(4096)
182
+ rescue EOFError, IOError
183
+ break
184
+ end
185
+ stdin.print in_data if @foreground && !stdin.closed?
186
+ if @echo_stdin
187
+ STDOUT.print in_data if @foreground
188
+ log_storage.print in_data if log_storage
189
+ stderr_storage.print in_data if stdout_storage
190
+ end
191
+ end
192
+ end
193
+ te = Thread.new(stderr) do |pipe|
194
+ err_data = nil
195
+ loop do
196
+ begin
197
+ err_data = pipe.readpartial(4096)
198
+ rescue EOFError, IOError
199
+ break
200
+ end
201
+ errmsg += err_data
202
+ STDERR.print err_data if @foreground
203
+ log_storage.print err_data if log_storage
204
+ stderr_storage.print err_data if stderr_storage
205
+ end
206
+ end
207
+
208
+ begin
209
+ wait_thr.join
210
+ if @foreground
211
+ ti.kill
212
+ to.kill unless te.join(10)
213
+ end
214
+ te .kill unless te.join(10)
215
+ rescue Interrupt
216
+ if @foreground # && @int_for_shell
217
+ Process.kill 'INT', wait_thr.pid
218
+ retry
219
+ else
220
+ raise
221
+ end
222
+ end
223
+ process_status = wait_thr.value # Process::Status object returned.
224
+ end
225
+
226
+ log_storage.close if log_storage
227
+ stdout_storage.close if stdout_storage
228
+ stderr_storage.close if stderr_storage
229
+
230
+ @after.call if @after
231
+
232
+ statistics = {}
233
+ totals = {}
234
+ if @out_files
235
+ @out_files.each_value do |f|
236
+ f.go(@name)
237
+
238
+ take_state(f)
239
+
240
+ statistics.merge! f.statistics if f.statistics
241
+ totals .merge! f.totals if f.totals
242
+
243
+ # warning!(pf,ps) if f.warning?
244
+ # error!( pf,ps) if f.error?
245
+ # fault!( pf,ps) if f.fault?
246
+ end
247
+ end
248
+ error!(nil, errmsg) if !process_status.success? || errmsg.size > 0
249
+
250
+ @state ||= 'pass'
251
+ @state = 'fail' unless self.pass? # state is error, warning or fault up to this point
252
+
253
+ # puts "log file produced #{totals}"
254
+ totals.each do |k,v|
255
+ if statistics[k].for_states.include? @state
256
+ if statistics[k].across_states
257
+ @totals[k] = v
258
+ end
259
+ if statistics[k].per_state
260
+ @totals["#{@state}_#{k}"] = v
261
+ end
262
+ # FIXME error_if_missing
263
+ end
264
+ end
265
+ # puts "we collected #{@totals}"
266
+
267
+ unless pass?
268
+ @problem.bundle=(@bundle_tgz || @directory)
269
+ # error(@problem.to_s)
270
+ end
271
+ # puts "#{full_name} ended"
272
+ end
273
+
274
+ def clean
275
+ return if @needs_clobber
276
+ clobber
277
+ end
278
+ def clobber
279
+ @clean_proc.call(self) if @clean_proc
280
+ FileUtils.rm_rf @directory
281
+ FileUtils.rm_rf "#{@directory}.tgz"
282
+ end
283
+
284
+ attr_writer :random_generator
285
+ def random_generator
286
+ @random_generator ||= BaseChip.new_random_generator
287
+ end
288
+ def generate_seed(format, bits=32)
289
+ case format
290
+ when :num
291
+ @random_generator.rand(2 ** bits)
292
+ when :hex
293
+ (@random_generator.rand(2 ** bits)).to_hex
294
+ when :dec
295
+ (@random_generator.rand(2 ** bits)).to_s
296
+ when :alphanumeric
297
+ random_string(bits)
298
+ end
299
+ end
300
+
301
+ def rerun_data
302
+ { 'full_name' => full_name ,
303
+ 'seed' => random_generator.seed ,
304
+ 'modes' => modes ,
305
+ 'append_arguments' => BaseChip.options. append_arguments ,
306
+ 'replace_arguments' => BaseChip.options.replace_arguments }
307
+ end
308
+ end
309
+ end
@@ -0,0 +1,105 @@
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 'reporting'
18
+ module BaseChip
19
+ module Base
20
+ def self.included mod
21
+ mod.extend Base::ClassMethods
22
+ mod.class_eval do
23
+ include Reporting
24
+ include Base::InstanceMethods
25
+
26
+ define_setting :directory, [ String ]
27
+
28
+ # chain together projects, blocks, and actions
29
+ attr_reader :project
30
+ attr_reader :block
31
+ attr_reader :configuration
32
+ attr_reader :action
33
+ attr_reader :test_list
34
+ attr_reader :test
35
+ attr_reader :tool
36
+ attr_reader :version
37
+ attr_reader :source_type
38
+ attr_reader :source_language
39
+ end
40
+ end
41
+ module ClassMethods
42
+ end
43
+ module InstanceMethods
44
+ def parent=(parent); @parent = parent; update_chaining; end
45
+ def foster=(parent); @foster = parent; update_chaining; end
46
+ def update_chaining
47
+ # chain blocks, projects, and actions together
48
+ @project ||= (self.is_a? BaseChip::Project ) ? self : ((parent.project if parent) || (foster.project if foster))
49
+ @block ||= (self.is_a? BaseChip::Block ) ? self : ((parent.block if parent) || (foster.block if foster))
50
+ @configuration ||= (self.is_a? BaseChip::Configuration ) ? self : ((parent.configuration if parent) || (foster.configuration if foster))
51
+ @action ||= (self.is_a? BaseChip::Action ) ? self : ((parent.action if parent) || (foster.action if foster))
52
+ @test_list ||= (self.is_a? BaseChip::TestList ) ? self : ((parent.test_list if parent) || (foster.test_list if foster))
53
+ @test ||= (self.is_a? BaseChip::Test ) ? self : ((parent.test if parent) || (foster.test if foster))
54
+ @tool ||= (self.is_a? BaseChip::Tool ) ? self : ((parent.tool if parent) || (foster.tool if foster))
55
+ @tool_version ||= (self.is_a? BaseChip::ToolVersion ) ? self : ((parent.tool_version if parent) || (foster.tool_version if foster))
56
+ @source_type ||= (self.is_a? BaseChip::SourceType ) ? self : ((parent.source_type if parent) || (foster.source_type if foster))
57
+ @source_language ||= (self.is_a? BaseChip::SourceLanguage) ? self : ((parent.source_language if parent) || (foster.source_language if foster))
58
+ end
59
+
60
+ def configure
61
+ return if @configured
62
+ super
63
+ # if self.class.children_types.keys.include?(:tool) && self.tools
64
+ # self.tools.each_value do |t|
65
+ # t.configure
66
+ # t.selected_version.configure
67
+ # t.selected_version.actions.each do |n,a|
68
+ # self.actions ||= {}
69
+ # if self.actions[n]
70
+ # self.actions[n].blks = a.blks + self.actions[n].blks
71
+ # self.actions[n].foster ||= a.parent
72
+ # else
73
+ # self.actions[n] = a.clone
74
+ # self.actions[n].blks = self.actions[n].blks.dup
75
+ # self.actions[n].foster = a.parent
76
+ # self.actions[n].parent = self
77
+ # end
78
+ # end
79
+ # end
80
+ # end
81
+ end
82
+
83
+ def discover_configurations
84
+ Dir.glob("#{BaseChip.root}/*/base_chip/configuration.rb").each do |f|
85
+ if f =~ /(\w+)\/base_chip\/configuration\.rb$/
86
+ self.block($1.to_sym) {|b| b.file f}
87
+ end
88
+ end
89
+ end
90
+ def file_glob(glob, regex = nil, type = nil)
91
+ Dir.glob(glob).each do |f|
92
+ if regex
93
+ if f =~ regex
94
+ self.send(type, $1.to_sym) { |t| t.file(f) }
95
+ else
96
+ fault "fileglob '#{glob}' did not match regex /#{regex}/ in #{self.name}"
97
+ end
98
+ else
99
+ self.file(f)
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,75 @@
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/configuration'
18
+
19
+ module BaseChip
20
+ class Block
21
+ include Dsl
22
+ include Base
23
+ include Hierarchy
24
+ define_children({:configuration => Configuration})
25
+
26
+ def configuration_dereference(name,names,passive)
27
+ if configuration = @configurations[name]
28
+ configuration.configure
29
+ configuration.dereference_workload(names,passive)
30
+ elsif passive
31
+ []
32
+ else
33
+ fault "Could not find configuration #{name} in block #{@name}" # FIXME say who wanted it, and if shortcut occurred
34
+ end
35
+ end
36
+ def dereference_workload(names = nil,passive=false)
37
+ configure
38
+ fault "No configurations specified for block #{@name}" unless @configurations # || passive || names.nil?
39
+ names ||= ['all']
40
+ out = Array.new
41
+ names.each do |n|
42
+ n = n.to_s
43
+ case n
44
+ when 'all', 'gate', 'upgate', 'downgate', 'diffgate' # FIXME , 'alltests', 'allactions'
45
+ next unless @configurations
46
+ @configurations.keys.each { |k| out += configuration_dereference(k,[n],true) }
47
+ when /^all:(.*)$/
48
+ next unless @configurations
49
+ tmp = $1
50
+ @configurations.keys.each { |k| out += configuration_dereference(k,[tmp],true) }
51
+ when /^([^:]*?):(.*)$/
52
+ out += configuration_dereference($1.to_sym,[$2],passive)
53
+ else
54
+ fault "No configurations specified for block #{@name}" unless @configurations || passive
55
+ if @configurations[:default]
56
+ out += configuration_dereference(:default,[n],passive)
57
+ elsif @configurations.size == 1
58
+ out += configuration_dereference(@configurations.keys[0],[n],passive)
59
+ end
60
+ end
61
+ end
62
+ out.uniq!
63
+ out
64
+ end
65
+
66
+ def shortcut(name, array)
67
+ @shortcuts ||= {}
68
+ @shortcuts[name] = array
69
+ end
70
+
71
+ def discover_configurations ; file_glob("#{@directory}/*/base_chip/configuration.rb" , /(\w+)\/base_chip\/configuration\.rb$/ , :configuration)
72
+ file_glob("#{@directory}/base_chip/configurations/*.rb", /base_chip\/configurations\/(\w+)\.rb$/, :configuration) end
73
+
74
+ end
75
+ end
@@ -0,0 +1,75 @@
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/bom_file'
18
+
19
+ class Hash
20
+ def deep_values
21
+ self.values.map do |v|
22
+ if v.respond_to? :values
23
+ v.values
24
+ else
25
+ v
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ module BaseChip
32
+ class Bom
33
+ attr_reader :hash
34
+ attr_reader :name1
35
+ attr_reader :name2
36
+ def initialize(hash)
37
+ @hash = hash.with_indifferent_access
38
+ @name1 = 'all'
39
+ @name2 = 'all'
40
+ end
41
+ def verilog ; @verilog ||= trim(2,:verilog ) end
42
+ def classes ; @classes ||= trim(2,:classes ) end
43
+ def vhdl ; @vhdl ||= trim(2,:vhdl ) end
44
+ def systemc ; @systemc ||= trim(2,:systemc ) end
45
+ def headers ; @headers ||= trim(2,:headers ) end
46
+
47
+ def rtl ; @rtl ||= trim(1,:rtl ) end
48
+ def gates ; @gates ||= trim(1,:gates ) end
49
+ def testbench ; @testbench ||= trim(1,:testbench) end
50
+ def stimulus ; @stimulus ||= trim(1,:stimulus ) end
51
+
52
+ def to_a ; @to_a ||= @hash.deep_values.flatten; end
53
+ def list ; @list ||= to_a.join(' ') ; end
54
+ def to_s ; @to_s ||= list ; end
55
+
56
+ def +(bom)
57
+ Bom.new(@hash.merge bom.hash)
58
+ end
59
+
60
+ protected
61
+ def trim(depth,key)
62
+ hash = HashWithIndifferentAccess.new
63
+ @hash.each do |k1,l1|
64
+ case depth
65
+ when 1; hash[k1] = l1 if k1.to_s == key.to_s
66
+ when 2; hash[k1] = tmp = HashWithIndifferentAccess.new
67
+ l1.each do |k2,l2|
68
+ tmp[k2] = l2 if k2.to_s == key.to_s
69
+ end
70
+ end
71
+ end
72
+ Bom.new(hash)
73
+ end
74
+ end
75
+ 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
+ module BaseChip
18
+ class BomType
19
+ def initialize(bom,type)
20
+ @bom = bom
21
+ @type = type
22
+ end
23
+ def to_s
24
+ "#{@bom.name1}.#{@bom.name2}.#{@type}"
25
+ end
26
+ def make
27
+ f = File.open(to_s,'w')
28
+ case @type
29
+ when :text ; f.puts @bom.to_a.join("\n")
30
+ when :tcl ; fault "TCL formatted bom files not yet implemented"
31
+ else ; fault "#{@type.inspect} was not understood by #{self.class}"
32
+ end
33
+ f.close
34
+ end
35
+ end
36
+
37
+ class Bom
38
+ def text
39
+ @text ||= BomType.new(self,:text)
40
+ end
41
+ def tcl
42
+ @tcl ||= BomType.new(self,:tcl )
43
+ end
44
+ end
45
+ end