rbbt-util 2.1.0 → 3.0.2

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 (46) hide show
  1. data/bin/rbbt_query.rb +63 -0
  2. data/lib/rbbt-util.rb +5 -5
  3. data/lib/rbbt.rb +2 -11
  4. data/lib/rbbt/util/cmd.rb +1 -1
  5. data/lib/rbbt/util/fix_width_table.rb +9 -3
  6. data/lib/rbbt/util/log.rb +23 -7
  7. data/lib/rbbt/util/misc.rb +121 -15
  8. data/lib/rbbt/util/open.rb +14 -4
  9. data/lib/rbbt/util/persistence.rb +52 -21
  10. data/lib/rbbt/util/rake.rb +108 -21
  11. data/lib/rbbt/util/resource.rb +338 -0
  12. data/lib/rbbt/util/simpleDSL.rb +1 -1
  13. data/lib/rbbt/util/simpleopt.rb +1 -1
  14. data/lib/rbbt/util/task.rb +340 -0
  15. data/lib/rbbt/util/tc_hash.rb +19 -2
  16. data/lib/rbbt/util/tsv.rb +15 -10
  17. data/lib/rbbt/util/tsv/accessor.rb +16 -7
  18. data/lib/rbbt/util/tsv/attach.rb +220 -17
  19. data/lib/rbbt/util/tsv/index.rb +6 -1
  20. data/lib/rbbt/util/tsv/manipulate.rb +4 -5
  21. data/lib/rbbt/util/tsv/parse.rb +45 -21
  22. data/lib/rbbt/util/tsv/resource.rb +74 -0
  23. data/lib/rbbt/util/workflow.rb +99 -75
  24. data/test/rbbt/util/test_filecache.rb +2 -2
  25. data/test/rbbt/util/test_misc.rb +7 -2
  26. data/test/rbbt/util/test_persistence.rb +40 -5
  27. data/test/rbbt/util/test_resource.rb +92 -0
  28. data/test/rbbt/util/test_task.rb +118 -0
  29. data/test/rbbt/util/test_tsv.rb +5 -1
  30. data/test/rbbt/util/test_workflow.rb +77 -62
  31. data/test/rbbt/util/tsv/test_attach.rb +95 -7
  32. data/test/rbbt/util/tsv/test_index.rb +0 -1
  33. data/test/rbbt/util/tsv/test_manipulate.rb +20 -0
  34. data/test/rbbt/util/tsv/test_resource.rb +9 -0
  35. data/test/test_helper.rb +10 -0
  36. data/test/test_rbbt.rb +2 -37
  37. metadata +16 -18
  38. data/lib/rbbt/util/data_module.rb +0 -93
  39. data/lib/rbbt/util/path.rb +0 -155
  40. data/lib/rbbt/util/pkg_config.rb +0 -78
  41. data/lib/rbbt/util/pkg_data.rb +0 -119
  42. data/lib/rbbt/util/pkg_software.rb +0 -145
  43. data/test/rbbt/util/test_data_module.rb +0 -50
  44. data/test/rbbt/util/test_path.rb +0 -10
  45. data/test/rbbt/util/test_pkg_data.rb +0 -129
  46. data/test/test_pkg.rb +0 -28
@@ -67,7 +67,7 @@ module SimpleDSL
67
67
  def load_config(method = nil, file = nil, &block)
68
68
  @config = {}
69
69
  if file
70
- raise ConfigFileMissingError.new "File '#{ file }' is missing. Have you installed the config files? (use rbbt_config)." unless File.exists? file
70
+ raise ConfigFileMissingError.new "Config file '#{ file }' is missing" unless File.exists? file
71
71
  parse(method, file)
72
72
  end
73
73
 
@@ -8,7 +8,7 @@ module SOPT
8
8
  opts.split(/:/).each do |opt|
9
9
  short, long = opt.sub(/\*$/,'').split('--').values_at(0,1)
10
10
  i= {
11
- :arg => !opt.match(/\*$/).nil?,
11
+ :arg => !!opt.match(/\*$/),
12
12
  }
