xpflow 0.1b

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/bin/xpflow +96 -0
  2. data/lib/colorado.rb +198 -0
  3. data/lib/json/add/core.rb +243 -0
  4. data/lib/json/add/rails.rb +8 -0
  5. data/lib/json/common.rb +423 -0
  6. data/lib/json/editor.rb +1369 -0
  7. data/lib/json/ext.rb +28 -0
  8. data/lib/json/pure/generator.rb +442 -0
  9. data/lib/json/pure/parser.rb +320 -0
  10. data/lib/json/pure.rb +15 -0
  11. data/lib/json/version.rb +8 -0
  12. data/lib/json.rb +62 -0
  13. data/lib/mime/types.rb +881 -0
  14. data/lib/mime-types.rb +3 -0
  15. data/lib/restclient/abstract_response.rb +106 -0
  16. data/lib/restclient/exceptions.rb +193 -0
  17. data/lib/restclient/net_http_ext.rb +55 -0
  18. data/lib/restclient/payload.rb +235 -0
  19. data/lib/restclient/raw_response.rb +34 -0
  20. data/lib/restclient/request.rb +316 -0
  21. data/lib/restclient/resource.rb +169 -0
  22. data/lib/restclient/response.rb +24 -0
  23. data/lib/restclient.rb +174 -0
  24. data/lib/xpflow/bash.rb +341 -0
  25. data/lib/xpflow/bundle.rb +113 -0
  26. data/lib/xpflow/cmdline.rb +249 -0
  27. data/lib/xpflow/collection.rb +122 -0
  28. data/lib/xpflow/concurrency.rb +79 -0
  29. data/lib/xpflow/data.rb +393 -0
  30. data/lib/xpflow/dsl.rb +816 -0
  31. data/lib/xpflow/engine.rb +574 -0
  32. data/lib/xpflow/ensemble.rb +135 -0
  33. data/lib/xpflow/events.rb +56 -0
  34. data/lib/xpflow/experiment.rb +65 -0
  35. data/lib/xpflow/exts/facter.rb +30 -0
  36. data/lib/xpflow/exts/g5k.rb +931 -0
  37. data/lib/xpflow/exts/g5k_use.rb +50 -0
  38. data/lib/xpflow/exts/gui.rb +140 -0
  39. data/lib/xpflow/exts/model.rb +155 -0
  40. data/lib/xpflow/graph.rb +1603 -0
  41. data/lib/xpflow/graph_xpflow.rb +251 -0
  42. data/lib/xpflow/import.rb +196 -0
  43. data/lib/xpflow/library.rb +349 -0
  44. data/lib/xpflow/logging.rb +153 -0
  45. data/lib/xpflow/manager.rb +147 -0
  46. data/lib/xpflow/nodes.rb +1250 -0
  47. data/lib/xpflow/runs.rb +773 -0
  48. data/lib/xpflow/runtime.rb +125 -0
  49. data/lib/xpflow/scope.rb +168 -0
  50. data/lib/xpflow/ssh.rb +186 -0
  51. data/lib/xpflow/stat.rb +50 -0
  52. data/lib/xpflow/stdlib.rb +381 -0
  53. data/lib/xpflow/structs.rb +369 -0
  54. data/lib/xpflow/taktuk.rb +193 -0
  55. data/lib/xpflow/templates/ssh-config.basic +14 -0
  56. data/lib/xpflow/templates/ssh-config.inria +18 -0
  57. data/lib/xpflow/templates/ssh-config.proxy +13 -0
  58. data/lib/xpflow/templates/taktuk +6590 -0
  59. data/lib/xpflow/templates/utils/batch +4 -0
  60. data/lib/xpflow/templates/utils/bootstrap +12 -0
  61. data/lib/xpflow/templates/utils/hostname +3 -0
  62. data/lib/xpflow/templates/utils/ping +3 -0
  63. data/lib/xpflow/templates/utils/rsync +12 -0
  64. data/lib/xpflow/templates/utils/scp +17 -0
  65. data/lib/xpflow/templates/utils/scp_many +8 -0
  66. data/lib/xpflow/templates/utils/ssh +3 -0
  67. data/lib/xpflow/templates/utils/ssh-interactive +4 -0
  68. data/lib/xpflow/templates/utils/taktuk +19 -0
  69. data/lib/xpflow/threads.rb +187 -0
  70. data/lib/xpflow/utils.rb +569 -0
  71. data/lib/xpflow/visual.rb +230 -0
  72. data/lib/xpflow/with_g5k.rb +7 -0
  73. data/lib/xpflow.rb +349 -0
  74. metadata +135 -0
