rbbt-util 5.44.1 → 6.0.4

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 (175) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/bin/rbbt +67 -90
  4. data/bin/rbbt_exec.rb +2 -2
  5. data/etc/app.d/base.rb +2 -2
  6. data/etc/app.d/semaphores.rb +3 -3
  7. data/lib/rbbt/annotations/annotated_array.rb +207 -207
  8. data/lib/rbbt/annotations/refactor.rb +27 -0
  9. data/lib/rbbt/annotations/util.rb +282 -282
  10. data/lib/rbbt/annotations.rb +343 -320
  11. data/lib/rbbt/association/database.rb +200 -225
  12. data/lib/rbbt/association/index.rb +294 -291
  13. data/lib/rbbt/association/item.rb +227 -227
  14. data/lib/rbbt/association/open.rb +35 -34
  15. data/lib/rbbt/association/util.rb +0 -169
  16. data/lib/rbbt/association.rb +2 -4
  17. data/lib/rbbt/entity/identifiers.rb +119 -118
  18. data/lib/rbbt/entity/refactor.rb +12 -0
  19. data/lib/rbbt/entity.rb +319 -315
  20. data/lib/rbbt/hpc/batch.rb +72 -53
  21. data/lib/rbbt/hpc/lsf.rb +2 -2
  22. data/lib/rbbt/hpc/orchestrate/batches.rb +2 -2
  23. data/lib/rbbt/hpc/orchestrate/chains.rb +25 -5
  24. data/lib/rbbt/hpc/orchestrate/rules.rb +2 -2
  25. data/lib/rbbt/hpc/orchestrate.rb +19 -13
  26. data/lib/rbbt/hpc/slurm.rb +18 -18
  27. data/lib/rbbt/knowledge_base/entity.rb +13 -5
  28. data/lib/rbbt/knowledge_base/query.rb +2 -2
  29. data/lib/rbbt/knowledge_base/registry.rb +32 -31
  30. data/lib/rbbt/knowledge_base/traverse.rb +1 -1
  31. data/lib/rbbt/knowledge_base.rb +1 -1
  32. data/lib/rbbt/monitor.rb +36 -25
  33. data/lib/rbbt/persist/refactor.rb +166 -0
  34. data/lib/rbbt/persist/tsv/tokyocabinet.rb +105 -105
  35. data/lib/rbbt/persist/tsv.rb +187 -185
  36. data/lib/rbbt/persist.rb +556 -551
  37. data/lib/rbbt/refactor.rb +20 -0
  38. data/lib/rbbt/resource/path/refactor.rb +178 -0
  39. data/lib/rbbt/resource/path.rb +317 -497
  40. data/lib/rbbt/resource/util.rb +0 -48
  41. data/lib/rbbt/resource.rb +3 -390
  42. data/lib/rbbt/tsv/accessor.rb +2 -838
  43. data/lib/rbbt/tsv/attach.rb +303 -299
  44. data/lib/rbbt/tsv/change_id.rb +244 -245
  45. data/lib/rbbt/tsv/csv.rb +87 -85
  46. data/lib/rbbt/tsv/dumper.rb +2 -100
  47. data/lib/rbbt/tsv/excel.rb +26 -24
  48. data/lib/rbbt/tsv/field_index.rb +4 -1
  49. data/lib/rbbt/tsv/filter.rb +3 -2
  50. data/lib/rbbt/tsv/index.rb +2 -284
  51. data/lib/rbbt/tsv/manipulate.rb +750 -747
  52. data/lib/rbbt/tsv/marshal.rb +3 -3
  53. data/lib/rbbt/tsv/matrix.rb +2 -2
  54. data/lib/rbbt/tsv/parallel/through.rb +2 -1
  55. data/lib/rbbt/tsv/parallel/traverse.rb +783 -781
  56. data/lib/rbbt/tsv/parser.rb +678 -678
  57. data/lib/rbbt/tsv/refactor.rb +195 -0
  58. data/lib/rbbt/tsv/stream.rb +253 -251
  59. data/lib/rbbt/tsv/util.rb +420 -420
  60. data/lib/rbbt/tsv.rb +210 -208
  61. data/lib/rbbt/util/R/eval.rb +4 -4
  62. data/lib/rbbt/util/R/plot.rb +62 -166
  63. data/lib/rbbt/util/R.rb +21 -18
  64. data/lib/rbbt/util/cmd.rb +2 -318
  65. data/lib/rbbt/util/color.rb +269 -269
  66. data/lib/rbbt/util/colorize.rb +89 -89
  67. data/lib/rbbt/util/concurrency/processes/refactor.rb +22 -0
  68. data/lib/rbbt/util/concurrency/processes/worker.rb +2 -2
  69. data/lib/rbbt/util/concurrency/processes.rb +389 -386
  70. data/lib/rbbt/util/config.rb +169 -167
  71. data/lib/rbbt/util/filecache.rb +1 -1
  72. data/lib/rbbt/util/iruby.rb +20 -0
  73. data/lib/rbbt/util/log/progress/report.rb +241 -241
  74. data/lib/rbbt/util/log/progress/util.rb +99 -99
  75. data/lib/rbbt/util/log/progress.rb +102 -102
  76. data/lib/rbbt/util/log/refactor.rb +49 -0
  77. data/lib/rbbt/util/log.rb +486 -532
  78. data/lib/rbbt/util/migrate.rb +2 -2
  79. data/lib/rbbt/util/misc/concurrent_stream.rb +248 -246
  80. data/lib/rbbt/util/misc/development.rb +12 -11
  81. data/lib/rbbt/util/misc/exceptions.rb +117 -112
  82. data/lib/rbbt/util/misc/format.rb +2 -230
  83. data/lib/rbbt/util/misc/indiferent_hash.rb +2 -107
  84. data/lib/rbbt/util/misc/inspect.rb +2 -476
  85. data/lib/rbbt/util/misc/lock.rb +109 -106
  86. data/lib/rbbt/util/misc/omics.rb +9 -1
  87. data/lib/rbbt/util/misc/pipes.rb +765 -793
  88. data/lib/rbbt/util/misc/refactor.rb +20 -0
  89. data/lib/rbbt/util/misc/ssw.rb +27 -17
  90. data/lib/rbbt/util/misc/system.rb +92 -105
  91. data/lib/rbbt/util/misc.rb +39 -20
  92. data/lib/rbbt/util/named_array/refactor.rb +4 -0
  93. data/lib/rbbt/util/named_array.rb +3 -220
  94. data/lib/rbbt/util/open/refactor.rb +7 -0
  95. data/lib/rbbt/util/open.rb +3 -857
  96. data/lib/rbbt/util/procpath.rb +6 -6
  97. data/lib/rbbt/util/python/paths.rb +27 -0
  98. data/lib/rbbt/util/python/run.rb +115 -0
  99. data/lib/rbbt/util/python/script.rb +110 -0
  100. data/lib/rbbt/util/python/util.rb +3 -3
  101. data/lib/rbbt/util/python.rb +22 -81
  102. data/lib/rbbt/util/semaphore.rb +152 -148
  103. data/lib/rbbt/util/simpleopt.rb +9 -8
  104. data/lib/rbbt/util/ssh/refactor.rb +19 -0
  105. data/lib/rbbt/util/ssh.rb +122 -118
  106. data/lib/rbbt/util/tar.rb +117 -115
  107. data/lib/rbbt/util/tmpfile.rb +69 -67
  108. data/lib/rbbt/util/version.rb +2 -0
  109. data/lib/rbbt/workflow/refactor/entity.rb +11 -0
  110. data/lib/rbbt/workflow/refactor/export.rb +66 -0
  111. data/lib/rbbt/workflow/refactor/inputs.rb +24 -0
  112. data/lib/rbbt/workflow/refactor/recursive.rb +64 -0
  113. data/lib/rbbt/workflow/refactor/task_info.rb +66 -0
  114. data/lib/rbbt/workflow/refactor.rb +150 -0
  115. data/lib/rbbt/workflow/remote_workflow/driver/rest.rb +1 -2
  116. data/lib/rbbt/workflow/remote_workflow/driver/ssh.rb +55 -32
  117. data/lib/rbbt/workflow/remote_workflow/remote_step/rest.rb +3 -1
  118. data/lib/rbbt/workflow/remote_workflow/remote_step/ssh.rb +14 -5
  119. data/lib/rbbt/workflow/remote_workflow/remote_step.rb +19 -7
  120. data/lib/rbbt/workflow/remote_workflow.rb +6 -1
  121. data/lib/rbbt/workflow/step/run.rb +766 -766
  122. data/lib/rbbt/workflow/step/save_load_inputs.rb +254 -254
  123. data/lib/rbbt/workflow/step.rb +2 -362
  124. data/lib/rbbt/workflow/task.rb +118 -118
  125. data/lib/rbbt/workflow/usage.rb +289 -287
  126. data/lib/rbbt/workflow/util/archive.rb +6 -5
  127. data/lib/rbbt/workflow/util/data.rb +1 -1
  128. data/lib/rbbt/workflow/util/orchestrator.rb +249 -246
  129. data/lib/rbbt/workflow/util/trace.rb +79 -44
  130. data/lib/rbbt/workflow.rb +4 -882
  131. data/lib/rbbt-util.rb +21 -13
  132. data/lib/rbbt.rb +16 -3
  133. data/python/rbbt/__init__.py +96 -4
  134. data/python/rbbt/workflow/remote.py +104 -0
  135. data/python/rbbt/workflow.py +64 -0
  136. data/python/test.py +10 -0
  137. data/share/Rlib/plot.R +37 -37
  138. data/share/Rlib/svg.R +22 -5
  139. data/share/install/software/lib/install_helpers +1 -1
  140. data/share/rbbt_commands/hpc/list +2 -3
  141. data/share/rbbt_commands/hpc/orchestrate +4 -4
  142. data/share/rbbt_commands/hpc/tail +2 -0
  143. data/share/rbbt_commands/hpc/task +10 -7
  144. data/share/rbbt_commands/lsf/list +2 -3
  145. data/share/rbbt_commands/lsf/orchestrate +4 -4
  146. data/share/rbbt_commands/lsf/tail +2 -0
  147. data/share/rbbt_commands/lsf/task +10 -7
  148. data/share/rbbt_commands/migrate +1 -1
  149. data/share/rbbt_commands/pbs/list +2 -3
  150. data/share/rbbt_commands/pbs/orchestrate +4 -4
  151. data/share/rbbt_commands/pbs/tail +2 -0
  152. data/share/rbbt_commands/pbs/task +10 -7
  153. data/share/rbbt_commands/resource/produce +8 -1
  154. data/share/rbbt_commands/slurm/list +2 -3
  155. data/share/rbbt_commands/slurm/orchestrate +4 -4
  156. data/share/rbbt_commands/slurm/tail +2 -0
  157. data/share/rbbt_commands/slurm/task +10 -7
  158. data/share/rbbt_commands/system/clean +5 -5
  159. data/share/rbbt_commands/system/status +5 -5
  160. data/share/rbbt_commands/tsv/get +2 -3
  161. data/share/rbbt_commands/tsv/info +10 -13
  162. data/share/rbbt_commands/tsv/keys +18 -14
  163. data/share/rbbt_commands/tsv/slice +2 -2
  164. data/share/rbbt_commands/tsv/transpose +6 -2
  165. data/share/rbbt_commands/workflow/info +20 -24
  166. data/share/rbbt_commands/workflow/list +1 -1
  167. data/share/rbbt_commands/workflow/prov +20 -13
  168. data/share/rbbt_commands/workflow/retry +43 -0
  169. data/share/rbbt_commands/workflow/server +12 -2
  170. data/share/rbbt_commands/workflow/task +80 -73
  171. data/share/rbbt_commands/workflow/write_info +26 -9
  172. data/share/software/opt/ssw/ssw.c +861 -0
  173. data/share/software/opt/ssw/ssw.h +130 -0
  174. data/share/workflow_config.ru +3 -3
  175. metadata +45 -6