13
13
  i[:short] = short unless short.nil? || short.empty?
14
14
  i[:long] = '--' + long unless long.nil? || long.empty?
@@ -0,0 +1,340 @@
1
+ require 'rbbt/util/open'
2
+
3
+ class Task
4
+ class << self
5
+ attr_accessor :basedir
6
+ end
7
+
8
+ @basedir = "."
9
+
10
+ class Job
11
+ attr_accessor :task, :id, :name, :options, :dependencies, :pid, :path, :previous_jobs
12
+
13
+ IDSEP = "_"
14
+
15
+ def self.id2name(job_id)
16
+ job_id.split(IDSEP)
17
+ end
18
+
19
+ def self.load(task, id)
20
+ name, hash = id2name(id)
21
+ self.new task, id, name, nil, nil
22
+ end
23
+
24
+ def initialize(task, id, name, options, dependencies)
25
+ @task = task
26
+ @id =id
27
+ @name = name
28
+ @options = options
29
+ @dependencies = dependencies
30
+
31
+ if @dependencies
32
+ @previous_jobs = Hash[*dependencies.first.collect{|job| job.task.name}.zip(dependencies.first).flatten]
33
+ dependencies.first.collect{|job| @previous_jobs.merge! job.previous_jobs }
34
+ else
35
+ @previous_jobs = []
36
+ end
37
+
38
+ basedir = task.workflow.jobdir unless task.workflow.nil?
39
+ @path = File.join(basedir || Task.basedir, task.name, id)
40
+ end
41
+
42
+ def info_file
43
+ path + '.info'
44
+ end
45
+
46
+ def info
47
+ return {} if not File.exists?(info_file)
48
+ YAML.load(File.open(info_file))
49
+ end
50
+
51
+ def set_info(key, value)
52
+ i = self.info
53
+ new_info = i.merge(key => value)
54
+ Open.write(info_file, new_info.to_yaml)
55
+ end
56
+
57
+ def step(name = nil, message = nil)
58
+ if name.nil?
59
+ info[:step]
60
+ else
61
+ set_info(:step, name)
62
+ set_info(:messages, info[:messages] || [] << message) if not message.nil?
63
+ end
64
+ end
65
+
66
+ def messages
67
+ info[:messages] || []
68
+ end
69
+
70
+ def done?
71
+ [:done, :error, :aborted].include? info[:step]
72
+ end
73
+
74
+ def error?
75
+ step == :error or step == :aborted
76
+ end
77
+
78
+ def arguments
79
+ options.values_at *task.options
80
+ end
81
+
82
+ def block
83
+ task.block
84
+ end
85
+
86
+ def run_dependencies
87
+ jobs, files = dependencies
88
+ jobs.each do |job| job.start unless File.exists? job.path; job.step(:done) end
89
+ files.each do |file| file.produce end
90
+ end
91
+
92
+ def input
93
+ dep = dependencies.flatten.first
94
+ if Job === dep
95
+ dep.load
96
+ else
97
+ dep.read
98
+ end
99
+ end
100
+
101
+ def start
102
+ Log.medium("Starting Job '#{ name }'. Path: '#{ path }'")
103
+ set_info(:start_time, Time.now)
104
+ save_options(options)
105
+
106
+ extend task.scope unless task.scope.nil? or Object == task.scope.class
107
+
108
+ begin
109
+
110
+ if dependencies.flatten.any?
111
+ run_dependencies
112
+ end
113
+
114
+ result = instance_exec *arguments, &block
115
+
116
+
117
+ if not result.nil?
118
+ case task.persistence
119
+ when nil, :string, :tsv, :integer
120
+ Open.write(path, result.to_s)
121
+ when :marshal
122
+ Open.write(path, Marshal.dump(result))
123
+ when :yaml
124
+ Open.write(path, YAML.dump(result))
125
+ end
126
+ end
127
+
128
+ set_info(:end_time, Time.now)
129
+ Log.medium("Finished Job '#{ name }'. Path: '#{ path }'")
130
+ rescue Exception
131
+ step(:error, "#{$!.class}: #{$!.message}")
132
+ raise $!
133
+ end
134
+ end
135
+
136
+ def save_options(options)
137
+ new_options = {}
138
+ options.each do |key, value|
139
+ case
140
+ when TSV === value
141
+ new_options[key] = value.to_s
142
+ else
143
+ new_options[key] = value
144
+ end
145
+ end
146
+ set_info(:options, new_options)
147
+ end
148
+
149
+ def recursive_done?
150
+ previous_jobs.values.inject(true){|acc,j| acc and j.recursive_done?} and done?
151
+ end
152
+
153
+ def run
154
+ return self if recursive_done?
155
+ begin
156
+ step(:started)
157
+ start
158
+ step(:done)
159
+ rescue Exception
160
+ Log.debug $!.message
161
+ Log.debug $!.backtrace * "\n"
162
+ step(:error, "#{$!.class}: #{$!.message}")
163
+ end
164
+ self
165
+ end
166
+
167
+ def fork
168
+ return self if recursive_done?
169
+ @pid = Process.fork do
170
+ begin
171
+ step(:started)
172
+ start
173
+ step(:done)
174
+ rescue Exception
175
+ Log.debug $!.message
176
+ Log.debug $!.backtrace * "\n"
177
+ step(:error, "#{$!.class}: #{$!.message}")
178
+ end
179
+ exit
180
+ end
181
+
182
+ self
183
+ end
184
+
185
+ def join
186
+ if @pid.nil?
187
+ while not done? do
188
+ Log.debug "Waiting: #{info[:step]}"
189
+ sleep 5
190
+ end
191
+ else
192
+ Process.waitpid @pid
193
+ end
194
+
195
+ self
196
+ end
197
+
198
+ def open
199
+ File.open(path)
200
+ end
201
+
202
+ def read
203
+ File.open(path) do |f| f.read end
204
+ end
205
+
206
+ def load
207
+ case task.persistence
208
+ when :float
209
+ Open.read(path).to_f
210
+ when :integer
211
+ Open.read(path).to_i
212
+ when :string
213
+ Open.read(path)
214
+ when :tsv
215
+ TSV.new(path)
216
+ when :marshal
217
+ Marshal.load(Open.read(path))
218
+ when :yaml
219
+ YAML.load(Open.read(path))
220
+ end
221
+ end
222
+
223
+ def clean
224
+ FileUtils.rm path if File.exists? path
225
+ FileUtils.rm info_file if File.exists? info_file
226
+ end
227
+
228
+ def recursive_clean
229
+ dependencies.first.each do |job| job.recursive_clean end
230
+ clean
231
+ end
232
+ end # END Job
233
+
234
+ def load(job_id)
235
+ Job.load(self, job_id)
236
+ end
237
+
238
+ def job_options(run_options = nil)
239
+ return {} if options.nil?
240
+
241
+ job_options = {}
242
+ options.each do |option|
243
+ job_options[option] = Misc.process_options run_options, option
244
+ end
245
+
246
+ job_options
247
+ end
248
+
249
+ def job_id(name, job_options)
250
+ if job_options.any?
251
+ name.to_s + "_" + Misc.hash2md5(job_options)
252
+ else
253
+ name.to_s
254
+ end
255
+ end
256
+
257
+ attr_accessor :name, :persistence, :options, :option_descriptions, :option_types, :option_defaults, :workflow, :dependencies, :scope, :block
258
+ def initialize(name, persistence = nil, options = nil, option_descriptions = nil, option_types = nil, option_defaults = nil, workflow = nil, dependencies = nil, scope = nil, &block)
259
+ dependencies = [dependencies] unless dependencies.nil? or Array === dependencies
260
+ @name = name.to_s
261
+
262
+ @persistence = persistence || :marshal
263
+
264
+ @options = Array === options ? options : [options] unless options.nil?
265
+
266
+ @option_defaults = option_defaults
267
+ @option_descriptions = option_descriptions
268
+ @option_types = option_types
269
+ @workflow = workflow
270
+ @dependencies = dependencies || []
271
+ @scope = scope
272
+
273
+ @block = block unless not block_given?
274
+ end
275
+
276
+ def recursive_options
277
+ all_options = []
278
+ option_descriptions = {}
279
+ option_types = {}
280
+ option_defaults = {}
281
+
282
+ all_options.concat self.options if self.options
283
+ option_descriptions.merge! self.option_descriptions if self.option_descriptions
284
+ option_types.merge! self.option_types if self.option_types
285
+ option_defaults.merge! self.option_defaults if self.option_defaults
286
+
287
+ self.dependencies.each do |task|
288
+ task = case
289
+ when Symbol === task
290
+ workflow.tasks[task]
291
+ when Task === task
292
+ task
293
+ else
294
+ next
295
+ end
296
+
297
+ n_all_options, n_option_descriptions, n_option_types, n_option_defaults = task.recursive_options
298
+
299
+ all_options.concat n_all_options if n_all_options
300
+ option_descriptions.merge! n_option_descriptions if n_option_descriptions
301
+ option_types.merge! n_option_types if n_option_types
302
+ option_defaults.merge! n_option_defaults if n_option_defaults
303
+ end
304
+
305
+ [all_options, option_descriptions, option_types, option_defaults]
306
+ end
307
+
308
+ def job_dependencies(jobname, run_options = {})
309
+ jobs = []
310
+ files = []
311
+ dependencies.each do |dependency|
312
+ case
313
+ when Task === dependency
314
+ jobs << dependency.job(jobname, run_options)
315
+ when Symbol === dependency
316
+ raise "No workflow defined, yet dependencies include Symbols (other tasks)" if workflow.nil?
317
+ jobs << workflow.tasks[dependency].job(jobname, run_options)
318
+ else
319
+ files << dependency
320
+ end
321
+ end
322
+ [jobs, files]
323
+ end
324
+
325
+ def job(jobname, run_options = {})
326
+
327
+ job_id = self.job_id jobname, run_options
328
+
329
+ job_options = self.job_options run_options
330
+
331
+ dependencies = self.job_dependencies(jobname, run_options)
332
+
333
+ Job.new(self, job_id, jobname, job_options, dependencies)
334
+ end
335
+
336
+ def run(*args)
337
+ job(*args).start
338
+ end
339
+
340
+ end
@@ -5,6 +5,17 @@ class TCHash < TokyoCabinet::HDB
5
5
  class OpenError < StandardError;end
