rbbt-util 2.1.0 → 3.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|