data/lib/rbbt/workflow.rb CHANGED
@@ -1,882 +1,4 @@
1
- require 'rbbt/workflow/definition'
2
- require 'rbbt/workflow/dependencies'
3
- require 'rbbt/workflow/task'
4
- require 'rbbt/workflow/step'
5
- require 'rbbt/workflow/accessor'
6
- require 'rbbt/workflow/doc'
7
- require 'rbbt/workflow/examples'
8
-
9
- require 'rbbt/workflow/util/archive'
10
- require 'rbbt/workflow/util/provenance'
11
-
12
- module Workflow
13
-
14
- class TaskNotFoundException < Exception
15
- def initialize(workflow, task = nil)
16
- if task
17
- super "Task '#{ task }' not found in #{ workflow } workflow"
18
- else
19
- super workflow
20
- end
21
- end
22
- end
23
-
24
- #{{{ WORKFLOW MANAGEMENT
25
- class << self
26
- attr_accessor :workflows, :autoinstall, :workflow_dir, :main
27
- end
28
-
29
- self.workflows = []
30
-
31
- def self.autoinstall
32
- @autoload ||= ENV["RBBT_WORKFLOW_AUTOINSTALL"] == "true"
33
- end
34
-
35
- def self.extended(base)
36
- self.workflows << base
37
- libdir = Path.caller_lib_dir
38
- return if libdir.nil?
39
- base.libdir = Path.setup(libdir).tap{|p| p.resource = base}
40
- end
41
-
42
- def self.init_remote_tasks
43
- return if defined? @@init_remote_tasks and @@init_remote_tasks
44
- @@init_remote_tasks = true
45
- load_remote_tasks(Rbbt.root.etc.remote_tasks.find) if Rbbt.root.etc.remote_tasks.exists?
46
- end
47
-
48
- def self.init_relay_tasks
49
- return if defined? @@init_relay_tasks and @@init_relay_tasks
50
- @@init_relay_tasks = true
51
- load_relay_tasks(Rbbt.root.etc.relay_tasks.find) if Rbbt.root.etc.relay_tasks.exists?
52
- end
53
-
54
-
55
-
56
- def self.require_remote_workflow(wf_name, url)
57
- require 'rbbt/workflow/remote_workflow'
58
- eval "Object::#{wf_name.split("+").first} = RemoteWorkflow.new '#{ url }', '#{wf_name}'"
59
- end
60
-
61
- def self.load_workflow_libdir(filename)
62
- workflow_lib_dir = File.join(File.dirname(File.expand_path(filename)), 'lib')
63
- if File.directory? workflow_lib_dir
64
- Log.debug "Adding workflow lib directory to LOAD_PATH: #{workflow_lib_dir}"
65
- $LOAD_PATH.unshift(workflow_lib_dir)
66
- end
67
- end
68
-
69
- def self.load_workflow_file(filename)
70
- begin
71
-
72
- load_workflow_libdir(filename)
73
-
74
- filename = File.expand_path(filename)
75
-
76
- Rbbt.add_version(filename)
77
-
78
- require filename
79
- Log.debug{"Workflow loaded from: #{ filename }"}
80
- return true
81
- rescue Exception
82
- Log.warn{"Error loading workflow: #{ filename }"}
83
- raise $!
84
- end
85
- end
86
-
87
- def self.installed_workflows
88
- self.workflow_dir['**/workflow.rb'].glob_all.collect do |file|
89
- File.basename(File.dirname(file))
90
- end
91
- end
92
-
93
- def self.workflow_dir
94
- @workflow_dir ||= begin
95
- case
96
- when (defined?(Rbbt) and Rbbt.etc.workflow_dir.exists?)
97
- dir = Rbbt.etc.workflow_dir.read.strip
98
- dir = File.expand_path(dir)
99
- Path.setup(dir)
100
- when defined?(Rbbt)
101
- Rbbt.workflows
102
- else
103
- dir = File.join(ENV['HOME'], '.workflows')
104
- Path.setup(dir)
105
- end
106
- end
107
- end
108
-
109
- def self.local_workflow_filename(wf_name)
110
- filename = nil
111
-
112
- if Path === wf_name
113
- case
114
- # Points to workflow file
115
- when ((File.exist?(wf_name.find) and not File.directory?(wf_name.find)) or File.exist?(wf_name.find + '.rb'))
116
- filename = wf_name.find
117
-
118
- # Points to workflow dir
119
- when (File.exist?(wf_name.find) and File.directory?(wf_name.find) and File.exist?(File.join(wf_name.find, 'workflow.rb')))
120
- filename = wf_name['workflow.rb'].find
121
- end
122
-
123
- else
124
- if ((File.exist?(wf_name) and not File.directory?(wf_name)) or File.exist?(wf_name + '.rb'))
125
- filename = (wf_name =~ /\.?\//) ? wf_name : "./" << wf_name
126
- else
127
- filename = workflow_dir[wf_name]['workflow.rb'].find
128
- end
129
- end
130
-
131
- if filename.nil? or not File.exist?(filename)
132
- wf_name_snake = Misc.snake_case(wf_name)
133
- return local_workflow_filename(wf_name_snake) if wf_name_snake != wf_name
134
- end
135
-
136
- filename
137
- end
138
-
139
- def self.require_local_workflow(wf_name)
140
-
141
- filename = local_workflow_filename(wf_name)
142
-
143
- if filename and File.exist?(filename)
144
- load_workflow_file filename
145
- else
146
- return false
147
- end
148
- end
149
-
150
- def self.require_workflow(wf_name, force_local=false)
151
- Workflow.init_remote_tasks
152
- Workflow.init_relay_tasks
153
- # Already loaded
154
- begin
155
- workflow = Misc.string2const wf_name
156
- Log.debug{"Workflow #{ wf_name } already loaded"}
157
- return workflow
158
- rescue Exception
159
- end
160
-
161
- # Load remotely
162
- if not force_local and Rbbt.etc.remote_workflows.exists?
163
- remote_workflows = Rbbt.etc.remote_workflows.yaml
164
- if Hash === remote_workflows and remote_workflows.include?(wf_name)
165
- url = remote_workflows[wf_name]
166
- begin
167
- return require_remote_workflow(wf_name, url)
168
- ensure
169
- Log.debug{"Workflow #{ wf_name } loaded remotely: #{ url }"}
170
- end
171
- end
172
- end
173
-
174
- if Open.remote?(wf_name) or Open.ssh?(wf_name)
175
- url = wf_name
176
-
177
- if Open.ssh?(wf_name)
178
- wf_name = File.basename(url.split(":").last)
179
- else
180
- wf_name = File.basename(url)
181
- end
182
-
183
- begin
184
- return require_remote_workflow(wf_name, url)
185
- ensure
186
- Log.debug{"Workflow #{ wf_name } loaded remotely: #{ url }"}
187
- end
188
- end
189
-
190
- # Load locally
191
-
192
- if wf_name =~ /::\w+$/
193
- clean_name = wf_name.sub(/::.*/,'')
194
- Log.info{"Looking for '#{wf_name}' in '#{clean_name}'"}
195
- require_workflow clean_name
196
- workflow = Misc.string2const Misc.camel_case(wf_name)
197
- workflow.load_documentation
198
- return workflow
199
- end
200
-
201
- Log.high{"Loading workflow #{wf_name}"}
202
-
203
- first = nil
204
- wf_name.split("+").each do |wf_name|
205
- self.main = nil
206
- require_local_workflow(wf_name) or
207
- (Workflow.autoinstall and `rbbt workflow install #{Misc.snake_case(wf_name)} || rbbt workflow install #{wf_name}` and require_local_workflow(wf_name)) or raise("Workflow not found or could not be loaded: #{ wf_name }")
208
-
209
- workflow = begin
210
- Misc.string2const Misc.camel_case(wf_name)
211
- rescue
212
- self.main || Workflow.workflows.last
213
- end
214
- workflow.load_documentation
215
-
216
-
217
- first ||= workflow
218
- end
219
-
220
- first.complete_name = wf_name
221
-
222
- return first
223
- end
224
-
225
- attr_accessor :description
226
- attr_accessor :libdir, :workdir
227
- attr_accessor :helpers, :tasks
228
- attr_accessor :task_dependencies, :task_description, :last_task
229
- attr_accessor :stream_exports, :asynchronous_exports, :synchronous_exports, :exec_exports
230
- attr_accessor :step_cache
231
- attr_accessor :load_step_cache
232
- attr_accessor :remote_tasks
233
- attr_accessor :relay_tasks
234
-
235
- #{{{ ATTR DEFAULTS
236
- #
237
- attr_accessor :complete_name
238
-
239
- def self.complete_name
240
- @complete_name ||= self.to_s
241
- end
242
-
243
- def self.workdir=(path)
244
- path = Path.setup path.dup unless Path === path
245
- @@workdir = path
246
- end
247
-
248
- def self.workdir
249
- @@workdir ||= if defined? Rbbt
250
- Rbbt.var.jobs
251
- else
252
- Path.setup('var/jobs')
253
- end
254
- end
255
-
256
- TAG = ENV["RBBT_INPUT_JOBNAME"] == "true" ? :inputs : :hash
257
- DEBUG_JOB_HASH = ENV["RBBT_DEBUG_JOB_HASH"] == 'true'
258
- def step_path(taskname, jobname, inputs, dependencies, extension = nil)
259
- raise "Jobname makes an invalid path: #{ jobname }" if jobname.include? '..'
260
- if inputs.length > 0 or dependencies.any?
261
- tagged_jobname = case TAG
262
- when :hash
263
- clean_inputs = Annotated.purge(inputs)
264
- clean_inputs = clean_inputs.collect{|i| Symbol === i ? i.to_s : i }
265
- deps_str = dependencies.collect{|d| (Step === d || (defined?(RemoteStep) && RemoteStep === d)) ? "Step: " << (Symbol === d.overriden ? d.path : d.short_path) : d }
266
- key_obj = {:inputs => clean_inputs, :dependencies => deps_str }
267
- key_str = Misc.obj2str(key_obj)
268
- hash_str = Misc.digest(key_str)
269
- Log.debug "Hash for '#{[taskname, jobname] * "/"}' #{hash_str} for #{key_str}" if DEBUG_JOB_HASH
270
- jobname + '_' << hash_str
271
- when :inputs
272
- all_inputs = {}
273
- inputs.zip(self.task_info(taskname)[:inputs]) do |i,f|
274
- all_inputs[f] = i
275
- end
276
- dependencies.each do |dep|
277
- ri = dep.recursive_inputs
278
- ri.zip(ri.fields).each do |i,f|
279
- all_inputs[f] = i
280
- end
281
- end
282
-
283
- all_inputs.any? ? jobname + '_' << Misc.obj2str(all_inputs) : jobname
284
- else
285
- jobname
286
- end
287
- else
288
- tagged_jobname = jobname
289
- end
290
-
291
- if extension and not extension.empty?
292
- tagged_jobname = tagged_jobname + ('.' << extension.to_s)
293
- end
294
-
295
- workdir[taskname][tagged_jobname].find
296
- end
297
-
298
- def import_task(workflow, orig, new)
299
- orig_task = workflow.tasks[orig]
300
- new_task = orig_task.dup
301
- options = {}
302
- orig_task.singleton_methods.
303
- select{|method| method.to_s[-1] != "="[0]}.each{|method|
304
- if orig_task.respond_to?(method.to_s + "=")
305
- options[method.to_s] = orig_task.send(method.to_s)
306
- end
307
- }
308
-
309
- Task.setup(options, &new_task)
310
- new_task.workflow = self
311
- new_task.name = new
312
- tasks[new] = new_task
313
- task_dependencies[new] = workflow.task_dependencies[orig]
314
- task_description[new] = workflow.task_description[orig]
315
- end
316
-
317
- def workdir=(path)
318
- path = Path.setup path.dup unless Path === path
319
- @workdir = path
320
- end
321
-
322
- def workdir
323
- @workdir ||= begin
324
- text = Module === self ? self.to_s : "Misc"
325
- Workflow.workdir[text]
326
- end
327
- end
328
-
329
- def libdir
330
- @libdir = Path.setup(Path.caller_lib_dir) if @libdir.nil?
331
- @libdir
332
- end
333
-
334
- def step_cache
335
- Thread.current[:step_cache] ||= {}
336
- end
337
-
338
- def self.load_step_cache
339
- Thread.current[:load_step_cache] ||= {}
340
- end
341
-
342
-
343
- def helpers
344
- @helpers ||= {}
345
- end
346
-
347
- def tasks
348
- @tasks ||= {}
349
- end
350
-
351
- def task_dependencies
352
- @task_dependencies ||= {}
353
- end
354
-
355
- def task_description
356
- @task_description ||= {}
357
- end
358
-
359
- def stream_exports
360
- @stream_exports ||= []
361
- end
362
-
363
- def asynchronous_exports
364
- @asynchronous_exports ||= []
365
- end
366
-
367
- def synchronous_exports
368
- @synchronous_exports ||= []
369
- end
370
-
371
- def exec_exports
372
- @exec_exports ||= []
373
- end
374
-
375
- def all_exports
376
- @all_exports ||= asynchronous_exports + synchronous_exports + exec_exports + stream_exports
377
- end
378
-
379
- def documented_tasks
380
- tasks.select{|k,v| v.description && ! v.description.empty? }.collect{|k,v| k }
381
- end
382
-
383
- # {{{ JOB MANAGEMENT
384
- DEFAULT_NAME="Default"
385
-
386
- def self.resolve_locals(inputs)
387
- inputs.each do |name, value|
388
- if (String === value and value =~ /^local:(.*?):(.*)/) or
389
- (Array === value and value.length == 1 and value.first =~ /^local:(.*?):(.*)/) or
390
- (TSV === value and value.size == 1 and value.keys.first =~ /^local:(.*?):(.*)/)
391
- task_name = $1
392
- jobname = $2
393
- value = load_id(File.join(task_name, jobname)).load
394
- inputs[name] = value
395
- end
396
- end
397
- end
398
-
399
- def step_module
400
- @_m ||= begin
401
- m = Module.new
402
-
403
- helpers.each do |name,block|
404
- m.send(:define_method, name, &block)
405
- end
406
-
407
- m
408
- end
409
- @_m
410
- end
411
-
412
- def __job(taskname, jobname = nil, inputs = {})
413
- taskname = taskname.to_sym
414
- return remote_tasks[taskname].job(taskname, jobname, inputs) if remote_tasks and remote_tasks.include? taskname
415
-
416
- task = tasks[taskname]
417
- raise "Task not found: #{ taskname }" if task.nil?
418
-
419
- inputs = IndiferentHash.setup(inputs)
420
-
421
- not_overriden = inputs.delete :not_overriden
422
- if not_overriden
423
- inputs[:not_overriden] = :not_overriden_dep
424
- end
425
-
426
- Workflow.resolve_locals(inputs)
427
-
428
- task_info = task_info(taskname)
429
- task_inputs = task_info[:inputs]
430
- #defaults = IndiferentHash.setup(task_info[:input_defaults]).merge(task.input_defaults)
431
- all_defaults = IndiferentHash.setup(task_info[:input_defaults])
432
- defaults = IndiferentHash.setup(task.input_defaults)
433
-
434
- missing_inputs = []
435
- task.required_inputs.each do |input|
436
- missing_inputs << input if inputs[input].nil?
437
- end if task.required_inputs
438
-
439
- if missing_inputs.length == 1
440
- raise ParameterException, "Input '#{missing_inputs.first}' is required but was not provided or is nil"
441
- end
442
-
443
- if missing_inputs.length > 1
444
- raise ParameterException, "Inputs #{Misc.humanize_list(missing_inputs)} are required but were not provided or are nil"
445
- end
446
-
447
- # jobname => true sets the value of the input to the name of the job
448
- if task.input_options
449
- jobname_input = task.input_options.select{|i,o| o[:jobname] }.collect{|i,o| i }.first
450
- else
451
- jobname_input = nil
452
- end
453
-
454
- if jobname_input && inputs[jobname_input].nil?
455
- inputs[jobname_input] = jobname || DEFAULT_NAME
456
- end
457
-
458
- real_inputs = {}
459
-
460
- inputs.each do |k,v|
461
- next unless (task_inputs.include?(k.to_sym) or task_inputs.include?(k.to_s))
462
- default = all_defaults[k]
463
- next if default == v
464
- next if (String === default and Symbol === v and v.to_s == default)
465
- next if (Symbol === default and String === v and v == default.to_s)
466
- real_inputs[k.to_sym] = v
467
- end
468
-
469
- jobname_input_value = inputs[jobname_input] || all_defaults[jobname_input]
470
- if jobname_input && jobname.nil? && String === jobname_input_value && ! jobname_input_value.include?('/')
471
- jobname = jobname_input_value
472
- end
473
-
474
- jobname = DEFAULT_NAME if jobname.nil? or jobname.empty?
475
-
476
- dependencies, overriden = real_dependencies(task, jobname, defaults.merge(inputs), task_dependencies[taskname] || [])
477
-
478
- #overriden_deps = dependencies.select{|d| Symbol === d.overriden }
479
- #overriden_target_deps = overriden_deps.select{|d| TrueClass === d.overriden }
480
-
481
- extension = task.extension
482
-
483
- if extension == :dep_task
484
- extension = nil
485
- if dependencies.any?
486
- dep_basename = File.basename(dependencies.last.path)
487
- if dep_basename.include? "."
488
- parts = dep_basename.split(".")
489
- extension = [parts.pop]
490
- while parts.length > 1 && parts.last.length <= 4
491
- extension << parts.pop
492
- end
493
- extension = extension.reverse * "."
494
- end
495
- end
496
- end
497
-
498
- #overriden = true if dependencies.select{|d| d.overriden && d.clean_name != d.name }.any?
499
- overriden = true if ! not_overriden && dependencies.select{|d| Symbol === d.overriden }.any?
500
-
501
- input_values = task.take_input_values(inputs)
502
- if real_inputs.empty? && Workflow::TAG != :inputs && ! overriden #&& ! dependencies.select{|d| d.overriden && d.clean_name != d.name }.any?
503
- step_path = step_path taskname, jobname, [], [], extension
504
- else
505
- step_path = step_path taskname, jobname, input_values, dependencies, extension
506
- end
507
-
508
- job = get_job_step step_path, task, input_values, dependencies
509
- job.workflow = self
510
- job.overriden = overriden if job.overriden.nil?
511
- job.clean_name = jobname
512
-
513
- #iif [job, not_overriden]
514
- #case not_overriden
515
- #when TrueClass
516
- # job.overriden = false
517
- #when :not_overriden_dep
518
- # job.overriden = true if overriden_target_deps.any?
519
- #else
520
- # job.overriden = true if overriden_deps.any?
521
- #end
522
-
523
- job.real_inputs = real_inputs.keys
524
- job
525
- end
526
-
527
- def _job(taskname, jobname = nil, inputs = {})
528
-
529
- task_info = task_info(taskname)
530
- task_inputs = task_info[:inputs]
531
- persist_inputs = inputs.values_at(*task_inputs)
532
- persist_inputs += inputs.values_at(*inputs.keys.select{|k| String === k && k.include?("#") }.sort)
533
- Persist.memory("STEP", :workflow => self.to_s, :taskname => taskname, :jobname => jobname, :inputs => persist_inputs, :repo => step_cache) do
534
- __job(taskname, jobname, inputs)
535
- end
536
- end
537
-
538
- def job(taskname, jobname = nil, inputs = {})
539
- inputs, jobname = jobname, nil if Hash === jobname
540
- begin
541
- _job(taskname, jobname, inputs)
542
- ensure
543
- step_cache.clear
544
- end
545
- end
546
-
547
-
548
- def set_step_dependencies(step)
549
- if step.info[:dependencies]
550
- Misc.insist do
551
- step.dependencies = step.info[:dependencies].collect do |task, job, path|
552
- next if job.nil?
553
- if Open.exists?(path)
554
- load_step(path)
555
- else
556
- Workflow.load_step(path)
557
- end
558
- end
559
- end
560
- end
561
- end
562
-
563
- #{{{ LOAD FROM FILE
564
-
565
- def get_job_step(step_path, task = nil, input_values = nil, dependencies = nil)
566
- step_path = step_path.call if Proc === step_path
567
- persist = input_values.nil? ? false : true
568
- persist = false
569
-
570
- if ! (Path === step_path ? step_path.find : File.exist?(step_path)) &&
571
- step_path.split("/").length == 3 &&
572
- File.exist?(new_path = Rbbt.var.jobs[step_path].find)
573
-
574
- step_path = new_path
575
- end
576
-
577
- key = Path === step_path ? step_path.find : step_path
578
-
579
- if ! File.exist?(step_path) && step_path.split("/").length == 3 && File.exist?(new_path = Rbbt.var.jobs[step_path].find)
580
- step_path = new_path
581
- end
582
-
583
- step = Step.new step_path, task, input_values, dependencies
584
-
585
- set_step_dependencies(step) unless dependencies
586
-
587
- step.extend step_module
588
-
589
- step.task ||= task
590
- step.inputs ||= input_values
591
- step.dependencies = dependencies if dependencies and (step.dependencies.nil? or step.dependencies.length < dependencies.length)
592
-
593
- step
594
- end
595
-
596
- def load_step(path)
597
- task = task_for path
598
- if task
599
- get_job_step path, tasks[task.to_sym]
600
- else
601
- get_job_step path
602
- end
603
- end
604
-
605
- def self.transplant(listed, real, other)
606
- if listed.nil?
607
- parts = real.split("/")
608
- other_parts = other.split("/")
609
- listed = (other_parts[0..-4] + parts[-3..-1]) * "/"
610
- end
611
-
612
- sl = listed.split("/", -1)
613
- so = other.split("/", -1)
614
- sr = real.split("/", -1)
615
- prefix = []
616
- while true
617
- break if sl[0] != so[0]
618
- cl = sl.shift
619
- co = so.shift
620
- prefix << cl
621
- end
622
- File.join(sr - sl + so)
623
- end
624
-
625
- def self.relocate_array(real, list)
626
- preal = real.split(/\/+/)
627
- prefix = preal[0..-4] * "/"
628
- list.collect do |other|
629
- pother = other.split(/\/+/)
630
- end_part = pother[-3..-1] * "/"
631
- new_path = prefix + "/" << end_part
632
- if File.exist? new_path
633
- new_path
634
- else
635
- Rbbt.var.jobs[end_part].find
636
- end
637
- end
638
- end
639
-
640
- def self.relocate(real, other)
641
- preal = real.split(/\/+/)
642
- pother = other.split(/\/+/)
643
- end_part = pother[-3..-1] * "/"
644
- new_path = preal[0..-4] * "/" << "/" << end_part
645
- return new_path if File.exist?(new_path) || File.exist?(new_path + '.info')
646
- Rbbt.var.jobs[end_part].find
647
- end
648
-
649
- def self.relocate_dependency(main, dep)
650
- dep_path = dep.path
651
- path = main.path
652
- if Open.exists?(dep_path) || Open.exists?(dep_path + '.info')
653
- dep
654
- else
655
- new_path = relocate(path, dep_path)
656
- relocated = true if Open.exists?(new_path) || Open.exists?(new_path + '.info')
657
- Workflow._load_step new_path
658
- end
659
- end
660
-
661
- def self.__load_step(path)
662
- if Open.remote?(path) || Open.ssh?(path)
663
- require 'rbbt/workflow/remote_workflow'
664
- return RemoteWorkflow.load_path path
665
- end
666
- step = Step.new path
667
- relocated = false
668
- dependencies = (step.info[:dependencies] || []).collect do |task,name,dep_path|
669
- dep_path = task if dep_path.nil?
670
- if Open.exists?(dep_path) || Open.exists?(dep_path + '.info') || Open.remote?(dep_path) || Open.ssh?(dep_path)
671
- Workflow._load_step dep_path
672
- else
673
- new_path = relocate(path, dep_path)
674
- relocated = true if Open.exists?(new_path) || Open.exists?(new_path + '.info')
675
- Workflow._load_step new_path
676
- end
677
- end
678
- step.instance_variable_set("@dependencies", dependencies)
679
- step.relocated = relocated
680
- step.load_inputs_from_info
681
- step
682
- end
683
-
684
- def self.fast_load_step(path)
685
- if Open.remote?(path) || Open.ssh?(path)
686
- require 'rbbt/workflow/remote_workflow'
687
- return RemoteWorkflow.load_path path
688
- end
689
-
690
- step = Step.new path
691
- step.dependencies = nil
692
- class << step
693
- def dependencies
694
- @dependencies ||= (self.info[:dependencies] || []).collect do |task,name,dep_path|
695
- dep = if Open.exists?(dep_path) || Open.exists?(dep_path + '.info')
696
- relocate = false
697
- Workflow.fast_load_step dep_path
698
- else
699
- new_path = Workflow.relocate(path, dep_path)
700
- relocated = true if Open.exists?(new_path) || Open.exists?(new_path + '.info')
701
- Workflow.fast_load_step new_path
702
- end
703
- dep.relocated = relocated
704
- dep
705
- end
706
- @dependencies
707
- end
708
-
709
- def inputs
710
- self.load_inputs_from_info unless @inputs
711
- @inputs
712
- end
713
-
714
- def dirty?
715
- false
716
- end
717
-
718
- def updated?
719
- true
720
- end
721
- end
722
-
723
- if ! Open.exists?(step.info_file)
724
- begin
725
- workflow = step.path.split("/")[-3]
726
- task_name = step.path.split("/")[-2]
727
- workflow = Kernel.const_get workflow
728
- step.task = workflow.tasks[task_name.to_sym]
729
- rescue
730
- Log.exception $!
731
- end
732
- end
733
- step
734
- end
735
-
736
- def self._load_step(path)
737
- Persist.memory("STEP", :path => path, :repo => load_step_cache) do
738
- __load_step(path)
739
- end
740
- end
741
-
742
- def self.load_step(path)
743
- path = Path.setup(path.dup) unless Path === path
744
-
745
- if ! (Path === path ? path.exists? : File.exist?(path)) && path.split("/").length == 3
746
- new_path = Rbbt.var.jobs[path]
747
- if new_path.exists? || new_path.set_extension('info').exists?
748
- path = new_path
749
- end
750
- end
751
-
752
- path = path.find if Path === path
753
-
754
- begin
755
- _load_step(path)
756
- ensure
757
- load_step_cache.clear
758
- end
759
- end
760
-
761
- def load_id(id)
762
- path = if Path === workdir
763
- workdir[id].find
764
- else
765
- File.join(workdir, id)
766
- end
767
- task = task_for path
768
- return remote_tasks[task].load_id(id) if remote_tasks && remote_tasks.include?(task)
769
- return Workflow.load_step path
770
- end
771
-
772
-
773
- def fast_load_id(id)
774
- path = if Path === workdir
775
- workdir[id].find
776
- else
777
- File.join(workdir, id)
778
- end
779
- task = task_for path
780
- return remote_tasks[task].load_id(id) if remote_tasks && remote_tasks.include?(task)
781
- return Workflow.fast_load_step path
782
- end
783
-
784
- def load_name(task, name)
785
- return remote_tasks[task].load_step(path) if remote_tasks and remote_tasks.include? task
786
- task = tasks[task.to_sym] if String === task or Symbol === task
787
- path = step_path task.name, name, [], [], task.extension
788
- get_job_step path, task
789
- end
790
-
791
- #}}} LOAD FROM FILE
792
-
793
- def jobs(taskname, query = nil)
794
- task_dir = File.join(File.expand_path(workdir.find), taskname.to_s)
795
- pattern = File.join(File.expand_path(task_dir), '**/*')
796
- job_info_files = Dir.glob(Step.info_file(pattern)).collect{|f| Misc.path_relative_to task_dir, f }
797
- job_info_files = job_info_files.select{|f| f.index(query) == 0 } if query
798
- job_info_files.collect{|f|
799
- job_name = Step.job_name_for_info_file(f, tasks[taskname].extension)
800
- }
801
- end
802
-
803
- #{{{ Make workflow resources local
804
- def local_persist_setup
805
- class << self
806
- include LocalPersist
807
- end
808
- self.local_persist_dir = Rbbt.var.cache.persistence.find :lib
809
- end
810
-
811
- def local_workdir_setup
812
- self.workdir = Rbbt.var.jobs.find :lib
813
- end
814
-
815
- def make_local
816
- local_persist_setup
817
- local_workdir_setup
818
- end
819
-
820
- def with_workdir(workdir)
821
- saved = self.workdir
822
- begin
823
- self.workdir = Path.setup(File.expand_path(workdir))
824
- yield
825
- ensure
826
- self.workdir = saved
827
- end
828
- end
829
-
830
- def add_remote_tasks(remote_tasks)
831
- remote_tasks.each do |remote, tasks|
832
- tasks.each do |task|
833
- self.remote_tasks[task.to_f] = remote
834
- end
835
- end
836
- end
837
-
838
- def self.process_remote_tasks(remote_tasks)
839
- require 'rbbt/workflow/remote_workflow'
840
- remote_tasks.each do |workflow, info|
841
- wf = Workflow.require_workflow workflow
842
- wf.remote_tasks ||= {}
843
- IndiferentHash.setup wf.remote_tasks
844
- info.each do |remote, tasks|
845
- remote_wf = RemoteWorkflow.new remote, workflow
846
- tasks.each do |task|
847
- Log.debug "Add remote task #{task} in #{wf} using #{remote_wf.url}"
848
- wf.remote_tasks[task.to_sym] = remote_wf
849
- end
850
- end
851
- end
852
- end
853
-
854
- def self.load_remote_tasks(filename)
855
- remote_workflow_tasks = Misc.load_yaml(filename)
856
- Workflow.process_remote_tasks(remote_workflow_tasks)
857
- end
858
-
859
- def self.process_relay_tasks(relay_tasks)
860
- require 'rbbt/workflow/remote_workflow'
861
- relay_tasks.each do |workflow, servers|
862
- wf = Workflow.require_workflow workflow
863
- wf.relay_tasks ||= {}
864
- IndiferentHash.setup wf.relay_tasks
865
- servers.each do |server, tasks|
866
- case tasks
867
- when Array
868
- tasks.each do |task|
869
- wf.relay_tasks[task.to_sym] = [server, {:migrate => :true}]
870
- end
871
- else
872
- wf.relay_tasks[tasks.to_sym] = [server, {:migrate => :true}]
873
- end
874
- end
875
- end
876
- end
877
-
878
- def self.load_relay_tasks(filename)
879
- relay_workflow_tasks = Misc.load_yaml(filename)
880
- Workflow.process_relay_tasks(relay_workflow_tasks)
881
- end
882
- end
1
+ require_relative 'util/misc/refactor'
2
+ Rbbt.require_instead 'scout/workflow'
3
+ require_relative 'workflow/refactor'
4
+ require_relative 'workflow/util/archive'