6
6
  class KeyFormatError < StandardError;end
7
7
 
8
+ class IntegerSerializer
9
+ def self.dump(i); [i].pack("l"); end
10
+ def self.load(str); str.unpack("l").first; end
11
+ end
12
+
13
+ class IntegerArraySerializer
14
+ def self.dump(a); a.pack("l*"); end
15
+ def self.load(str); str.unpack("l*"); end
16
+ end
17
+
18
+
8
19
  class StringSerializer
9
20
  def self.dump(str); str.to_s; end
10
21
  def self.load(str); str; end
@@ -31,7 +42,7 @@ class TCHash < TokyoCabinet::HDB
31
42
  end
32
43
 
33
44
 
34
- ALIAS = {:marshal => Marshal, nil => Marshal, :single => StringSerializer, :list => StringArraySerializer, :double => StringDoubleArraySerializer}
45
+ ALIAS = {:integer => IntegerSerializer, :integer_array => IntegerArraySerializer, :marshal => Marshal, nil => Marshal, :single => StringSerializer, :list => StringArraySerializer, :double => StringDoubleArraySerializer}
35
46
 
36
47
  CONNECTIONS = {}
37
48
 
@@ -179,7 +190,13 @@ class TCHash < TokyoCabinet::HDB
179
190
 
