rbbt-util 3.0.2 → 3.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rbbt/util/log.rb CHANGED
@@ -16,13 +16,15 @@ module Log
16
16
  @@severity
17
17
  end
18
18
 
19
- SEVERITY_COLOR = ["0;37m", "32m", "33m", "31m", "1;0m" ].collect{|e| "\033[#{e}"}
19
+ SEVERITY_COLOR = ["0;37m", "0;32m", "0;33m", "0;31m", "1;0m" ].collect{|e| "\033[#{e}"}
20
20
 
21
21
  def self.log(message, severity = MEDIUM)
22
22
  severity_color = SEVERITY_COLOR[severity]
23
+ font_color = {false => "\033[0;37m", true => "\033[0m"}[severity >= INFO]
24
+
23
25
  STDERR.puts caller.select{|l| l =~ /rbbt/} * "\n" if @@severity == -1 and not message.empty?
24
26
  #STDERR.puts "#{Time.now.strftime("[%m/%d/%y-%H:%M:%S]")}[#{severity.to_s}]: " + message if severity >= @@severity
25
- STDERR.puts "\033[0;37m#{Time.now.strftime("[%m/%d/%y-%H:%M:%S]")}#{severity_color}[#{severity.to_s}]\033[0m: " + message if severity >= @@severity
27
+ STDERR.puts "\033[0;37m#{Time.now.strftime("[%m/%d/%y-%H:%M:%S]")}#{severity_color}[#{severity.to_s}]\033[0m:#{font_color} " << message.strip << "\033[0m" if severity >= @@severity
26
28
  end
27
29
 
28
30
  def self.debug(message)
@@ -41,6 +43,10 @@ module Log
41
43
  log(message, HIGH)
42
44
  end
43
45
 
46
+ def self.info(message)
47
+ log(message, INFO)
48
+ end
49
+
44
50
  def self.warn(message)
45
51
  log(message, WARN)
46
52
  end
@@ -1,4 +1,5 @@
1
1
  require 'iconv'
2
+ require 'lockfile'
2
3
  require 'digest/md5'
3
4
 
4
5
  class RBBTError < StandardError
@@ -14,9 +15,32 @@ class RBBTError < StandardError
14
15
  end
15
16
  end
16
17
 
18
+ module IndiferentHash
19
+ def indiferent_get(key)
20
+ old_get(key) ||
21
+ old_get(key.to_s) ||
22
+ old_get(key.to_sym)
23
+ end
24
+
25
+ def self.extended(base)
26
+ class << base
27
+ alias_method :old_get, :[]
28
+ alias_method :[], :indiferent_get
29
+ end
30
+ end
31
+ end
32
+
17
33
  module Misc
18
34
  class FieldNotFoundError < StandardError;end
19
35
 
36
+ def self.lock(file, *args)
37
+ FileUtils.mkdir_p File.dirname(File.expand_path(file)) unless File.exists? File.dirname(File.expand_path(file))
38
+ lockfile = Lockfile.new file + '.lock'
39
+ lockfile.lock do
40
+ yield file, *args
41
+ end
42
+ end
43
+
20
44
  def self.string2const(string)
21
45
  return nil if string.nil?
22
46
  mod = Kernel
@@ -137,15 +161,19 @@ module Misc
137
161
 
138
162
  def self.hash2md5(hash)
139
163
  o = {}
140
- hash.each do |k,v|
141
- if v.inspect =~ /:0x0/
164
+ hash.keys.sort_by{|k| k.to_s}.each do |k|
165
+ v = hash[k]
166
+ case
167
+ when v.inspect =~ /:0x0/
142
168
  o[k] = v.inspect.sub(/:0x[a-f0-9]+@/,'')
169
+ when Resource::Path === v
170
+ "" << String.new(v.to_s)
143
171
  else
144
172
  o[k] = v
145
173
  end
146
174
  end
147
175
 
148
- Digest::MD5.hexdigest(o.inspect)
176
+ Digest::MD5.hexdigest(o.sort_by{|k| k.to_s}.inspect)
149
177
  end
150
178
 
151
179
  def self.string2hash(string)
@@ -200,9 +200,21 @@ module Open
200
200
  end
201
201
  end
202
202
 
203
- def self.write(file, content)
203
+ def self.write(file, content = nil)
204
204
  FileUtils.mkdir_p File.dirname(file)
205
- if String === content
205
+ case
206
+ when content.nil?
207
+ begin
208
+ File.open(file, 'w') do |f|
209
+ f.flock(File::LOCK_EX)
210
+ yield f
211
+ f.flock(File::LOCK_UN)
212
+ end
213
+ rescue Exception
214
+ FileUtils.rm file if File.exists? file
215
+ raise $!
216
+ end
217
+ when String === content
206
218
  File.open(file, 'w') do |f|
207
219
  f.flock(File::LOCK_EX)
208
220
  f.write content
@@ -217,8 +229,9 @@ module Open
217
229
  end
218
230
  f.flock(File::LOCK_UN)