data/lib/xpflow/dsl.rb ADDED
@@ -0,0 +1,816 @@
1
+ # encoding: UTF-8
2
+
3
+ #
4
+ # DSL implementation.
5
+ #
6
+
7
+ module XPFlow
8
+
9
+ class LibraryLink
10
+
11
+ constructor :process, :key, :parts
12
+
13
+ def method_missing(method, *args, &block)
14
+ new_parts = @parts + [ method.to_s ]
15
+ full_name = new_parts.join(".")
16
+ obj = @process.library.resolve_name(full_name)
17
+ if obj.nil?
18
+ raise "No such object '#{full_name}'"
19
+ end
20
+ if obj.is_a?(Library)
21
+ raise NoMethodError, "Library referencing requires no args" if args.length > 0
22
+ else
23
+ # activity/process
24
+ args = XPValue.flatten(args)
25
+ full_name = XPValue.flatten(full_name)
26
+ run = RunDSL.new(@process, @key, full_name, args, {}, block)
27
+ return @process.push(run)
28
+ end
29
+ return LibraryLink.new(@process, @key, new_parts)
30
+ end
31
+ end
32
+
33
+ class Key
34
+
35
+ def initialize(array)
36
+ @array = array
37
+ end
38
+
39
+ end
40
+
41
+ class DSL
42
+
43
+ def initialize(process, key)
44
+ @process = process
45
+ if key.nil?
46
+ @_key = []
47
+ elsif key.is_a?(Array)
48
+ @_key = key
49
+ elsif key.is_a?(String)
50
+ @_key = from_string(key)
51
+ else
52
+ raise "Unsupported key type"
53
+ end
54
+ @current_key = -1
55
+ @keys = []
56
+ end
57
+
58
+ def from_string(s) # string => Array
59
+ raise "error" unless s.start_with?("/")
60
+ arr = s.split("/"); arr.shift
61
+ return arr
62
+ end
63
+
64
+ def to_string(arr)
65
+ return "/" + arr.join("/")
66
+ end
67
+
68
+ def key
69
+ return to_string(@_key)
70
+ end
71
+
72
+ def new_key
73
+ @current_key += 1
74
+ key = @_key + [ @current_key ]
75
+ @keys.push(key)
76
+ return to_string(key)
77
+ end
78
+
79
+ def parse(*args, &block)
80
+ begin
81
+ $current_dsl.push(self)
82
+ self.instance_exec(*args, &block)
83
+ ensure
84
+ $current_dsl.pop
85
+ end
86
+ return self
87
+ end
88
+
89
+ def repr
90
+ {
91
+ :key => key()
92
+ }
93
+ end
94
+
95
+ end
96
+
97
+ $current_dsl = []
98
+
99
+ class DSLVariable
100
+
101
+ include Operations
102
+
103
+ attr_reader :key
104
+ constructor :key
105
+
106
+ def to_s
107
+ "Var[-@@@@-#{key}-@@@@-]"
108
+ end
109
+
110
+ def self.replace(s, scope)
111
+ out = s.gsub(/Var\[-@@@@-([\/\d]+)-@@@@-\]/) do |m|
112
+ key = $1
113
+ scope.get(key).to_s
114
+ end
115
+ return out
116
+ end
117
+
118
+ def to_ary
119
+ return 10.times.map do |i|
120
+ u = XPValue.flatten(self)
121
+ u.index(XPConst.new(i))
122
+ end
123
+ end
124
+
125
+ def as_s
126
+ return method_missing(:to_s)
127
+ end
128
+
129
+ def as_i
130
+ return method_missing(:to_i)
131
+ end
132
+
133
+ def method_missing(method, *args)
134
+ dsl = $current_dsl.last
135
+ raise "Fatal error" if dsl.nil?
136
+ raise "Arguments are unsupported" if args.length > 0
137
+ return dsl.get_of(self, method)
138
+ end
139
+
140
+ end
141
+
142
+ class RunDSL < DSL
143
+
144
+ constructor [ :process, :key ], :name, :args, :opts, :block
145
+
146
+ def repr
147
+ super.merge({
148
+ :type => :run,
149
+ :name => @name,
150
+ :args => @args,
151
+ :opts => @opts
152
+ })
153
+ end
154
+
155
+ def collect_meta(xxxx)
156
+ {
157
+
158
+ }
159
+ end
160
+
161
+ def as_run
162
+ return ActivityRun.new(key, @name, @args, @opts, @block)
163
+ end
164
+
165
+ end
166
+
167
+ class ReturnLoopDSL < DSL
168
+
169
+ constructor [ :process, :key ], :flag, :cond, :value
170
+
171
+ def as_run
172
+ return ReturnLoopRun.new(key, @flag, @cond, @value)
173
+ end
174
+ end
175
+
176
+ class CheckpointDSL < DSL
177
+
178
+ constructor [ :process, :key ], :name, :opts, :parent
179
+
180
+ def as_run
181
+ return CheckpointRun.new(new_key, @name, @opts, @parent)
182
+ end
183
+ end
184
+
185
+ class OtherwiseDSL < DSL
186
+
187
+ constructor [ :process, :key ]
188
+
189
+ end
190
+
191
+ class ListDSL < DSL
192
+
193
+ constructor [ :process, :key ], :list
194
+
195
+ def __list__
196
+ return @list
197
+ end
198
+
199
+ def __as_run__
200
+ return @list.map(&:as_run)
201
+ end
202
+
203
+ def push(x, inc = 0)
204
+ @list.push(x)
205
+ return DSLVariable.new(x.key)
206
+ end
207
+
208
+ def parse_and_push(dsl, *args, &block)
209
+ return push(dsl.parse(*args, &block))
210
+ end
211
+
212
+ def as_run
213
+ runs = __as_run__
214
+ return SequenceRun.new(key, runs)
215
+ end
216
+
217
+ def __workflow__(*args)
218
+ block, _ = @process.current_workflow
219
+ seq = SequenceDSL.new(@process, new_key)
220
+ return parse_and_push(seq, *args, &block)
221
+ end
222
+
223
+ ### DSL PART ###
224
+
225
+ def parallel(opts = {}, &block)
226
+ retries = opts[:retry]
227
+ if retries.nil?
228
+ dsl = ParallelDSL.new(@process, new_key)
229
+ return parse_and_push(dsl, &block)
230
+ else
231
+ try :retry => retries do
232
+ parallel(&block)
233
+ end
234
+ end
235
+ end
236
+
237
+ def any(&block)
238
+ one = XPValue.flatten(-1)
239
+ dsl = ManyDSL.new(@process, new_key, one)
240
+ return parse_and_push(dsl, &block)
241
+ end
242
+
243
+ def many(arg, &block)
244
+ n = XPValue.flatten(arg)
245
+ dsl = ManyDSL.new(@process, new_key, n)
246
+ return parse_and_push(dsl, &block)
247
+ end
248
+
249
+ def formany(arg, array, &block)
250
+ n = XPValue.flatten(arg)
251
+ array = XPValue.flatten(array)
252
+ dsl = ForManyDSL.new(@process, new_key, n, array)
253
+ return parse_and_push(dsl, &block)
254
+ end
255
+
256
+ def sequence(&block)
257
+ dsl = SequenceDSL.new(@process, new_key)
258
+ return parse_and_push(dsl, &block)
259
+ end
260
+
261
+ def seq(&block)
262
+ return sequence(&block)
263
+ end
264
+
265
+ def seqtry(&block)
266
+ dsl = SeqtryDSL.new(@process, new_key)
267
+ return parse_and_push(dsl, &block)
268
+ end
269
+
270
+ def foreach(array, opts = {}, &block)
271
+ array = XPValue.flatten(array)
272
+ opts = XPValue.flatten(opts)
273
+ dsl = ForEachDSL.new(@process, new_key, array, opts)
274
+ return parse_and_push(dsl, &block)
275
+ end
276
+
277
+ def forall(array, opts = {}, &block)
278
+ array = XPValue.flatten(array)
279
+ opts = XPValue.flatten(opts)
280
+ dsl = ForAllDSL.new(@process, new_key, array, opts)
281
+ return parse_and_push(dsl, &block)
282
+ end
283
+
284
+ def times(loops, &block)
285
+ loops = XPValue.flatten(loops)
286
+ dsl = TimesDSL.new(@process, new_key, loops)
287
+ return parse_and_push(dsl, &block)
288
+ end
289
+
290
+ def forany(array, &block)
291
+ one = XPValue.flatten(-1)
292
+ array = XPValue.flatten(array)
293
+ dsl = ForManyDSL.new(@process, new_key, one, array)
294
+ return parse_and_push(dsl, &block)
295
+ end
296
+
297
+ def on(condition, &block)
298
+ condition = XPValue.flatten(condition)
299
+ dsl = IfDSL.new(@process, new_key, condition)
300
+ return parse_and_push(dsl, &block)
301
+ end
302
+
303
+ def switch(*args, &block)
304
+ if args.length == 0
305
+ s = SwitchDSL.new(@process, new_key)
306
+ parse_and_push(s, &block)
307
+ elsif args.length == 1
308
+ s = BoundSwitchDSL.new(@process, new_key, XPValue.flatten(args.first))
309
+ parse_and_push(s, &block)
310
+ else
311
+ raise
312
+ end
313
+ end
314
+
315
+ def multi(&block)
316
+ dsl = MultiDSL.new(@process, new_key)
317
+ return parse_and_push(dsl, &block)
318
+ end
319
+
320
+ def try(opts = {}, &block)
321
+ opts = XPValue.flatten(opts)
322
+ dsl = TryDSL.new(@process, new_key, opts)
323
+ return parse_and_push(dsl, &block)
324
+ end
325
+
326
+ def result(path, opts = {}, &block)
327
+ # TODO: reimplement with macros!
328
+ opts = XPValue.flatten(opts)
329
+ path = XPValue.flatten(path)
330
+ dsl = ResultDSL.new(@process, new_key, path, opts)
331
+ return parse_and_push(dsl, &block)
332
+ end
333
+
334
+ def loop(opts = {}, &block)
335
+ opts = XPValue.flatten(opts)
336
+ dsl = LoopDSL.new(@process, new_key, opts)
337
+ return parse_and_push(dsl, &block)
338
+ end
339
+
340
+ def cache(opts = {}, &block)
341
+ dsl = CacheDSL.new(@process, new_key, opts)
342
+ return parse_and_push(dsl, &block)
343
+ end
344
+
345
+
346
+ def info(opts = {}, &block)
347
+ opts = XPValue.flatten(opts)
348
+ dsl = InfoDSL.new(@process, opts)
349
+ return parse_and_push(dsl, &block)
350
+ end
351
+
352
+ def run(arg, *args, &block)
353
+ # Kernel.puts "run: #{args} #{args.inspect}"
354
+ opts = XPFlow::parse_comment_opts(__FILE__)
355
+ name = nil
356
+ if arg.is_a?(Hash)
357
+ opts = opts.merge(arg)
358
+ name, args = args.first, args.tail
359
+ else
360
+ name = arg
361
+ end
362
+ raise 'No name given' if name.nil?
363
+ args = XPValue.flatten(args)
364
+ name = XPValue.flatten(name)
365
+ return push(RunDSL.new(@process, new_key, name, args, opts, block))
366
+ end
367
+
368
+ def rerun(name, *args, &block)
369
+ # TODO
370
+ try :retry => 100000 do # as many times as needed
371
+ run(name, *args, &block)
372
+ end
373
+ end
374
+
375
+ def sleep(t)
376
+ # this has to be present in DSL for some rather obscure reasons :)
377
+ return method_missing(:sleep, t)
378
+ end
379
+
380
+ def puts(*args)
381
+ # overloads the standard 'puts'
382
+ return method_missing(:log, *args)
383
+ end
384
+
385
+ def fail(*args)
386
+ # same here
387
+ return method_missing(:fail, *args)
388
+ end
389
+
390
+ def system(cmd)
391
+ # same here
392
+ return method_missing(:system, cmd)
393
+ end
394
+
395
+ def send(o, method, *args)
396
+ # same reason as sleep
397
+ return method_missing(:send, o, method, *args)
398
+ end
399
+
400
+ def method_missing(method, *args, &block)
401
+ # this is rather tricky:
402
+ # 1. DSL has predefined commands.
403
+ # 2. When no command matches we try to find "injected" activity, or activity
404
+ # the was injected into the DSL. That way we can move many DSL commands to activities.
405
+ # 3. When injected activities do not match, we try to match with a namespace. If there
406
+ # is a library with such a name we return a special variable. The only use for that
407
+ # is to be able to run activities like that: run g5k.reserve_nodes
408
+ # 4. If nothing matches, we raise an error.
409
+
410
+ # pp @process.library.traversal_graph
411
+
412
+ name = method.to_s
413
+ activity = @process.library.get_activity_or_nil(name)
414
+
415
+ if activity.is_a?(MacroDSL)
416
+ m = activity
417
+ seq = nil
418
+ raise "Macro must be provided with a workflow" if block.nil?
419
+ @process.with_workflow(block, args) do
420
+ seq = SequenceDSL.new(@process, new_key)
421
+ seq.parse(*args, &m.block)
422
+ push(seq)
423
+ end
424
+ return seq
425
+ end
426
+
427
+ if activity.nil? == false
428
+ args = XPValue.flatten(args)
429
+ name = XPValue.flatten(name)
430
+ opts = XPFlow::parse_comment_opts(__FILE__)
431
+ run = RunDSL.new(@process, new_key, name, args, opts, block)
432
+ return push(run)
433
+ end
434
+
435
+ library = @process.library.get_library_or_nil(name)
436
+
437
+ if library.nil? == false
438
+ raise NoMethodError, "Library referencing requires no args" if args.length > 0
439
+ return LibraryLink.new(@process, new_key, [ method.to_s ])
440
+ end
441
+
442
+ if name.end_with?('_of') and [ 1, 2 ].include?(args.length)
443
+ name = name.chomp('_of')
444
+ return self.get_of(args.first, name.to_sym, args[1])
445
+ end
446
+
447
+ raise NoMethodError, "Unknown or malformed DSL command or no such activity (:#{method})"
448
+ end
449
+
450
+ def _visit(*args)
451
+ pp caller
452
+ raise "Somebody did something stupid (see #{self.class})."
453
+ end
454
+
455
+ def experiment_scope(name = nil, &block)
456
+ # creates a new experiment scope
457
+ dsl = ExperimentDSL.new(@process, name)
458
+ return parse_and_push(dsl, &block)
459
+ end
460
+
461
+ ### END OF DSL ###
462
+
463
+ end
464
+
465
+ class SequenceDSL < ListDSL
466
+
467
+ def initialize(process, key)
468
+ super(process, key, [])
469
+ end
470
+
471
+ def self.repr(o)
472
+ return {
473
+ :key => o.key,
474
+ :type => :seq,
475
+ :body => o.__list__.map(&:repr)
476
+ }
477
+ end
478
+
479
+ def repr
480
+ return SequenceDSL.repr(self)
481
+ end
482
+
483
+ end
484
+
485
+ class ProcessDSL < SequenceDSL
486
+
487
+ attr_reader :args
488
+ attr_reader :name
489
+ attr_reader :library
490
+
491
+ def initialize(name, library, &block)
492
+ super(self, [])
493
+ @name = name
494
+ @library = library
495
+ @workflows = [] # a stack of current workflows used in macros
496
+ if block.nil?
497
+ raise "Block is nil?"
498
+ end
499
+ count = block.arity
500
+ if count >= 0
501
+ @args = count.times.map { |i| DSLVariable.new(new_key()) }
502
+ else
503
+ @args = 10.times.map { |i| DSLVariable.new(new_key()) }
504
+ end
505
+ self.parse(*@args, &block)
506
+ end
507
+
508
+ def checkpoint(*args)
509
+ name = nil
510
+ opts = {}
511
+ opts = args.pop if args.last.is_a?(Hash)
512
+ raise 'Wrong arguments' if args.length > 1
513
+ name = args.first if args.length == 1
514
+ push(CheckpointDSL.new(@process, new_key, name, opts, self))
515
+ end
516
+
517
+ def get_injection(name)
518
+ return @library.get_injection(name)
519
+ end
520
+
521
+ def as_process
522
+ keys = @args.map(&:key)
523
+ seq = self.as_run
524
+ return ProcessActivity.new(@name, keys, seq)
525
+ end
526
+
527
+ def repr
528
+ return {
529
+ :type => :process,
530
+ :name => @name,
531
+ :body => SequenceDSL.repr(self)
532
+ }
533
+ end
534
+
535
+ def with_workflow(m, args)
536
+ begin
537
+ @workflows.push([ m, args ])
538
+ yield
539
+ ensure
540
+ @workflows.pop
541
+ end
542
+ end
543
+
544
+ def current_workflow
545
+ raise "No current workflow" if @workflows.length == 0
546
+ return @workflows.last
547
+ end
548
+
549
+ end
550
+
551
+
552
+ class InnerDSL < SequenceDSL
553
+
554
+ alias :sequence_run :as_run
555
+
556
+ end
557
+
558
+ class WithParamsDSL < InnerDSL
559
+
560
+ def parse(&block)
561
+ args = @args.map { |x| DSLVariable.new(x) }
562
+ return super(*args, &block)
563
+ end
564
+
565
+ def repr
566
+ super.merge({
567
+ :args => @args
568
+ })
569
+ end
570
+
571
+ end
572
+
573
+
574
+ class SeqtryDSL < InnerDSL
575
+
576
+ constructor [ :process, :key ]
577
+
578
+ def as_run
579
+ return SeqtryRun.new(key, sequence_run.body)
580
+ end
581
+
582
+ end
583
+
584
+ class ExperimentDSL < InnerDSL
585
+
586
+ constructor [ :process ], :name
587
+
588
+ def as_run
589
+ return ExperimentRun.new(@process.get_key, @name, sequence_run)
590
+ end
591
+
592
+ end
593
+
594
+ class ForEachDSL < WithParamsDSL
595
+
596
+ constructor [ :process, :key ], :array, :opts
597
+
598
+ def init
599
+ @args = [ new_key() ] # iterator
600
+ end
601
+
602
+ def as_run
603
+ return ForEachRun.new(key, @array, @args.first, @opts, sequence_run)
604
+ end
605
+
606
+ def repr
607
+ super.merge({
608
+ :type => :foreach,
609
+ :array => @array
610
+ })
611
+ end
612
+
613
+ end
614
+
615
+ class ParallelDSL < InnerDSL
616
+
617
+ def as_run
618
+ return ParallelRun.new(key, __as_run__)
619
+ end
620
+ end
621
+
622
+ class TimesDSL < WithParamsDSL
623
+
624
+ constructor [ :process, :key ], :loops
625
+
626
+ def init
627
+ @args = [ new_key() ] # iterator
628
+ end
629
+
630
+ def as_run
631
+ return TimesRun.new(key, @loops, @args.first, sequence_run)
632
+ end
633
+ end
634
+
635
+ class ForAllDSL < WithParamsDSL
636
+
637
+ constructor [ :process, :key ], :array, :opts
638
+
639
+ def init
640
+ @args = [ new_key() ] # iterator
641
+ end
642
+
643
+ def as_run
644
+ return ForAllRun.new(key, @array, @args.first, @opts, sequence_run)
645
+ end
646
+ end
647
+
648
+ class ForManyDSL < WithParamsDSL
649
+
650
+ constructor [ :process, :key ], :number, :array
651
+
652
+ def init
653
+ @args = [ new_key() ] # iterator
654
+ end
655
+
656
+ def as_run
657
+ return ForManyRun.new(key, @number, @array, @args.first, sequence_run)
658
+ end
659
+
660
+ end
661
+
662
+ class ManyDSL < InnerDSL
663
+
664
+ constructor [ :process, :key ], :number
665
+
666
+ def as_run
667
+ return ManyRun.new(key, @number, __as_run__)
668
+ end
669
+
670
+ end
671
+
672
+ class TryDSL < InnerDSL
673
+
674
+ constructor [ :process, :key ], :opts
675
+
676
+ def as_run
677
+ return TryRun.new(key, @opts, sequence_run)
678
+ end
679
+
680
+ end
681
+
682
+ class ResultDSL < InnerDSL
683
+
684
+ constructor [ :process, :key ], :path, :opts
685
+
686
+ def as_run
687
+ return ResultRun.new(key, @path, @opts, sequence_run)
688
+ end
689
+
690
+ end
691
+
692
+ class CacheDSL < InnerDSL
693
+
694
+ constructor [ :process, :key ], :opts
695
+
696
+ def as_run
697
+ return CacheRun.new(key, @opts, sequence_run)
698
+ end
699
+
700
+ end
701
+
702
+ class InfoDSL < InnerDSL
703
+
704
+ constructor [ :process, :key ], :opts
705
+
706
+ def as_run
707
+ return InfoRun.new(key, @opts, sequence_run)
708
+ end
709
+ end
710
+
711
+
712
+ class IfDSL < SequenceDSL
713
+
714
+ constructor [ :process, :key ], :cond
715
+
716
+ def otherwise
717
+ push(OtherwiseDSL.new(@process, new_key))
718
+ end
719
+
720
+ def as_run
721
+ i = nil
722
+ @list.length.times do |j|
723
+ i = j if (@list[j].is_a?(OtherwiseDSL))
724
+ end
725
+ on_true = []
726
+ on_false = []
727
+ if i.nil?
728
+ on_true = @list
729
+ else
730
+ on_true = @list[0..(i-1)]
731
+ on_false = @list[(i+1)..-1]
732
+ raise if (on_true.length + on_false.length + 1) != @list.length
733
+ end
734
+ on_true = ListDSL.new(@process, new_key, on_true).as_run
735
+ on_false = ListDSL.new(@process, new_key, on_false).as_run
736
+ return IfRun.new(key, @cond, on_true, on_false)
737
+ end
738
+
739
+ end
740
+
741
+ class LoopDSL < WithParamsDSL
742
+
743
+ constructor [ :process, :key ], :opts
744
+
745
+ def init
746
+ @flag = new_key()
747
+ @iter = new_key()
748
+ @array = new_key()
749
+ @args = [ @iter, @array ]
750
+ end
751
+
752
+ def return_on(cond, value = nil)
753
+ cond = XPValue.flatten(cond)
754
+ value = XPValue.flatten(value)
755
+ push(ReturnLoopDSL.new(@process, key, @flag, cond, value))
756
+ end
757
+
758
+ def as_run
759
+ return LoopRun.new(key, @flag, @iter, @array, __as_run__, @opts)
760
+ end
761
+ end
762
+
763
+ class SwitchDSL < DSL
764
+
765
+ constructor [ :process, :key ], :cases => [], :default => nil
766
+
767
+ def on(cond, &block)
768
+ body = SequenceDSL.new(@process, new_key).parse(&block)
769
+ @cases.push([ XPValue.flatten(cond), body ])
770
+ end
771
+
772
+ def default(&block)
773
+ @default = SequenceDSL.new(@process, new_key).parse(&block)
774
+ end
775
+
776
+ def _cases_as_runs
777
+ return @cases.map { |c, b| [ c, b.as_run ] }
778
+ end
779
+
780
+ def _default_as_run
781
+ return nil if @default.nil?
782
+ return @default.as_run
783
+ end
784
+
785
+ def as_run
786
+ return SwitchRun.new(key, _cases_as_runs, _default_as_run)
787
+ end
788
+ end
789
+
790
+ class MultiDSL < SwitchDSL
791
+
792
+ def as_run
793
+ return MultiRun.new(key, _cases_as_runs, _default_as_run)
794
+ end
795
+ end
796
+
797
+ class BoundSwitchDSL < SwitchDSL
798
+
799
+ constructor [ :process, :key ], :cond
800
+
801
+ def as_run
802
+ return BoundSwitchRun.new(key, _cases_as_runs, _default_as_run, @cond)
803
+ end
804
+ end
805
+
806
+ class MacroDSL
807
+
808
+ # stores a block for workflow construction later
809
+
810
+ attr_reader :block
811
+
812
+ constructor :name, :engine, :block
813
+
814
+ end
815
+
816
+ end