rbbt-util 5.44.1 → 6.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (167) hide show
  1. checksums.yaml +4 -4
  2. data/bin/rbbt +67 -90
  3. data/etc/app.d/base.rb +2 -2
  4. data/etc/app.d/semaphores.rb +3 -3
  5. data/lib/rbbt/annotations/annotated_array.rb +207 -207
  6. data/lib/rbbt/annotations/refactor.rb +27 -0
  7. data/lib/rbbt/annotations/util.rb +282 -282
  8. data/lib/rbbt/annotations.rb +343 -320
  9. data/lib/rbbt/association/database.rb +200 -225
  10. data/lib/rbbt/association/index.rb +294 -291
  11. data/lib/rbbt/association/item.rb +227 -227
  12. data/lib/rbbt/association/open.rb +35 -34
  13. data/lib/rbbt/association/util.rb +0 -169
  14. data/lib/rbbt/association.rb +2 -4
  15. data/lib/rbbt/entity/identifiers.rb +119 -118
  16. data/lib/rbbt/entity/refactor.rb +12 -0
  17. data/lib/rbbt/entity.rb +319 -315
  18. data/lib/rbbt/hpc/batch.rb +72 -53
  19. data/lib/rbbt/hpc/lsf.rb +2 -2
  20. data/lib/rbbt/hpc/orchestrate/batches.rb +2 -2
  21. data/lib/rbbt/hpc/orchestrate/chains.rb +25 -5
  22. data/lib/rbbt/hpc/orchestrate/rules.rb +2 -2
  23. data/lib/rbbt/hpc/orchestrate.rb +19 -13
  24. data/lib/rbbt/hpc/slurm.rb +18 -18
  25. data/lib/rbbt/knowledge_base/entity.rb +13 -5
  26. data/lib/rbbt/knowledge_base/query.rb +2 -2
  27. data/lib/rbbt/knowledge_base/registry.rb +32 -31
  28. data/lib/rbbt/knowledge_base/traverse.rb +1 -1
  29. data/lib/rbbt/knowledge_base.rb +1 -1
  30. data/lib/rbbt/monitor.rb +36 -25
  31. data/lib/rbbt/persist/refactor.rb +166 -0
  32. data/lib/rbbt/persist/tsv/tokyocabinet.rb +105 -105
  33. data/lib/rbbt/persist/tsv.rb +187 -185
  34. data/lib/rbbt/persist.rb +556 -551
  35. data/lib/rbbt/refactor.rb +20 -0
  36. data/lib/rbbt/resource/path/refactor.rb +178 -0
  37. data/lib/rbbt/resource/path.rb +317 -497
  38. data/lib/rbbt/resource/util.rb +0 -48
  39. data/lib/rbbt/resource.rb +3 -390
  40. data/lib/rbbt/tsv/accessor.rb +2 -838
  41. data/lib/rbbt/tsv/attach.rb +303 -299
  42. data/lib/rbbt/tsv/change_id.rb +244 -245
  43. data/lib/rbbt/tsv/csv.rb +87 -85
  44. data/lib/rbbt/tsv/dumper.rb +2 -100
  45. data/lib/rbbt/tsv/excel.rb +26 -24
  46. data/lib/rbbt/tsv/field_index.rb +4 -1
  47. data/lib/rbbt/tsv/filter.rb +3 -2
  48. data/lib/rbbt/tsv/index.rb +2 -284
  49. data/lib/rbbt/tsv/manipulate.rb +750 -747
  50. data/lib/rbbt/tsv/marshal.rb +3 -3
  51. data/lib/rbbt/tsv/matrix.rb +2 -2
  52. data/lib/rbbt/tsv/parallel/through.rb +2 -1
  53. data/lib/rbbt/tsv/parallel/traverse.rb +783 -781
  54. data/lib/rbbt/tsv/parser.rb +678 -678
  55. data/lib/rbbt/tsv/refactor.rb +195 -0
  56. data/lib/rbbt/tsv/stream.rb +253 -251
  57. data/lib/rbbt/tsv/util.rb +420 -420
  58. data/lib/rbbt/tsv.rb +210 -208
  59. data/lib/rbbt/util/R/eval.rb +4 -4
  60. data/lib/rbbt/util/R/plot.rb +62 -166
  61. data/lib/rbbt/util/R.rb +21 -18
  62. data/lib/rbbt/util/cmd.rb +2 -318
  63. data/lib/rbbt/util/color.rb +269 -269
  64. data/lib/rbbt/util/colorize.rb +89 -89
  65. data/lib/rbbt/util/concurrency/processes/refactor.rb +22 -0
  66. data/lib/rbbt/util/concurrency/processes/worker.rb +2 -2
  67. data/lib/rbbt/util/concurrency/processes.rb +389 -386
  68. data/lib/rbbt/util/config.rb +169 -167
  69. data/lib/rbbt/util/iruby.rb +20 -0
  70. data/lib/rbbt/util/log/progress/report.rb +241 -241
  71. data/lib/rbbt/util/log/progress/util.rb +99 -99
  72. data/lib/rbbt/util/log/progress.rb +102 -102
  73. data/lib/rbbt/util/log/refactor.rb +49 -0
  74. data/lib/rbbt/util/log.rb +486 -532
  75. data/lib/rbbt/util/migrate.rb +1 -1
  76. data/lib/rbbt/util/misc/concurrent_stream.rb +248 -246
  77. data/lib/rbbt/util/misc/development.rb +12 -11
  78. data/lib/rbbt/util/misc/exceptions.rb +117 -112
  79. data/lib/rbbt/util/misc/format.rb +2 -230
  80. data/lib/rbbt/util/misc/indiferent_hash.rb +2 -107
  81. data/lib/rbbt/util/misc/inspect.rb +2 -476
  82. data/lib/rbbt/util/misc/lock.rb +109 -106
  83. data/lib/rbbt/util/misc/omics.rb +9 -1
  84. data/lib/rbbt/util/misc/pipes.rb +765 -793
  85. data/lib/rbbt/util/misc/refactor.rb +20 -0
  86. data/lib/rbbt/util/misc/ssw.rb +27 -17
  87. data/lib/rbbt/util/misc/system.rb +0 -15
  88. data/lib/rbbt/util/misc.rb +39 -20
  89. data/lib/rbbt/util/named_array/refactor.rb +4 -0
  90. data/lib/rbbt/util/named_array.rb +3 -220
  91. data/lib/rbbt/util/open/refactor.rb +7 -0
  92. data/lib/rbbt/util/open.rb +3 -857
  93. data/lib/rbbt/util/procpath.rb +6 -6
  94. data/lib/rbbt/util/python/paths.rb +27 -0
  95. data/lib/rbbt/util/python/run.rb +115 -0
  96. data/lib/rbbt/util/python/script.rb +110 -0
  97. data/lib/rbbt/util/python/util.rb +3 -3
  98. data/lib/rbbt/util/python.rb +22 -81
  99. data/lib/rbbt/util/semaphore.rb +152 -148
  100. data/lib/rbbt/util/simpleopt.rb +9 -8
  101. data/lib/rbbt/util/ssh/refactor.rb +19 -0
  102. data/lib/rbbt/util/ssh.rb +122 -118
  103. data/lib/rbbt/util/tar.rb +117 -115
  104. data/lib/rbbt/util/tmpfile.rb +69 -67
  105. data/lib/rbbt/util/version.rb +2 -0
  106. data/lib/rbbt/workflow/refactor/entity.rb +11 -0
  107. data/lib/rbbt/workflow/refactor/export.rb +66 -0
  108. data/lib/rbbt/workflow/refactor/inputs.rb +24 -0
  109. data/lib/rbbt/workflow/refactor/recursive.rb +64 -0
  110. data/lib/rbbt/workflow/refactor/task_info.rb +65 -0
  111. data/lib/rbbt/workflow/refactor.rb +153 -0
  112. data/lib/rbbt/workflow/remote_workflow/driver/ssh.rb +55 -32
  113. data/lib/rbbt/workflow/remote_workflow/remote_step/rest.rb +3 -1
  114. data/lib/rbbt/workflow/remote_workflow/remote_step/ssh.rb +14 -5
  115. data/lib/rbbt/workflow/remote_workflow/remote_step.rb +19 -7
  116. data/lib/rbbt/workflow/remote_workflow.rb +6 -1
  117. data/lib/rbbt/workflow/step/run.rb +766 -766
  118. data/lib/rbbt/workflow/step/save_load_inputs.rb +254 -254
  119. data/lib/rbbt/workflow/step.rb +2 -362
  120. data/lib/rbbt/workflow/task.rb +118 -118
  121. data/lib/rbbt/workflow/usage.rb +289 -287
  122. data/lib/rbbt/workflow/util/archive.rb +6 -5
  123. data/lib/rbbt/workflow/util/data.rb +1 -1
  124. data/lib/rbbt/workflow/util/orchestrator.rb +249 -246
  125. data/lib/rbbt/workflow/util/trace.rb +79 -44
  126. data/lib/rbbt/workflow.rb +4 -882
  127. data/lib/rbbt-util.rb +21 -13
  128. data/lib/rbbt.rb +16 -3
  129. data/python/rbbt/__init__.py +19 -1
  130. data/share/Rlib/plot.R +37 -37
  131. data/share/Rlib/svg.R +22 -5
  132. data/share/install/software/lib/install_helpers +1 -1
  133. data/share/rbbt_commands/hpc/list +2 -3
  134. data/share/rbbt_commands/hpc/orchestrate +4 -4
  135. data/share/rbbt_commands/hpc/tail +2 -0
  136. data/share/rbbt_commands/hpc/task +10 -7
  137. data/share/rbbt_commands/lsf/list +2 -3
  138. data/share/rbbt_commands/lsf/orchestrate +4 -4
  139. data/share/rbbt_commands/lsf/tail +2 -0
  140. data/share/rbbt_commands/lsf/task +10 -7
  141. data/share/rbbt_commands/migrate +1 -1
  142. data/share/rbbt_commands/pbs/list +2 -3
  143. data/share/rbbt_commands/pbs/orchestrate +4 -4
  144. data/share/rbbt_commands/pbs/tail +2 -0
  145. data/share/rbbt_commands/pbs/task +10 -7
  146. data/share/rbbt_commands/resource/produce +8 -1
  147. data/share/rbbt_commands/slurm/list +2 -3
  148. data/share/rbbt_commands/slurm/orchestrate +4 -4
  149. data/share/rbbt_commands/slurm/tail +2 -0
  150. data/share/rbbt_commands/slurm/task +10 -7
  151. data/share/rbbt_commands/system/clean +5 -5
  152. data/share/rbbt_commands/system/status +5 -5
  153. data/share/rbbt_commands/tsv/get +2 -3
  154. data/share/rbbt_commands/tsv/info +10 -13
  155. data/share/rbbt_commands/tsv/keys +18 -14
  156. data/share/rbbt_commands/tsv/slice +2 -2
  157. data/share/rbbt_commands/tsv/transpose +6 -2
  158. data/share/rbbt_commands/workflow/info +20 -24
  159. data/share/rbbt_commands/workflow/list +1 -1
  160. data/share/rbbt_commands/workflow/prov +20 -13
  161. data/share/rbbt_commands/workflow/server +11 -1
  162. data/share/rbbt_commands/workflow/task +76 -71
  163. data/share/rbbt_commands/workflow/write_info +26 -9
  164. data/share/software/opt/ssw/ssw.c +861 -0
  165. data/share/software/opt/ssw/ssw.h +130 -0
  166. data/share/workflow_config.ru +3 -3
  167. metadata +40 -2
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'