rbbt-util 5.32.16 → 5.32.17

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,3 @@
1
-
2
1
  class Step
3
2
 
4
3
  STREAM_CACHE = {}
@@ -127,7 +126,7 @@ class Step
127
126
  end
128
127
 
129
128
  def input_dependencies
130
- (inputs.flatten.select{|i| Step === i} + inputs.flatten.select{|dep| Path === dep && Step === dep.resource}.collect{|dep| dep.resource})
129
+ @input_dependencies ||= (recursive_inputs.flatten.select{|i| Step === i } + recursive_inputs.flatten.select{|dep| Path === dep && Step === dep.resource }.collect{|dep| dep.resource })
131
130
  end
132
131
 
133
132
  def execute_dependency(dependency, log = true)
@@ -207,7 +206,7 @@ class Step
207
206
  if dup and step.streaming? and not step.result.nil?
208
207
  if dep_step[step.path] and dep_step[step.path].length > 1
209
208
  stream = step.result
210
- other_steps = dep_step[step.path]
209
+ other_steps = dep_step[step.path].uniq
211
210
  return unless other_steps.length > 1
212
211
  log_dependency_exec(step, "duplicating #{other_steps.length}")
213
212
  copies = Misc.tee_stream_thread_multiple(stream, other_steps.length)
@@ -369,6 +368,7 @@ class Step
369
368
  end
370
369
  next unless step.dependencies and step.dependencies.any?
371
370
  (step.dependencies + step.input_dependencies).each do |step_dep|
371
+ next unless step.dependencies.include?(step_dep)
372
372
  next if step_dep.done? or step_dep.running? or (ComputeDependency === step_dep and (step_dep.compute == :nodup or step_dep.compute == :ignore))
373
373
  dep_step[step_dep.path] ||= []
374
374
  dep_step[step_dep.path] << step
@@ -483,4 +483,44 @@ class Step
483
483
  kill_children
484
484
  end
485
485
 
486
+ def overriden?
487
+ return true if @overriden
488
+ return true if dependencies.select{|dep| dep.overriden? }.any?
489
+ info[:archived_info].each do |f,i|
490
+ return true if i[:overriden] || i["overriden"]
491
+ end if info[:archived_info]
492
+ return false
493
+ end
494
+
495
+ def overriden
496
+ @overriden
497
+ #if @overriden.nil?
498
+ # return false if dependencies.nil?
499
+ # dependencies.select{|dep| dep.overriden? }.any?
500
+ #else
501
+ # @overriden
502
+ #end
503
+ end
504
+
505
+ def overriden_deps
506
+ ord = []
507
+ deps = dependencies.dup
508
+ while dep = deps.shift
509
+ case dep.overriden
510
+ when FalseClass
511
+ next
512
+ when Symbol
513
+ ord << dep
514
+ else
515
+ deps += dep.dependencies
516
+ end
517
+ end
518
+ ord
519
+ end
520
+
521
+ def dependencies=(dependencies)
522
+ @dependencies = dependencies
523
+ set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]} if dependencies
524
+ end
525
+
486
526
  end