180
191
  def collect
181
192
  res = []
182
- self.each{|k, v| res << yield(k,v)}
193
+ self.each{|k, v|
194
+ if block_given?
195
+ res << yield(k,v)
196
+ else
197
+ res << [k,v]
198
+ end
199
+ }
183
200
  res
184
201
  end
185
202
 
@@ -1,6 +1,6 @@
1
+ require 'rbbt/util/resource'
1
2
  require 'rbbt/util/misc'
2
3
  require 'rbbt/util/open'
3
- require 'rbbt/util/path'
4
4
  require 'rbbt/util/tc_hash'
5
5
  require 'rbbt/util/tmpfile'
6
6
  require 'rbbt/util/log'
@@ -13,6 +13,7 @@ require 'rbbt/util/tsv/accessor'
13
13
  require 'rbbt/util/tsv/manipulate'
14
14
  require 'rbbt/util/tsv/index'
15
15
  require 'rbbt/util/tsv/attach'
16
+ require 'rbbt/util/tsv/resource'
16
17
  class TSV
17
18
 
18
19
  def self.headers(file, options = {})
@@ -65,7 +66,7 @@ class TSV
65
66
 
66
67
  @filename = Misc.process_options options, :filename
67
68
  @filename ||= case
68
- when Path === file
69
+ when Resource::Path === file
69
70
  file
