test_ids 1.2.3 → 1.2.4
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.
- checksums.yaml +4 -4
- data/config/application.rb +34 -34
- data/config/boot.rb +4 -2
- data/config/commands.rb +21 -19
- data/config/shared_commands.rb +5 -3
- data/config/version.rb +1 -1
- data/lib/tasks/test_ids.rake +1 -0
- data/lib/test_ids/allocator.rb +156 -150
- data/lib/test_ids/bin_array.rb +13 -12
- data/lib/test_ids/commands/clear.rb +16 -11
- data/lib/test_ids/commands/repair.rb +10 -5
- data/lib/test_ids/configuration.rb +12 -21
- data/lib/test_ids/git.rb +57 -57
- data/lib/test_ids/origen/origen.rb +3 -1
- data/lib/test_ids/origen_testers/flow.rb +9 -9
- data/lib/test_ids/shutdown_handler.rb +2 -0
- data/lib/test_ids.rb +87 -111
- data/lib/test_ids_dev/dut.rb +2 -0
- data/lib/test_ids_dev/interface.rb +3 -1
- data/program/prb1.rb +2 -0
- metadata +19 -24
data/lib/test_ids/allocator.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'json'
|
|
2
4
|
module TestIds
|
|
3
5
|
# The allocator is responsible for assigning new numbers and keeping a record of
|
|
@@ -54,7 +56,7 @@ module TestIds
|
|
|
54
56
|
rangehash = {}
|
|
55
57
|
else
|
|
56
58
|
rangehash = store['pointers']['ranges']
|
|
57
|
-
rangehash =
|
|
59
|
+
rangehash = rangehash.transform_keys(&:to_sym)
|
|
58
60
|
end
|
|
59
61
|
orig_options = options.dup
|
|
60
62
|
# Check the database to see if the passed in range has already been included in the database hash
|
|
@@ -70,18 +72,15 @@ module TestIds
|
|
|
70
72
|
# and new value is assigned to the softbin.
|
|
71
73
|
if previous_assigned_value == range[@pointer]
|
|
72
74
|
@pointer += options[:size]
|
|
73
|
-
assigned_value = range[@pointer]
|
|
74
|
-
else
|
|
75
|
-
# Because of the pointer calculations above, I don't think it will ever reach here, has not in my test cases so far!
|
|
76
|
-
assigned_value = range[@pointer]
|
|
77
75
|
end
|
|
76
|
+
assigned_value = range[@pointer]
|
|
78
77
|
# Now update the database pointers to point to the lastest assigned softbin for a given range.
|
|
79
|
-
rangehash.merge!(
|
|
78
|
+
rangehash.merge!("#{range_definition}": (range[@pointer]).to_s)
|
|
80
79
|
else
|
|
81
80
|
# This is the case for a brand new range that has not been passed before
|
|
82
81
|
# We start from the first value as the assigned softbin and update the database to reflect.
|
|
83
82
|
@pointer = 0
|
|
84
|
-
rangehash.merge!(
|
|
83
|
+
rangehash.merge!("#{range_definition}": (range[@pointer]).to_s)
|
|
85
84
|
assigned_value = range[@pointer]
|
|
86
85
|
end
|
|
87
86
|
unless !assigned_value.nil? && range.include?(assigned_value)
|
|
@@ -148,7 +147,7 @@ module TestIds
|
|
|
148
147
|
nones = []
|
|
149
148
|
|
|
150
149
|
# Record any :nones that are present for later
|
|
151
|
-
|
|
150
|
+
%i(bin softbin number).each do |type|
|
|
152
151
|
nones << type if options[type] == :none
|
|
153
152
|
config(type).allocator.instance_variable_set('@needs_regenerated', {})
|
|
154
153
|
end
|
|
@@ -176,9 +175,12 @@ module TestIds
|
|
|
176
175
|
store['assigned']['bins'] = store['assigned']['bins'].merge(other_store['assigned']['bins'])
|
|
177
176
|
store['assigned']['softbins'] = store['assigned']['softbins'].merge(other_store['assigned']['softbins'])
|
|
178
177
|
store['assigned']['numbers'] = store['assigned']['numbers'].merge(other_store['assigned']['numbers'])
|
|
179
|
-
store['manually_assigned']['bins'] =
|
|
180
|
-
|
|
181
|
-
store['manually_assigned']['
|
|
178
|
+
store['manually_assigned']['bins'] =
|
|
179
|
+
store['manually_assigned']['bins'].merge(other_store['manually_assigned']['bins'])
|
|
180
|
+
store['manually_assigned']['softbins'] =
|
|
181
|
+
store['manually_assigned']['softbins'].merge(other_store['manually_assigned']['softbins'])
|
|
182
|
+
store['manually_assigned']['numbers'] =
|
|
183
|
+
store['manually_assigned']['numbers'].merge(other_store['manually_assigned']['numbers'])
|
|
182
184
|
store['references']['bins'] = store['references']['bins'].merge(other_store['references']['bins'])
|
|
183
185
|
store['references']['softbins'] = store['references']['softbins'].merge(other_store['references']['softbins'])
|
|
184
186
|
store['references']['numbers'] = store['references']['numbers'].merge(other_store['references']['numbers'])
|
|
@@ -189,8 +191,8 @@ module TestIds
|
|
|
189
191
|
if file && File.exist?(file)
|
|
190
192
|
lines = File.readlines(file)
|
|
191
193
|
# Remove any header comment lines since these are not valid JSON
|
|
192
|
-
lines.shift while lines.first =~
|
|
193
|
-
s = JSON.
|
|
194
|
+
lines.shift while lines.first =~ %r{^//} && !lines.empty?
|
|
195
|
+
s = JSON.parse(lines.join("\n"))
|
|
194
196
|
end
|
|
195
197
|
if s
|
|
196
198
|
unless s['format_revision']
|
|
@@ -215,10 +217,14 @@ module TestIds
|
|
|
215
217
|
s = {
|
|
216
218
|
'format_revision' => 2,
|
|
217
219
|
'configuration' => nil,
|
|
218
|
-
'pointers' => { 'bins' => s['pointers']['bin'], 'softbins' => s['pointers']['softbin'],
|
|
219
|
-
|
|
220
|
-
'
|
|
221
|
-
|
|
220
|
+
'pointers' => { 'bins' => s['pointers']['bin'], 'softbins' => s['pointers']['softbin'],
|
|
221
|
+
'numbers' => s['pointers']['number'] },
|
|
222
|
+
'assigned' => { 'bins' => s['assigned']['bin'], 'softbins' => s['assigned']['softbin'],
|
|
223
|
+
'numbers' => s['assigned']['number'] },
|
|
224
|
+
'manually_assigned' => { 'bins' => s['manually_assigned']['bin'],
|
|
225
|
+
'softbins' => s['manually_assigned']['softbin'], 'numbers' => s['manually_assigned']['number'] },
|
|
226
|
+
'references' => { 'bins' => s['references']['bin'], 'softbins' => s['references']['softbin'],
|
|
227
|
+
'numbers' => s['references']['number'] }
|
|
222
228
|
}
|
|
223
229
|
end
|
|
224
230
|
|
|
@@ -239,20 +245,22 @@ module TestIds
|
|
|
239
245
|
end
|
|
240
246
|
end
|
|
241
247
|
|
|
242
|
-
|
|
248
|
+
# disable lint check combination loop as we prefer how the output looks like
|
|
249
|
+
# rubocop:disable Style/CombinableLoops
|
|
250
|
+
def repair(_options = {})
|
|
243
251
|
#####################################################################
|
|
244
252
|
# Add any numbers that are missing from the references pool if the
|
|
245
253
|
# allocator has moved onto the reclamation phase
|
|
246
254
|
#####################################################################
|
|
247
255
|
{ 'bins' => 'bins', 'softbins' => 'softbins', 'numbers' => 'test_numbers' }.each do |type, name|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
+
next unless !config.send(type).function? && store['pointers'][type] == 'done'
|
|
257
|
+
|
|
258
|
+
Origen.log.info "Checking for missing #{name}..."
|
|
259
|
+
recovered = add_missing_references(config.send, store['references'][type])
|
|
260
|
+
if recovered.zero?
|
|
261
|
+
Origen.log.info " All #{name} are already available."
|
|
262
|
+
else
|
|
263
|
+
Origen.log.success " Another #{recovered} #{name} have been made available!"
|
|
256
264
|
end
|
|
257
265
|
end
|
|
258
266
|
|
|
@@ -262,6 +270,7 @@ module TestIds
|
|
|
262
270
|
#####################################################################
|
|
263
271
|
{ 'bins' => 'bins', 'softbins' => 'softbins', 'numbers' => 'test_numbers' }.each do |type, name|
|
|
264
272
|
next if config.send(type).function?
|
|
273
|
+
|
|
265
274
|
Origen.log.info "Checking all #{name} assignments are valid..."
|
|
266
275
|
also_remove_from = []
|
|
267
276
|
if type == 'bin'
|
|
@@ -269,11 +278,12 @@ module TestIds
|
|
|
269
278
|
also_remove_from << store['assigned']['numbers'] if config.numbers.function?
|
|
270
279
|
elsif type == 'softbin'
|
|
271
280
|
also_remove_from << store['assigned']['numbers'] if config.numbers.function?
|
|
272
|
-
|
|
273
|
-
also_remove_from << store['assigned']['softbins']
|
|
281
|
+
elsif config.softbins.function?
|
|
282
|
+
also_remove_from << store['assigned']['softbins']
|
|
274
283
|
end
|
|
275
|
-
removed = remove_invalid_assignments(config.send(type), store['assigned'][type],
|
|
276
|
-
|
|
284
|
+
removed = remove_invalid_assignments(config.send(type), store['assigned'][type],
|
|
285
|
+
store['manually_assigned'][type], also_remove_from)
|
|
286
|
+
if removed.zero?
|
|
277
287
|
Origen.log.info " All #{name} assignments are already valid."
|
|
278
288
|
else
|
|
279
289
|
Origen.log.success " #{removed} #{name} assignments have been removed!"
|
|
@@ -286,15 +296,18 @@ module TestIds
|
|
|
286
296
|
#####################################################################
|
|
287
297
|
{ 'bins' => 'bins', 'softbins' => 'softbins', 'numbers' => 'test_numbers' }.each do |type, name|
|
|
288
298
|
next if config.send(type).function?
|
|
299
|
+
|
|
289
300
|
Origen.log.info "Checking all #{name} references are valid..."
|
|
290
|
-
removed = remove_invalid_references(config.send(type), store['references'][type],
|
|
291
|
-
|
|
301
|
+
removed = remove_invalid_references(config.send(type), store['references'][type],
|
|
302
|
+
store['manually_assigned'][type])
|
|
303
|
+
if removed.zero?
|
|
292
304
|
Origen.log.info " All #{name} references are already valid."
|
|
293
305
|
else
|
|
294
306
|
Origen.log.success " #{removed} #{name} references have been removed!"
|
|
295
307
|
end
|
|
296
308
|
end
|
|
297
309
|
end
|
|
310
|
+
# rubocop:enable Style/CombinableLoops
|
|
298
311
|
|
|
299
312
|
# Clear the :bins, :softbins and/or :numbers and/or :ranges by setting the options for each item
|
|
300
313
|
def clear(options)
|
|
@@ -316,49 +329,49 @@ module TestIds
|
|
|
316
329
|
store['pointers']['numbers'] = nil
|
|
317
330
|
store['references']['numbers'] = {}
|
|
318
331
|
end
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
332
|
+
return unless options[:range] || options[:ranges]
|
|
333
|
+
|
|
334
|
+
store['pointers']['ranges'] = nil
|
|
322
335
|
end
|
|
323
336
|
|
|
324
337
|
# Saves the current allocator state to the repository
|
|
325
338
|
def save
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
339
|
+
return unless file
|
|
340
|
+
|
|
341
|
+
# Ensure the current store has been loaded before we try to re-write it, this
|
|
342
|
+
# is necessary if the program generator has crashed before creating a test
|
|
343
|
+
store
|
|
344
|
+
store['configuration'] = config
|
|
345
|
+
p = Pathname.new(file)
|
|
346
|
+
FileUtils.mkdir_p(p.dirname)
|
|
347
|
+
File.open(p, 'w') do |f|
|
|
348
|
+
f.puts '// The structure of this file is as follows:'
|
|
349
|
+
f.puts '//'
|
|
350
|
+
f.puts '// {'
|
|
351
|
+
f.puts '// // A revision number used by TestIDs to identify the format of this file'
|
|
352
|
+
f.puts "// 'format_revision' => STORE_FORMAT_REVISION,"
|
|
353
|
+
f.puts '//'
|
|
354
|
+
f.puts '// // Captures the configuration that was used the last time this database was updated.'
|
|
355
|
+
f.puts "// 'configuration' => { 'bins' => {}, 'softbins' => {}, 'numbers' => {} },"
|
|
356
|
+
f.puts '//'
|
|
357
|
+
f.puts '// // If some number are still to be allocated, these point to the last number given out.'
|
|
358
|
+
f.puts '// // If all numbers have been allocated and we are now on the reclamation phase, the pointer'
|
|
359
|
+
f.puts '// // will contain "done".'
|
|
360
|
+
f.puts "// 'pointers' => { 'bins' => nil, 'softbins' => nil, 'numbers' => nil, 'ranges' => nil },"
|
|
361
|
+
f.puts '//'
|
|
362
|
+
f.puts '// // This is the record of all numbers which have been previously assigned.'
|
|
363
|
+
f.puts "// 'assigned' => { 'bins' => {}, 'softbins' => {}, 'numbers' => {} },"
|
|
364
|
+
f.puts '//'
|
|
365
|
+
f.puts '// // This is a record of any numbers which have been manually assigned.'
|
|
366
|
+
f.puts "// 'manually_assigned' => { 'bins' => {}, 'softbins' => {}, 'numbers' => {} },"
|
|
367
|
+
f.puts '//'
|
|
368
|
+
f.puts '// // This contains all assigned numbers with a timestamp of when they were last referenced.'
|
|
369
|
+
f.puts '// // When numbers need to be reclaimed, they will be taken from the bottom of this list, i.e.'
|
|
370
|
+
f.puts '// // the numbers which have not been used for the longest time, e.g. because the test they'
|
|
371
|
+
f.puts '// // were assigned to has since been removed.'
|
|
372
|
+
f.puts "// 'references' => { 'bins' => {}, 'softbins' => {}, 'numbers' => {} }"
|
|
373
|
+
f.puts '// }'
|
|
374
|
+
f.puts JSON.pretty_generate(store)
|
|
362
375
|
end
|
|
363
376
|
end
|
|
364
377
|
|
|
@@ -385,11 +398,11 @@ module TestIds
|
|
|
385
398
|
|
|
386
399
|
# First work out the test ID to be used for each of the numbers, and how many numbers
|
|
387
400
|
# should be reserved
|
|
388
|
-
if (options[type].is_a?(Symbol) || options[type].is_a?(String)) && options[type] != :none
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
401
|
+
id = if (options[type].is_a?(Symbol) || options[type].is_a?(String)) && options[type] != :none
|
|
402
|
+
options[type].to_s
|
|
403
|
+
else
|
|
404
|
+
name
|
|
405
|
+
end
|
|
393
406
|
id = "#{id}_#{options[:index]}" if options[:index]
|
|
394
407
|
id = "#{id}_#{options[:test_ids_flow_id]}" if config.unique_by_flow?
|
|
395
408
|
|
|
@@ -400,25 +413,21 @@ module TestIds
|
|
|
400
413
|
store['manually_assigned']["#{type}s"][options[type].to_s] = true
|
|
401
414
|
val['number'] = options[type]
|
|
402
415
|
end
|
|
403
|
-
|
|
416
|
+
elsif @needs_regenerated[type]
|
|
404
417
|
# Will be set if an upstream dependent type has been marked for regeneration by the code below
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
val['size'] = nil
|
|
418
|
+
val['number'] = nil
|
|
419
|
+
val['size'] = nil
|
|
408
420
|
# Regenerate the number if the original allocation has since been applied manually elsewhere
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
@needs_regenerated[t] = true
|
|
416
|
-
end
|
|
417
|
-
end
|
|
421
|
+
elsif store['manually_assigned'][type_plural][val['number'].to_s]
|
|
422
|
+
val['number'] = nil
|
|
423
|
+
val['size'] = nil
|
|
424
|
+
# Also regenerate these as they could be a function of the number we just invalidated
|
|
425
|
+
(%i(bin softbin number) - [type]).each do |t|
|
|
426
|
+
@needs_regenerated[t] = true if config.send("#{t}s").needs?(type)
|
|
418
427
|
end
|
|
419
428
|
end
|
|
420
429
|
|
|
421
|
-
if size = options["#{type}_size".to_sym]
|
|
430
|
+
if (size = options["#{type}_size".to_sym])
|
|
422
431
|
val['size'] = size
|
|
423
432
|
end
|
|
424
433
|
|
|
@@ -433,6 +442,8 @@ module TestIds
|
|
|
433
442
|
end
|
|
434
443
|
|
|
435
444
|
# Update the supplied options hash that will be forwarded to the program generator
|
|
445
|
+
return if type == :bin && options[:bin].is_a?(String)
|
|
446
|
+
|
|
436
447
|
options[type] = val['number']
|
|
437
448
|
options["#{type}_size".to_sym] = val['size']
|
|
438
449
|
end
|
|
@@ -447,7 +458,7 @@ module TestIds
|
|
|
447
458
|
|
|
448
459
|
def remove_invalid_references(config_item, references, manually_assigned)
|
|
449
460
|
removed = 0
|
|
450
|
-
references.each do |num,
|
|
461
|
+
references.each do |num, _time|
|
|
451
462
|
unless config_item.valid?(num.to_i) || manually_assigned[num]
|
|
452
463
|
removed += 1
|
|
453
464
|
references.delete(num)
|
|
@@ -460,12 +471,12 @@ module TestIds
|
|
|
460
471
|
removed = 0
|
|
461
472
|
assigned.each do |id, a|
|
|
462
473
|
a['size'].times do |i|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
474
|
+
next if config_item.valid?(a['number'] + i) || manually_assigned[(a['number'] + i).to_s]
|
|
475
|
+
|
|
476
|
+
removed += 1
|
|
477
|
+
assigned.delete(id)
|
|
478
|
+
also_remove_from.each { |a| a.delete(id) }
|
|
479
|
+
break
|
|
469
480
|
end
|
|
470
481
|
end
|
|
471
482
|
removed
|
|
@@ -489,74 +500,70 @@ module TestIds
|
|
|
489
500
|
conf = config.send(type_plural)
|
|
490
501
|
if conf.algorithm
|
|
491
502
|
algo = conf.algorithm.to_s.downcase
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
end
|
|
503
|
+
fail "Illegal algorithm: #{algo}" unless algo.to_s =~ /^[bsn\dx]+$/
|
|
504
|
+
|
|
505
|
+
number = algo.to_s
|
|
506
|
+
(%i(bin softbin number) - [type]).each do |t|
|
|
507
|
+
next unless number =~ /(#{t.to_s[0]}+)/
|
|
508
|
+
|
|
509
|
+
max_size = Regexp.last_match(1).size
|
|
510
|
+
num = options[t].to_s
|
|
511
|
+
if num.size > max_size
|
|
512
|
+
fail "The allocated number, #{num}, overflows the #{t} field in the #{type} algorithm - #{algo}"
|
|
503
513
|
end
|
|
504
514
|
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
515
|
+
number = number.sub(/#{t.to_s[0]}+/, num.rjust(max_size, '0'))
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
if number =~ /(x+)/
|
|
519
|
+
max_counter_size = Regexp.last_match(1).size
|
|
520
|
+
refs = store['references'][type_plural]
|
|
521
|
+
i = 0
|
|
522
|
+
possible = []
|
|
523
|
+
proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0')).to_i.to_s
|
|
524
|
+
possible << proposal
|
|
525
|
+
while refs[proposal] && i.to_s.size <= max_counter_size
|
|
526
|
+
i += 1
|
|
510
527
|
proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0')).to_i.to_s
|
|
511
528
|
possible << proposal
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
#
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
# Not the most efficient search algorithm, but this should be hit very rarely
|
|
521
|
-
# and even then only to generate the bin the first time around
|
|
522
|
-
p = refs.sort_by { |bin, last_used| last_used }.find do |bin, last_used|
|
|
523
|
-
possible.include?(bin)
|
|
524
|
-
end
|
|
525
|
-
proposal = p[0]
|
|
529
|
+
end
|
|
530
|
+
# Overflowed, need to go search for the oldest duplicate now
|
|
531
|
+
if i.to_s.size > max_counter_size
|
|
532
|
+
i = 0
|
|
533
|
+
# Not the most efficient search algorithm, but this should be hit very rarely
|
|
534
|
+
# and even then only to generate the bin the first time around
|
|
535
|
+
p = refs.sort_by { |_bin, last_used| last_used }.find do |bin, _last_used|
|
|
536
|
+
possible.include?(bin)
|
|
526
537
|
end
|
|
527
|
-
|
|
538
|
+
proposal = p[0]
|
|
528
539
|
end
|
|
529
|
-
|
|
530
|
-
fail "Illegal algorithm: #{algo}"
|
|
540
|
+
number = proposal
|
|
531
541
|
end
|
|
542
|
+
|
|
532
543
|
number.to_i
|
|
533
|
-
elsif callback = conf.callback
|
|
544
|
+
elsif (callback = conf.callback)
|
|
534
545
|
callback.call(options)
|
|
546
|
+
elsif store['pointers'][type_plural] == 'done'
|
|
547
|
+
reclaim_item(type, options)
|
|
535
548
|
else
|
|
536
|
-
|
|
537
|
-
|
|
549
|
+
b = conf.include.next(after: instance_variable_get("@last_#{type}"), size: options[:size])
|
|
550
|
+
instance_variable_set("@last_#{type}", nil)
|
|
551
|
+
b = conf.include.next(size: options[:size]) while b && (store['manually_assigned'][type_plural][b.to_s] || conf.exclude.include?(b))
|
|
552
|
+
# When no number is returned it means we have used them all, all future generation
|
|
553
|
+
# now switches to reclaim mode
|
|
554
|
+
if b
|
|
555
|
+
store['pointers'][type_plural] = b + (options[:size] || 1) - 1
|
|
556
|
+
b
|
|
538
557
|
else
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
while b && (store['manually_assigned'][type_plural][b.to_s] || conf.exclude.include?(b))
|
|
542
|
-
b = conf.include.next(size: options[:size])
|
|
543
|
-
end
|
|
544
|
-
# When no number is returned it means we have used them all, all future generation
|
|
545
|
-
# now switches to reclaim mode
|
|
546
|
-
if b
|
|
547
|
-
store['pointers'][type_plural] = b + (options[:size] || 1) - 1
|
|
548
|
-
b
|
|
549
|
-
else
|
|
550
|
-
store['pointers'][type_plural] = 'done'
|
|
551
|
-
reclaim_item(type, options)
|
|
552
|
-
end
|
|
558
|
+
store['pointers'][type_plural] = 'done'
|
|
559
|
+
reclaim_item(type, options)
|
|
553
560
|
end
|
|
554
561
|
end
|
|
555
562
|
end
|
|
556
563
|
|
|
557
564
|
def reclaim_item(type, options)
|
|
558
565
|
type_plural = "#{type}s"
|
|
559
|
-
store['references'][type_plural] = store['references'][type_plural].sort_by { |
|
|
566
|
+
store['references'][type_plural] = store['references'][type_plural].sort_by { |_k, v| v }.to_h
|
|
560
567
|
if options[:size] == 1
|
|
561
568
|
v = store['references'][type_plural].first
|
|
562
569
|
v[0].to_i if v
|
|
@@ -599,12 +606,11 @@ module TestIds
|
|
|
599
606
|
p = i
|
|
600
607
|
s = 1
|
|
601
608
|
end
|
|
602
|
-
prev = v
|
|
603
609
|
else
|
|
604
610
|
p = i
|
|
605
611
|
s = 1
|
|
606
|
-
prev = v
|
|
607
612
|
end
|
|
613
|
+
prev = v
|
|
608
614
|
end
|
|
609
615
|
if s > max_size
|
|
610
616
|
max_size = s
|
data/lib/test_ids/bin_array.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module TestIds
|
|
2
4
|
class BinArray
|
|
3
5
|
def initialize
|
|
@@ -74,11 +76,11 @@ module TestIds
|
|
|
74
76
|
end
|
|
75
77
|
else
|
|
76
78
|
v = @store.first
|
|
77
|
-
if v.is_a?(Range)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
@next = if v.is_a?(Range)
|
|
80
|
+
v.min
|
|
81
|
+
else
|
|
82
|
+
v
|
|
83
|
+
end
|
|
82
84
|
end
|
|
83
85
|
if options[:size] && options[:size] > 1
|
|
84
86
|
# Check that all the numbers in the range to be reserved are included in the allocation,
|
|
@@ -121,7 +123,7 @@ module TestIds
|
|
|
121
123
|
nx = @next
|
|
122
124
|
@pointer = nil
|
|
123
125
|
@next = nil
|
|
124
|
-
while n = self.next
|
|
126
|
+
while (n = self.next)
|
|
125
127
|
yield n
|
|
126
128
|
end
|
|
127
129
|
@pointer = p
|
|
@@ -141,11 +143,10 @@ module TestIds
|
|
|
141
143
|
self.<<(i)
|
|
142
144
|
elsif i.is_a?(String)
|
|
143
145
|
# JSON does not serialize ranges well, take care of it here
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
end
|
|
146
|
+
fail "Unknown bin array object type (#{o.class}): #{o}" unless i =~ /^(\d+)\.\.(\d+)$/
|
|
147
|
+
|
|
148
|
+
self.<<((Regexp.last_match(1).to_i)..(Regexp.last_match(2).to_i))
|
|
149
|
+
|
|
149
150
|
else
|
|
150
151
|
fail "Unknown bin array object type (#{o.class}): #{o}"
|
|
151
152
|
end
|
|
@@ -155,7 +156,7 @@ module TestIds
|
|
|
155
156
|
private
|
|
156
157
|
|
|
157
158
|
def previous_pointer(i)
|
|
158
|
-
i
|
|
159
|
+
i.zero? ? @store.size - 1 : i - 1
|
|
159
160
|
end
|
|
160
161
|
|
|
161
162
|
def min_val(v)
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'optparse'
|
|
2
4
|
|
|
3
5
|
options = {}
|
|
@@ -5,27 +7,30 @@ options = {}
|
|
|
5
7
|
# App options are options that the application can supply to extend this command
|
|
6
8
|
app_options = @application_options || []
|
|
7
9
|
opt_parser = OptionParser.new do |opts|
|
|
8
|
-
opts.banner =
|
|
9
|
-
Clear all existing bin, softbin or test number allocations in the given TestId database.
|
|
10
|
+
opts.banner = <<~EOT
|
|
11
|
+
Clear all existing bin, softbin or test number allocations in the given TestId database.
|
|
10
12
|
|
|
11
|
-
Usage: origen test_ids:clear [ID] [options]
|
|
13
|
+
Usage: origen test_ids:clear [ID] [options]
|
|
12
14
|
|
|
13
|
-
Examples: origen test_ids:clear --bins # Clear the bins in the default database
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
Examples: origen test_ids:clear --bins # Clear the bins in the default database
|
|
16
|
+
origen test_ids:clear wafer_test --numbers # Clear the test numbers in the wafer_test database
|
|
17
|
+
origen test_ids:clear --bins --softbin --numbers # Clear everything in the default database
|
|
16
18
|
|
|
17
19
|
EOT
|
|
18
|
-
opts.on('--bins', 'Clear the bin database') {
|
|
20
|
+
opts.on('--bins', 'Clear the bin database') { options[:bins] = true }
|
|
19
21
|
opts.on('--softbins', 'Clear the softbin database') { options[:softbins] = true }
|
|
20
|
-
opts.on('--numbers', 'Clear the test number database') {
|
|
21
|
-
opts.on('--ranges', 'Clear the ranges database') {
|
|
22
|
+
opts.on('--numbers', 'Clear the test number database') { options[:numbers] = true }
|
|
23
|
+
opts.on('--ranges', 'Clear the ranges database') { options[:ranges] = true }
|
|
22
24
|
# opts.on('-pl', '--plugin PLUGIN_NAME', String, 'Set current plugin') { |pl_n| options[:current_plugin] = pl_n }
|
|
23
|
-
opts.on('-d', '--debugger', 'Enable the debugger') {
|
|
25
|
+
opts.on('-d', '--debugger', 'Enable the debugger') { options[:debugger] = true }
|
|
24
26
|
app_options.each do |app_option|
|
|
25
27
|
opts.on(*app_option) {}
|
|
26
28
|
end
|
|
27
29
|
opts.separator ''
|
|
28
|
-
opts.on('-h', '--help', 'Show this message')
|
|
30
|
+
opts.on('-h', '--help', 'Show this message') do
|
|
31
|
+
puts opts
|
|
32
|
+
exit 0
|
|
33
|
+
end
|
|
29
34
|
end
|
|
30
35
|
|
|
31
36
|
opt_parser.parse! ARGV
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'optparse'
|
|
2
4
|
|
|
3
5
|
options = {}
|
|
@@ -5,21 +7,24 @@ options = {}
|
|
|
5
7
|
# App options are options that the application can supply to extend this command
|
|
6
8
|
app_options = @application_options || []
|
|
7
9
|
opt_parser = OptionParser.new do |opts|
|
|
8
|
-
opts.banner =
|
|
9
|
-
Performs maintenance on the given TestId database.
|
|
10
|
+
opts.banner = <<~EOT
|
|
11
|
+
Performs maintenance on the given TestId database.
|
|
10
12
|
|
|
11
|
-
Usage: origen test_ids:repair ID [options]
|
|
13
|
+
Usage: origen test_ids:repair ID [options]
|
|
12
14
|
|
|
13
15
|
EOT
|
|
14
16
|
# opts.on('--bins', 'Clear the bin database') { options[:bins] = true }
|
|
15
17
|
# opts.on('--softbins', 'Clear the softbin database') { options[:softbins] = true }
|
|
16
18
|
# opts.on('--numbers', 'Clear the test number database') { options[:numbers] = true }
|
|
17
|
-
opts.on('-d', '--debugger', 'Enable the debugger') {
|
|
19
|
+
opts.on('-d', '--debugger', 'Enable the debugger') { options[:debugger] = true }
|
|
18
20
|
app_options.each do |app_option|
|
|
19
21
|
opts.on(*app_option) {}
|
|
20
22
|
end
|
|
21
23
|
opts.separator ''
|
|
22
|
-
opts.on('-h', '--help', 'Show this message')
|
|
24
|
+
opts.on('-h', '--help', 'Show this message') do
|
|
25
|
+
puts opts
|
|
26
|
+
exit 0
|
|
27
|
+
end
|
|
23
28
|
end
|
|
24
29
|
|
|
25
30
|
opt_parser.parse! ARGV
|