@@ -0,0 +1,294 @@
1
+ class Step
2
+ def info(check_lock = true)
3
+ return {:status => :noinfo} if info_file.nil? || ! Open.exists?(info_file)
4
+
5
+ begin
6
+ Misc.insist do
7
+
8
+ begin
9
+ return @info_cache if @info_cache and @info_cache_time and Open.ctime(info_file) < @info_cache_time
10
+ rescue Exception
11
+ raise $!
12
+ end
13
+
14
+
15
+ begin
16
+ @info_cache = Misc.insist(3, 1.6, info_file) do
17
+ Misc.insist(2, 1, info_file) do
18
+ Misc.insist(3, 0.2, info_file) do
19
+ raise TryAgain, "Info locked" if check_lock and info_lock.locked?
20
+ info_lock.lock if check_lock and false
21
+ begin
22
+ Open.open(info_file, :mode => 'rb') do |file|
23
+ Step.load_serialized_info(file)
24
+ end
25
+ ensure
26
+ info_lock.unlock if check_lock and false
27
+ end
28
+ end
29
+ end
30
+ end
31
+ @info_cache_time = Time.now
32
+ @info_cache
33
+ end
34
+ end
35
+ rescue Exception
36
+ Log.debug{"Error loading info file: " + info_file}
37
+ Log.exception $!
38
+ Open.rm info_file
39
+ Misc.sensiblewrite(info_file, Step.serialize_info({:status => :error, :messages => ["Info file lost"]}))
40
+ raise $!
41
+ end
42
+ end
43
+
44
+ def load_inputs_from_info
45
+ if info[:inputs]
46
+ info_inputs = info[:inputs]
47
+ if task && task.respond_to?(:inputs) && task.inputs
48
+ IndiferentHash.setup info_inputs
49
+ @inputs = NamedArray.setup info_inputs.values_at(*task.inputs.collect{|name| name.to_s}), task.inputs
50
+ else
51
+ @inputs = NamedArray.setup info_inputs.values, info_inputs.keys
52
+ end
53
+ else
54
+ nil
55
+ end
56
+ end
57
+
58
+ def load_dependencies_from_info
59
+ relocated = nil
60
+ @dependencies = (self.info[:dependencies] || []).collect do |task,name,dep_path|
61
+ if Open.exists?(dep_path) || Open.exists?(dep_path + '.info')
62
+ Workflow._load_step dep_path
63
+ else
64
+ next if FalseClass === relocated
65
+ new_path = Workflow.relocate(path, dep_path)
66
+ relocated = true if Open.exists?(new_path) || Open.exists?(new_path + '.info')
67
+ Workflow._load_step new_path
68
+ end
69
+ end.compact
70
+ @relocated = relocated
71
+ end
72
+
73
+
74
+ def archive_deps
75
+ self.set_info :archived_info, archived_info
76
+ self.set_info :archived_dependencies, info[:dependencies]
77
+ end
78
+
79
+ def archived_info
80
+ return info[:archived_info] if info[:archived_info]
81
+
82
+ archived_info = {}
83
+ dependencies.each do |dep|
84
+ if Symbol === dep.overriden && ! Open.exists?(dep.info_file)
85
+ archived_info[dep.path] = dep.overriden
86
+ else
87
+ archived_info[dep.path] = dep.info
88
+ end
89
+ archived_info.merge!(dep.archived_info)
90
+ end if dependencies
91
+
92
+ archived_info
93
+ end
94
+
95
+ def archived_inputs
96
+ return {} unless info[:archived_dependencies]
97
+ archived_info = self.archived_info
98
+
99
+ all_inputs = IndiferentHash.setup({})
100
+ deps = info[:archived_dependencies].collect{|p| p.last}
101
+ seen = []
102
+ while path = deps.pop
103
+ dep_info = archived_info[path]
104
+ if dep_info
105
+ dep_info[:inputs].each do |k,v|
106
+ all_inputs[k] = v unless all_inputs.include?(k)
107
+ end if dep_info[:inputs]
108
+ deps.concat(dep_info[:dependencies].collect{|p| p.last } - seen) if dep_info[:dependencies]
109
+ deps.concat(dep_info[:archived_dependencies].collect{|p| p.last } - seen) if dep_info[:archived_dependencies]
110
+ end
111
+ seen << path
112
+ end
113
+
114
+ all_inputs
115
+ end
116
+
117
+ def status
118
+ begin
119
+ info[:status]
120
+ rescue Exception
121
+ Log.error "Exception reading status: #{$!.message}"
122
+ :error
123
+ end
124
+ end
125
+
126
+ def status=(status)
127
+ set_info(:status, status)
128
+ end
129
+
130
+ def messages
131
+ if messages = info[:messages]
132
+ messages
133
+ else
134
+ set_info(:messages, []) if self.respond_to?(:set_info)
135
+ end
136
+ end
137
+
138
+ def message(message)
139
+ message = Log.uncolor(message)
140
+ set_info(:messages, (messages || []) << message)
141
+ end
142
+
143
+ def self.status_color(status)
144
+ status = status.split(">").last
145
+ case status
146
+ when "starting"
147
+ :yellow
148
+ when "error", "aborted"
149
+ :red
150
+ when "done"
151
+ :green
152
+ else
153
+ :cyan
154
+ end
155
+ end
156
+
157
+ def self.log_block(status, message, path, &block)
158
+ start = Time.now
159
+ status = status.to_s
160
+ status_color = self.status_color status
161
+
162
+ Log.info do
163
+ now = Time.now
164
+ str = Log.color :reset
165
+ str << "#{ Log.color status_color, status}"
166
+ str << ": #{ message }" if message and message != :result
167
+ str << " -- #{Log.color :blue, path.to_s}" if path
168
+ str << " #{Log.color :yellow, Process.pid}"
169
+ str
170
+ end
171
+ res = yield
172
+ eend = Time.now
173
+ Log.info do
174
+ now = Time.now
175
+ str = "#{ Log.color :cyan, status.to_s } +#{Log.color :green, "%.2f" % (eend - start)}"
176
+ str << ": #{ res }" if message == :result
177
+ str << " -- #{Log.color :blue, path.to_s}" if path
178
+ str << " #{Log.color :yellow, Process.pid}"
179
+ str
180
+ end
181
+ res
182
+ end
183
+
184
+ def self.log_string(status, message, path)
185
+ Log.info do
186
+
187
+ status = status.to_s
188
+ status_color = self.status_color status
189
+
190
+ str = Log.color :reset
191
+ str << "#{ Log.color status_color, status}"
192
+ str << ": #{ message }" if message
193
+ str << " -- #{Log.color :blue, path.to_s}" if path
194
+ str << " #{Log.color :yellow, Process.pid}"
195
+ str
196
+ end
197
+ end
198
+
199
+ def self.log_progress(status, options = {}, path = nil, &block)
200
+ options = Misc.add_defaults options, :severity => Log::INFO, :file => (@exec ? nil : path)
201
+ max = Misc.process_options options, :max
202
+ Log::ProgressBar.with_bar(max, options) do |bar|
203
+ begin
204
+ res = yield bar
205
+ raise KeepBar.new res if IO === res
206
+ res
207
+ rescue
208
+ Log.exception $!
209
+ raise $!
210
+ end
211
+ end
212
+ end
213
+
214
+ def log_progress(status, options = {}, &block)
215
+ Step.log_progress(status, options, file(:progress), &block)
216
+ end
217
+
218
+ def progress_bar(msg = "Progress", options = nil)
219
+ if Hash === msg and options.nil?
220
+ options = msg
221
+ msg = nil
222
+ end
223
+ options = {} if options.nil?
224
+
225
+ max = options[:max]
226
+ Log::ProgressBar.new_bar(max, {:desc => msg, :file => (@exec ? nil : file(:progress))}.merge(options))
227
+ end
228
+
229
+ def self.log(status, message, path, &block)
230
+ if block
231
+ if Hash === message
232
+ log_progress(status, message, path, &block)
233
+ else
234
+ log_block(status, message, path, &block)
235
+ end
236
+ else
237
+ log_string(status, message, path)
238
+ end
239
+ end
240
+
241
+ def log(status, message = nil, &block)
242
+ self.status = status
243
+ if message
244
+ self.message Log.uncolor(message)
245
+ end
246
+ Step.log(status, message, path, &block)
247
+ end
248
+
249
+ def exception(ex, msg = nil)
250
+ ex_class = ex.class.to_s
251
+ backtrace = ex.backtrace if ex.respond_to?(:backtrace)
252
+ message = ex.message if ex.respond_to?(:message)
253
+ set_info :backtrace, backtrace
254
+ set_info :exception, {:class => ex_class, :message => message, :backtrace => backtrace}
255
+ if msg.nil?
256
+ log :error, "#{ex_class} -- #{message}"
257
+ else
258
+ log :error, "#{msg} -- #{message}"
259
+ end
260
+ self._abort
261
+ end
262
+
263
+ def get_exception
264
+ if info[:exception].nil?
265
+ return Aborted if aborted?
266
+ return Exception.new(messages.last) if error?
267
+ Exception.new ""
268
+ else
269
+ ex_class, ex_message, ex_backtrace = info[:exception].values_at :class, :message, :backtrace
270
+ begin
271
+ klass = Kernel.const_get(ex_class)
272
+ ex = klass.new ex_message
273
+ ex.set_backtrace ex_backtrace unless ex_backtrace.nil? or ex_backtrace.empty?
274
+ ex
275
+ rescue
276
+ Log.exception $!
277
+ Exception.new ex_message
278
+ end
279
+ end
280
+ end
281
+
282
+ def recoverable_error?
283
+ return true if aborted?
284
+ return false unless error?
285
+ begin
286
+ return true unless info[:exception]
287
+ klass = Kernel.const_get(info[:exception][:class])
288
+ ! (klass <= RbbtException)
289
+ rescue Exception
290
+ true
291
+ end
292
+ end
293
+
294
+ end
@@ -0,0 +1,146 @@
1
+ class Step
2
+ def self.clean(path)
3
+ info_file = Step.info_file path
4
+ pid_file = Step.pid_file path
5
+ md5_file = Step.md5_file path
6
+ files_dir = Step.files_dir path
7
+ tmp_path = Step.tmp_path path
8
+
9
+ if ! (Open.writable?(path) && Open.writable?(info_file))
10
+ Log.warn "Could not clean #{path}: not writable"
11
+ return
12
+ end
13
+
14
+ if ENV["RBBT_DEBUG_CLEAN"] == 'true'
15
+ raise "DO NOT CLEAN"
16
+ end
17
+
18
+ if (Open.exists?(path) or Open.broken_link?(path)) or Open.exists?(pid_file) or Open.exists?(info_file) or Open.exists?(files_dir) or Open.broken_link?(files_dir)
19
+
20
+ @result = nil
21
+ @pid = nil
22
+
23
+ Misc.insist do
24
+ Open.rm info_file if Open.exists?(info_file)
25
+ Open.rm md5_file if Open.exists?(md5_file)
26
+ Open.rm path if (Open.exists?(path) || Open.broken_link?(path))
27
+ Open.rm_rf files_dir if Open.exists?(files_dir) || Open.broken_link?(files_dir)
28
+ Open.rm pid_file if Open.exists?(pid_file)
29
+ Open.rm tmp_path if Open.exists?(tmp_path)
30
+ end
31
+ end
32
+ end
33
+
34
+ def clean
35
+ if ! Open.exists?(info_file)
36
+ Log.high "Refusing to clean step with no .info file: #{path}"
37
+ return self
38
+ end
39
+ status = []
40
+ status << "dirty" if done? && dirty?
41
+ status << "not running" if ! done? && ! running?
42
+ status.unshift " " if status.any?
43
+ Log.high "Cleaning step: #{path}#{status * " "}"
44
+ Log.stack caller if RBBT_DEBUG_CLEAN
45
+ abort if ! done? && running?
46
+ Step.clean(path)
47
+ @done = false
48
+ self
49
+ end
50
+
51
+ def resumable?
52
+ (task && task.resumable) || status == :waiting || status == :cleaned
53
+ end
54
+
55
+ def started?
56
+ Open.exists?(path) or (Open.exists?(pid_file) && Open.exists?(info_file))
57
+ end
58
+
59
+ def waiting?
60
+ Open.exists?(info_file) and not started?
61
+ end
62
+
63
+ def dirty_files
64
+ rec_dependencies = self.rec_dependencies(true)
65
+ return [] if rec_dependencies.empty?
66
+ canfail_paths = self.canfail_paths
67
+
68
+ dirty_files = rec_dependencies.reject{|dep|
69
+ (defined?(WorkflowRemoteClient) && WorkflowRemoteClient::RemoteStep === dep) ||
70
+ ! Open.exists?(dep.info_file) ||
71
+ (dep.path && (Open.exists?(dep.path) || Open.remote?(dep.path))) ||
72
+ ((dep.error? || dep.aborted?) && (! dep.recoverable_error? || canfail_paths.include?(dep.path)))
73
+ }
74
+ end
75
+
76
+ def dirty?
77
+ return true if Open.exists?(pid_file) && ! ( Open.exists?(info_file) || done? )
78
+ return false unless done? || status == :done
79
+ return false unless ENV["RBBT_UPDATE"] == "true"
80
+
81
+ status = self.status
82
+
83
+ if done? and not (status == :done or status == :ending or status == :producing) and not status == :noinfo
84
+ return true
85
+ end
86
+
87
+ if status == :done and not done?
88
+ return true
89
+ end
90
+
91
+ if dirty_files.any?
92
+ Log.low "Some dirty files found for #{self.path}: #{Misc.fingerprint dirty_files}"
93
+ true
94
+ else
95
+ ! self.updated?
96
+ end
97
+ end
98
+
99
+ def done?
100
+ @done ||= path and Open.exists? path
101
+ end
102
+
103
+ def streaming?
104
+ (IO === @result) or (not @saved_stream.nil?) or status == :streaming
105
+ end
106
+
107
+ def noinfo?
108
+ status == :noinfo
109
+ end
110
+
111
+ def running?
112
+ return false if ! (started? || status == :ending)
113
+ return nil unless Open.exist?(self.pid_file)
114
+ pid = Open.read(self.pid_file).to_i
115
+
116
+ return false if done? or error? or aborted?
117
+
118
+ if Misc.pid_exists?(pid)
119
+ pid
120
+ else
121
+ done? or error? or aborted?
122
+ end
123
+ end
124
+
125
+ def stalled?
126
+ started? && ! (done? || running? || done? || error? || aborted?)
127
+ end
128
+
129
+ def missing?
130
+ status == :done && ! Open.exists?(path)
131
+ end
132
+
133
+ def error?
134
+ status == :error
135
+ end
136
+
137
+ def nopid?
138
+ ! Open.exists?(pid_file) && ! (status.nil? || status == :aborted || status == :done || status == :error || status == :cleaned)
139
+ end
140
+
141
+ def aborted?
142
+ status = self.status
143
+ status == :aborted || ((status != :ending && status != :dependencies && status != :cleaned && status != :noinfo && status != :setup && status != :noinfo && status != :waiting) && nopid?)
144
+ end
145
+
146
+ end