219
231
  end
220
- rescue
232
+ rescue Exception
221
233
  FileUtils.rm file if File.exists? file
234
+ raise $!
222
235
  end
223
236
  content.close
224
237
  end
@@ -181,6 +181,7 @@ module Persistence
181
181
  FileUtils.rm persistence_file
182
182
  end
183
183
 
184
+ Log.debug "Dump data into '#{persistence_file}'"
184
185
  per = Persistence::TSV.get persistence_file, true, serializer
185
186
 
186
187
  per.write
@@ -227,30 +228,41 @@ module Persistence
227
228
 
228
229
  serializer = tsv_serializer res, extra
229
230
 
230
- per = Persistence::TSV.get persistence_file, true, serializer
231
+ begin
232
+ per = Persistence::TSV.get persistence_file, true, serializer
231
233
 
232
- per.write
233
- per.merge! res
234
- Persistence::TSV::FIELD_INFO_ENTRIES.keys.each do |key|
235
- if extra.include?(key.to_sym) and per.respond_to?(key.to_sym)
236
- per.send "#{key}=".to_sym, extra[key.to_sym]
234
+ per.write
235
+ per.merge! res
236
+ Persistence::TSV::FIELD_INFO_ENTRIES.keys.each do |key|
237
+ if extra.include?(key.to_sym) and per.respond_to?(key.to_sym)
238
+ per.send "#{key}=".to_sym, extra[key.to_sym]
239
+ end
237
240
  end
241
+ rescue Exception
242
+ per.close
243
+ raise $!
238
244
  end
245
+
239
246
  per.read
240
247
 
241
248
  [ per, extra ]
242
249
  else
243
250
  Log.debug "Loading #{ persistence_file }. Prefix = #{prefix}"
244
- per = Persistence::TSV.get persistence_file, true, serializer
245
-
246
- extra = {}
247
- Persistence::TSV::FIELD_INFO_ENTRIES.keys.each do |key|
248
- if per.respond_to?(key.to_sym)
249
- extra[key] = per.send(key.to_sym)
251
+ begin
252
+ per = Persistence::TSV.get persistence_file, true, serializer
253
+
254
+ extra = {}
255
+ Persistence::TSV::FIELD_INFO_ENTRIES.keys.each do |key|
256
+ if per.respond_to?(key.to_sym)
257
+ extra[key] = per.send(key.to_sym)
258
+ end
250
259
  end
251
- end
252
260
 
253
- [ per, extra ]
261
+ rescue Exception
262
+ per.close
263
+ raise $!
264
+ end
265
+ [ per, extra ]
254
266
  end
255
267
  end
256
268
 
@@ -314,16 +326,16 @@ module Persistence
314
326
 
315
327
  filename = get_filename(file)
316
328
 
317
- if persistence == :no_create
318
- o = options.dup
319
- options =
320
- Misc.add_defaults options, :persistence_update => false, :persistence_file => nil, :filename => nil
321
- persistence_update, persistence_dir, persistence_file, filename =
322
- Misc.process_options options, :persistence_update, :persistence_dir, :persistence_file, :filename
329
+ o = options.dup
330
+ o =
331
+ Misc.add_defaults o, :persistence_update => false, :persistence_file => nil, :filename => nil
332
+ persistence_update, persistence_dir, persistence_file, filename =
333
+ Misc.process_options o, :persistence_update, :persistence_dir, :persistence_file, :filename
323
334
 
324
- filename ||= get_filename(file)
325
- persistence_file ||= get_persistence_file(filename, prefix, options.merge(:persistence_dir => persistence_dir))
335
+ filename ||= get_filename(file)
336
+ persistence_file ||= get_persistence_file(filename, prefix, o.merge(:persistence_dir => persistence_dir))
326
337
 
338
+ if persistence == :no_create
327
339
  persistence = false if not File.exists? persistence_file
328
340
  end
329
341
 
@@ -333,21 +345,24 @@ module Persistence
333
345
  else
334
346
  Log.low "Persistent Loading for #{filename}. Prefix: #{prefix}. Type #{persistence_type.to_s}"
335
347
 
336
- case persistence_type.to_sym
337
- when :string
338
- persist_string(file, prefix, options, &block)
339
- when :marshal
340
- persist_marshal(file, prefix, options, &block)
341
- when :yaml
342
- persist_yaml(file, prefix, options, &block)
343
- when :tsv
344
- persist_tsv(file, prefix, options, &block)
345
- when :tsv_string
346
- persist_tsv_string(file, prefix, options, &block)
347
- when :tsv_extra
348
- persist_tsv_extra(file, prefix, options, &block)
349
- when :fwt
350
- persist_fwt(file, prefix, options, &block)
348
+ Misc.lock(persistence_file, file, prefix, options, block) do |persistence_file,file,prefix,options,block|
349
+
350
+ case persistence_type.to_sym
351
+ when :string
352
+ persist_string(file, prefix, options, &block)
353
+ when :marshal
354
+ persist_marshal(file, prefix, options, &block)
355
+ when :yaml
356
+ persist_yaml(file, prefix, options, &block)
357
+ when :tsv
358
+ persist_tsv(file, prefix, options, &block)
359
+ when :tsv_string
360
+ persist_tsv_string(file, prefix, options, &block)
361
+ when :tsv_extra
362
+ persist_tsv_extra(file, prefix, options, &block)
363
+ when :fwt
364
+ persist_fwt(file, prefix, options, &block)
365
+ end
351
366
  end