70
71
  when (String === file and File.exists? file)
71
72
  File.expand_path file
@@ -89,13 +90,18 @@ class TSV
89
90
  # TSV: Duplicate
90
91
  case
91
92
  when block_given?
92
- @data, extra = Persistence.persist(@filename, :TSV, :tsv_extra, options.merge(:force_array => true)) do |filename, options| yield filename, options end
93
+ @data, extra = Persistence.persist(file, :TSV, :tsv_extra, options.merge(:force_array => true)) do |file, options, filename| yield file, options, filename end
93
94
  extra.each do |key, values|
94
95
  self.send("#{ key }=".to_sym, values) if self.respond_to? "#{ key }=".to_sym
95
96
  end if not extra.nil?
96
97
 
97
98
  else
99
+
98
100
  case
101
+ when Array === file
102
+ @data = Hash[file.collect{|v|
103
+ [v,[]]
104
+ }]
99
105
  when Hash === file
100
106
  @data = file
101
107
  when TSV === file
@@ -108,12 +114,12 @@ class TSV
108
114
  end
109
115
  end
110
116
  else
111
- @data, extra = Persistence.persist(@filename, :TSV, :tsv_extra, options) do |file, options, filename|
117
+ @data, extra = Persistence.persist(file, :TSV, :tsv_extra, options) do |file, options, filename|
112
118
  data, extra = nil
113
119
 
114
120
  case
115
121
  ## Parse source
116
- when (String === file and file.respond_to? :open)
122
+ when Resource::Path === file #(String === file and file.respond_to? :open)
117
123
  data, extra = TSV.parse(file.open(:grep => options[:grep]) , options)
118
124
  extra[:namespace] ||= file.namespace
119
125
  extra[:datadir] ||= file.datadir
@@ -123,14 +129,13 @@ class TSV
123
129
  Open.open(file, :grep => options[:grep]) do |f|
124
130
  data, extra = TSV.parse(f, options)
125
131
  end
126
- #extra[:namespace] = File.basename(File.dirname(filename))
127
- #extra.delete :namespace if extra[:namespace].empty? or extra[:namespace] == "."
128
132
  when File === file
133
+ path = file.path
134
+ file = Open.grep(file, options[:grep]) if options[:grep]
135
+ data, extra = TSV.parse(file, options)
136
+ when IO === file
129
137
  file = Open.grep(file, options[:grep]) if options[:grep]
130
138
  data, extra = TSV.parse(file, options)
131
- extra[:namespace] = File.basename(File.dirname(file.filename))
132
- extra.delete :namespace if extra[:namespace].empty? or extra[:namespace] == "."
133
- ## Encapsulate Hash or TSV
134
139
  when block_given?
135
140
  data
136
141
  else