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.
- data/bin/rbbt_query.rb +63 -0
- data/lib/rbbt-util.rb +5 -5
- data/lib/rbbt.rb +2 -11
- data/lib/rbbt/util/cmd.rb +1 -1
- data/lib/rbbt/util/fix_width_table.rb +9 -3
- data/lib/rbbt/util/log.rb +23 -7
- data/lib/rbbt/util/misc.rb +121 -15
- data/lib/rbbt/util/open.rb +14 -4
- data/lib/rbbt/util/persistence.rb +52 -21
- data/lib/rbbt/util/rake.rb +108 -21
- data/lib/rbbt/util/resource.rb +338 -0
- data/lib/rbbt/util/simpleDSL.rb +1 -1
- data/lib/rbbt/util/simpleopt.rb +1 -1
- data/lib/rbbt/util/task.rb +340 -0
- data/lib/rbbt/util/tc_hash.rb +19 -2
- data/lib/rbbt/util/tsv.rb +15 -10
- data/lib/rbbt/util/tsv/accessor.rb +16 -7
- data/lib/rbbt/util/tsv/attach.rb +220 -17
- data/lib/rbbt/util/tsv/index.rb +6 -1
- data/lib/rbbt/util/tsv/manipulate.rb +4 -5
- data/lib/rbbt/util/tsv/parse.rb +45 -21
- data/lib/rbbt/util/tsv/resource.rb +74 -0
- data/lib/rbbt/util/workflow.rb +99 -75
- data/test/rbbt/util/test_filecache.rb +2 -2
- data/test/rbbt/util/test_misc.rb +7 -2
- data/test/rbbt/util/test_persistence.rb +40 -5
- data/test/rbbt/util/test_resource.rb +92 -0
- data/test/rbbt/util/test_task.rb +118 -0
- data/test/rbbt/util/test_tsv.rb +5 -1
- data/test/rbbt/util/test_workflow.rb +77 -62
- data/test/rbbt/util/tsv/test_attach.rb +95 -7
- data/test/rbbt/util/tsv/test_index.rb +0 -1
- data/test/rbbt/util/tsv/test_manipulate.rb +20 -0
- data/test/rbbt/util/tsv/test_resource.rb +9 -0
- data/test/test_helper.rb +10 -0
- data/test/test_rbbt.rb +2 -37
- metadata +16 -18
- data/lib/rbbt/util/data_module.rb +0 -93
- data/lib/rbbt/util/path.rb +0 -155
- data/lib/rbbt/util/pkg_config.rb +0 -78
- data/lib/rbbt/util/pkg_data.rb +0 -119
- data/lib/rbbt/util/pkg_software.rb +0 -145
- data/test/rbbt/util/test_data_module.rb +0 -50
- data/test/rbbt/util/test_path.rb +0 -10
- data/test/rbbt/util/test_pkg_data.rb +0 -129
- data/test/test_pkg.rb +0 -28
data/lib/rbbt/util/simpleDSL.rb
CHANGED
@@ -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 "
|
70
|
+
raise ConfigFileMissingError.new "Config file '#{ file }' is missing" unless File.exists? file
|
71
71
|
parse(method, file)
|
72
72
|
end
|
73
73
|
|
data/lib/rbbt/util/simpleopt.rb
CHANGED
@@ -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 =>
|
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
|
data/lib/rbbt/util/tc_hash.rb
CHANGED
@@ -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|
|
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
|
|
data/lib/rbbt/util/tsv.rb
CHANGED
@@ -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(
|
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(
|
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
|