352
367
  end
353
368
  end
@@ -240,6 +240,14 @@ source "$INSTALL_HELPER_FILE"
240
240
  Open.read self.find, *args
241
241
  end
242
242
 
243
+ def yaml(*args)
244
+ YAML.load(open)
245
+ end
246
+
247
+ def marshal(*args)
248
+ Marshal.load(open)
249
+ end
250
+
243
251
  def write(content, *args)
244
252
  FileUtils.mkdir_p File.dirname(self.find) unless File.exists? self.find
245
253
  Open.write(self.find, content, *args)
@@ -1,4 +1,5 @@
1
1
  require 'rbbt/util/open'
2
+ require 'rbbt/util/task/job'
2
3
 
3
4
  class Task
4
5
  class << self
@@ -7,246 +8,12 @@ class Task
7
8
 
8
9
  @basedir = "."
9
10
 
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
11
  def load(job_id)
235
12
  Job.load(self, job_id)
236
13
  end
237
14
 
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)
15
+ def job_id(name, job_options, previous_jobs)
16
+ job_options = job_options.merge :previous_jobs => previous_jobs.collect{|job| job.id} if previous_jobs.any?
250
17
  if job_options.any?
251
18
  name.to_s + "_" + Misc.hash2md5(job_options)
252
19
  else
@@ -254,8 +21,8 @@ class Task
254
21
  end
255
22
  end
256
23
 
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)
24
+ attr_accessor :name, :persistence, :options, :option_descriptions, :option_types, :option_defaults, :workflow, :dependencies, :scope, :description, :block
25
+ def initialize(name, persistence = nil, options = nil, option_descriptions = nil, option_types = nil, option_defaults = nil, workflow = nil, dependencies = nil, scope = nil, description = nil, &block)
259
26
  dependencies = [dependencies] unless dependencies.nil? or Array === dependencies
260
27
  @name = name.to_s
261
28
 
@@ -269,68 +36,61 @@ class Task
269
36
  @workflow = workflow
270
37
  @dependencies = dependencies || []
271
38
  @scope = scope
39
+ @description = description
272
40
 
273
41
  @block = block unless not block_given?
274
42
  end
275
43
 
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
44
+ def process_options(args, optional_args)
45
+ run_options = {}
286
46
 
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]
47
+ options.each do |option|
48
+ if option_defaults and option_defaults.include? option
49
+ run_options[option] = Misc.process_options(optional_args, option) || option_defaults[option]
50
+ else
51
+ run_options[option] = args.shift
52
+ end
53
+ end unless options.nil?
54
+
55
+ [run_options, args, optional_args]
306
56
  end
307
57
 
308
- def job_dependencies(jobname, run_options = {})
309
- jobs = []
310
- files = []
58
+ def setup(jobname, args, optional_args, dependencies)
59
+ previous_jobs = []
60
+ required_files = []
61
+
62
+ run_options, args, optional_args = process_options args, optional_args
63
+
311
64
  dependencies.each do |dependency|
312
65
  case
66
+ when Proc === dependency
67
+ previous_jobs << dependency.call(jobname, run_options)
313
68
  when Task === dependency
314
- jobs << dependency.job(jobname, run_options)
69
+ previous_jobs << dependency.job(jobname, *(args + [optional_args]))
70
+ when Task::Job === dependency
71
+ previous_jobs << dependency
315
72
  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)
73
+ previous_jobs << workflow.tasks[dependency].job(jobname, *(args + [optional_args]))
318
74
  else
319
- files << dependency
75
+ required_files << dependency
320
76
  end
321
77
  end
322
- [jobs, files]
323
- end
324
78
 
325
- def job(jobname, run_options = {})
79
+ [previous_jobs, required_files, run_options]
80
+ end
326
81
 
327
- job_id = self.job_id jobname, run_options
82
+ def job(jobname, *args)
83
+ if Hash === args.last
84
+ optional_args = args.pop
85
+ else
86
+ optional_args = {}
87
+ end
328
88
 
329
- job_options = self.job_options run_options
89
+ previous_jobs, required_files, run_options = setup(jobname, args, optional_args, dependencies)
330
90
 
331
- dependencies = self.job_dependencies(jobname, run_options)
91
+ job_id = self.job_id jobname, run_options, previous_jobs
332
92
 
333
- Job.new(self, job_id, jobname, job_options, dependencies)
93
+ Job.new(self, job_id, jobname, run_options, previous_jobs, required_files, previous_jobs.first)
334
94
  end
335
95
 
336
96
  def run(*args)