ripe 0.2.0 → 0.2.1
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.
- checksums.yaml +4 -4
- data/.travis.yml +0 -5
- data/Guardfile +2 -4
- data/README.md +1 -0
- data/bin/ripe +1 -59
- data/lib/ripe.rb +8 -1
- data/lib/ripe/blocks.rb +13 -0
- data/lib/ripe/blocks/block.rb +142 -0
- data/lib/ripe/blocks/liquid_block.rb +48 -0
- data/lib/ripe/blocks/multi_block.rb +71 -0
- data/lib/ripe/blocks/parallel_block.rb +29 -0
- data/lib/ripe/blocks/serial_block.rb +61 -0
- data/lib/ripe/blocks/working_block.rb +101 -0
- data/lib/ripe/cli.rb +121 -0
- data/lib/ripe/cli/helper.rb +31 -0
- data/lib/ripe/db.rb +7 -0
- data/lib/ripe/db/task.rb +42 -0
- data/lib/ripe/db/task_migration.rb +33 -0
- data/lib/ripe/db/worker.rb +64 -0
- data/lib/ripe/db/worker_migration.rb +41 -0
- data/lib/ripe/dsl.rb +2 -4
- data/lib/ripe/dsl/task_dsl.rb +4 -2
- data/lib/ripe/dsl/workflow_dsl.rb +5 -0
- data/lib/ripe/library.rb +34 -45
- data/lib/ripe/repo.rb +24 -23
- data/lib/ripe/version.rb +1 -1
- data/lib/ripe/worker_controller.rb +72 -144
- data/lib/ripe/worker_controller/preparer.rb +172 -0
- data/lib/ripe/worker_controller/syncer.rb +118 -0
- data/spec/cli_spec.rb +14 -0
- data/spec/library_spec.rb +18 -18
- data/spec/spec_helper.rb +2 -0
- data/spec/testpack.rb +16 -5
- data/spec/testpack/.ripe/meta.db +0 -0
- data/spec/testpack/.ripe/tasks/bar.sh +3 -0
- data/spec/testpack/{ripe → .ripe}/tasks/foo.sh +0 -0
- data/spec/testpack/.ripe/workers/1/1.sh +16 -0
- data/spec/testpack/.ripe/workers/1/2.sh +16 -0
- data/spec/testpack/.ripe/workers/1/job.sh +54 -0
- data/spec/testpack/.ripe/workers/2/3.sh +16 -0
- data/spec/testpack/.ripe/workers/2/4.sh +16 -0
- data/spec/testpack/.ripe/workers/2/job.sh +54 -0
- data/spec/testpack/.ripe/workers/3/5.sh +16 -0
- data/spec/testpack/.ripe/workers/3/6.sh +16 -0
- data/spec/testpack/.ripe/workers/3/job.sh +54 -0
- data/spec/testpack/.ripe/workflows/foobar.rb +23 -0
- data/spec/testpack/{case/Sample1 → Sample1}/bar_output.txt +0 -0
- data/spec/testpack/{case/Sample1 → Sample1}/foo_input.txt +0 -0
- data/spec/testpack/{case/Sample1 → Sample1}/foo_output.txt +0 -0
- data/spec/testpack/{case/Sample2 → Sample2}/bar_output.txt +0 -0
- data/spec/testpack/{case/Sample2 → Sample2}/foo_input.txt +0 -0
- data/spec/testpack/{case/Sample2 → Sample2}/foo_output.txt +0 -0
- data/spec/testpack/{case/Sample3 → Sample3}/bar_output.txt +0 -0
- data/spec/testpack/{case/Sample3 → Sample3}/foo_input.txt +0 -0
- data/spec/testpack/{case/Sample3 → Sample3}/foo_output.txt +0 -0
- data/spec/worker_controller_spec.rb +143 -0
- metadata +66 -40
- data/lib/ripe/block.rb +0 -41
- data/lib/ripe/liquid_block.rb +0 -17
- data/lib/ripe/multi_block.rb +0 -35
- data/lib/ripe/parallel_block.rb +0 -13
- data/lib/ripe/serial_block.rb +0 -37
- data/lib/ripe/task.rb +0 -21
- data/lib/ripe/task_migration.rb +0 -18
- data/lib/ripe/worker.rb +0 -44
- data/lib/ripe/worker_migration.rb +0 -26
- data/lib/ripe/working_block.rb +0 -41
- data/spec/block_spec.rb +0 -7
- data/spec/ripe_spec.rb +0 -7
- data/spec/testpack/ripe/tasks/bar.sh +0 -3
- data/spec/testpack/ripe/workflows/foobar.rb +0 -23
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
class WorkerController
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class controls worker preparation from a given workflow, list of
|
|
7
|
+
# samples and parameters. It applies the workflow to each of the specified
|
|
8
|
+
# samples.
|
|
9
|
+
#
|
|
10
|
+
# @attr workers [Array<Worker>] workers prepared in current batch
|
|
11
|
+
#
|
|
12
|
+
# @see Ripe::DSL::WorkflowDSL#describe
|
|
13
|
+
# @see Ripe::WorkerController#prepare
|
|
14
|
+
|
|
15
|
+
class Preparer
|
|
16
|
+
|
|
17
|
+
attr_accessor :workers
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
# Prepare workers by applying the workflow callback and its parameters to
|
|
21
|
+
# each sample.
|
|
22
|
+
#
|
|
23
|
+
# @param workflow [String] the name of a workflow to apply on the sample
|
|
24
|
+
# list
|
|
25
|
+
# @param samples [Array<String>] list of samples to apply the callback to
|
|
26
|
+
# @param params [Hash<Symbol, String>] a list of worker-wide parameters
|
|
27
|
+
|
|
28
|
+
def initialize(workflow, samples, params = {})
|
|
29
|
+
# Extract callback and params from input
|
|
30
|
+
callback, params = load_workflow(workflow, params)
|
|
31
|
+
|
|
32
|
+
if ![:patch, :force, :depend].include?(params[:mode].to_sym)
|
|
33
|
+
abort "Invalid mode #{params[:mode]}."
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Apply the workflow to each sample
|
|
37
|
+
sample_blocks = prepare_sample_blocks(samples, callback, params)
|
|
38
|
+
|
|
39
|
+
# Split samples into groups of +:group_num+ samples and produce a
|
|
40
|
+
# worker from each of these groups.
|
|
41
|
+
@workers = sample_blocks.each_slice(params[:group_num].to_i).map do |worker_blocks|
|
|
42
|
+
prepare_worker(worker_blocks, params)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
##
|
|
47
|
+
# Load a workflow and return its +callback+ and +params+ components.
|
|
48
|
+
#
|
|
49
|
+
# @param workflow [String] the name of a workflow
|
|
50
|
+
# @param params [Hash<Symbol, String>] a list of worker-wide parameters
|
|
51
|
+
# @return [Proc, Hash<Symbol, String>] a list containing the workflow callback
|
|
52
|
+
# and default params
|
|
53
|
+
|
|
54
|
+
def load_workflow(workflow, params)
|
|
55
|
+
filename = Library.find(:workflow, workflow)
|
|
56
|
+
abort "Could not find workflow #{workflow}." if filename == nil
|
|
57
|
+
require_relative filename
|
|
58
|
+
|
|
59
|
+
# Imports +$workflow+ from the workflow component. This is a dirty
|
|
60
|
+
# hack to help make the +DSL::WorkflowDSL+ more convenient for the
|
|
61
|
+
# end user.
|
|
62
|
+
|
|
63
|
+
params = {
|
|
64
|
+
wd: Dir.pwd,
|
|
65
|
+
mode: :patch,
|
|
66
|
+
group_num: 1,
|
|
67
|
+
}.merge($workflow.params.merge(params))
|
|
68
|
+
|
|
69
|
+
[$workflow.callback, params]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Apply the workflow (callback) to each sample, producing a single root
|
|
74
|
+
# block per sample.
|
|
75
|
+
#
|
|
76
|
+
# @param samples [Array<String>] a list of samples
|
|
77
|
+
# @param callback [Proc] workflow callback to be applied to each sample
|
|
78
|
+
# @param params [Hash] a list of worker-wide parameters
|
|
79
|
+
# @return [Hash] a +{sample => block}+ hash
|
|
80
|
+
|
|
81
|
+
def prepare_sample_blocks(samples, callback, params)
|
|
82
|
+
sample_blocks = samples.map do |sample|
|
|
83
|
+
block = callback.call(sample, params).prune(params[:mode].to_sym == :force,
|
|
84
|
+
params[:mode].to_sym == :depend)
|
|
85
|
+
if block != nil
|
|
86
|
+
puts "Preparing sample #{sample}"
|
|
87
|
+
{sample => block}
|
|
88
|
+
else
|
|
89
|
+
puts "Nothing to do for sample #{sample}"
|
|
90
|
+
nil
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Produce a {sample => block} hash
|
|
95
|
+
sample_blocks.compact.inject(&:merge)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
##
|
|
99
|
+
# Prepare a worker from a group of sample blocks.
|
|
100
|
+
#
|
|
101
|
+
# @param worker_sample_blocks [Hash] a list containing as many elements
|
|
102
|
+
# as there are samples in the group, with each element containing
|
|
103
|
+
# +[String, Blocks::Block]+
|
|
104
|
+
# @param params [Hash] worker-level parameter list
|
|
105
|
+
# @return [DB::Worker] worker
|
|
106
|
+
|
|
107
|
+
def prepare_worker(worker_sample_blocks, params)
|
|
108
|
+
worker = DB::Worker.create(handle: params[:handle])
|
|
109
|
+
worker_blocks = prepare_worker_blocks(worker_sample_blocks, worker)
|
|
110
|
+
|
|
111
|
+
# Combine all grouped sample blocks into a single worker block
|
|
112
|
+
|
|
113
|
+
params = params.merge({
|
|
114
|
+
name: worker.id,
|
|
115
|
+
stdout: worker.stdout,
|
|
116
|
+
stderr: worker.stderr,
|
|
117
|
+
command: Blocks::SerialBlock.new(*worker_blocks).command,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
worker_block = Blocks::LiquidBlock.new("#{PATH}/share/moab.sh", params)
|
|
121
|
+
File.open(worker.sh, 'w') { |f| f.write(worker_block.command) }
|
|
122
|
+
|
|
123
|
+
worker.update({
|
|
124
|
+
status: :prepared,
|
|
125
|
+
ppn: params[:ppn],
|
|
126
|
+
queue: params[:queue],
|
|
127
|
+
walltime: params[:walltime],
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
worker
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
##
|
|
134
|
+
# Organize worker blocks into tasks and prepare them.
|
|
135
|
+
#
|
|
136
|
+
# @param worker_sample_blocks [Array<Hash<String, Blocks::Block>>] a list
|
|
137
|
+
# containing as many elements as there are samples in the group
|
|
138
|
+
# @param worker [DB::Worker] worker
|
|
139
|
+
# @return [Array<Blocks::Block>] a list of all the prepared blocks for a
|
|
140
|
+
# worker
|
|
141
|
+
|
|
142
|
+
def prepare_worker_blocks(worker_sample_blocks, worker)
|
|
143
|
+
worker_sample_blocks.map do |sample, block|
|
|
144
|
+
# Preorder traversal of blocks -- assign incremental numbers starting from
|
|
145
|
+
# 1 to each node as it is being traversed, as well as producing the job
|
|
146
|
+
# file for each task.
|
|
147
|
+
post_var_assign = lambda do |subblock|
|
|
148
|
+
if subblock.blocks.length == 0
|
|
149
|
+
# This section is only called when the subblock is actually a working
|
|
150
|
+
# block (a leaf in the block arborescence).
|
|
151
|
+
task = worker.tasks.create({
|
|
152
|
+
sample: sample,
|
|
153
|
+
block: subblock.id,
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
File.open(task.sh, 'w') { |f| f.write(subblock.command) }
|
|
157
|
+
subblock.vars.merge!(log: task.log)
|
|
158
|
+
else
|
|
159
|
+
subblock.blocks.each(&post_var_assign)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
post_var_assign.call(block)
|
|
164
|
+
block
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
class WorkerController
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class controls worker syncing with the compute cluster queue.
|
|
7
|
+
#
|
|
8
|
+
# @attr_reader running_jobs [Array<Hash<Symbol, String>>] a list of running
|
|
9
|
+
# jobs as well as certain parameters (+moab_id+, +time+ and +status).
|
|
10
|
+
# @attr_reader completed_jobs [Array<DB::Worker>] a list of completed
|
|
11
|
+
# workers
|
|
12
|
+
# @attr_reader workers [Array<DB::Worker>] list of workers that have been
|
|
13
|
+
# updated (or completed)
|
|
14
|
+
#
|
|
15
|
+
# @see Ripe::WorkerController#sync
|
|
16
|
+
|
|
17
|
+
class Syncer
|
|
18
|
+
|
|
19
|
+
attr_reader :running_jobs, :completed_jobs, :workers
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# Synchronize the status of jobs with the internal list of workers.
|
|
23
|
+
|
|
24
|
+
def initialize
|
|
25
|
+
@workers = []
|
|
26
|
+
|
|
27
|
+
fetch_running_jobs
|
|
28
|
+
update_running_workers
|
|
29
|
+
fetch_completed_jobs
|
|
30
|
+
update_completed_workers
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
# Fetch status for all running jobs.
|
|
35
|
+
#
|
|
36
|
+
# @return [void]
|
|
37
|
+
|
|
38
|
+
def fetch_running_jobs
|
|
39
|
+
lists = {idle: '-i', blocked: '-b', active: '-r'}
|
|
40
|
+
lists = lists.map do |status, op|
|
|
41
|
+
showq = `showq -u $(whoami) #{op} | grep $(whoami)`.split("\n")
|
|
42
|
+
showq.map do |job|
|
|
43
|
+
{
|
|
44
|
+
moab_id: job[/^([0-9]+) /, 1],
|
|
45
|
+
time: job[/ ([0-9]{1,2}(\:[0-9]{2})+) /, 1],
|
|
46
|
+
status: status,
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
@running_jobs = lists.inject(&:+)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
##
|
|
54
|
+
# Update the status of running workers from the running jobs.
|
|
55
|
+
#
|
|
56
|
+
# @return [void]
|
|
57
|
+
|
|
58
|
+
def update_running_workers
|
|
59
|
+
@workers += @running_jobs.map do |job|
|
|
60
|
+
worker = DB::Worker.find_by(moab_id: job[:moab_id])
|
|
61
|
+
if worker
|
|
62
|
+
worker.update(time: job[:time])
|
|
63
|
+
unless ['cancelled', job[:status]].include?(worker.status)
|
|
64
|
+
checkjob = `checkjob #{job[:moab_id]}`
|
|
65
|
+
worker.update({
|
|
66
|
+
host: checkjob[/Allocated Nodes:\n\[(.*):[0-9]+\]\n/, 1],
|
|
67
|
+
# Queued jobs that appear become either idle, blocked or active
|
|
68
|
+
status: job[:status],
|
|
69
|
+
})
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
worker
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
# Fetch a list of completed workers from the running jobs: these are jobs
|
|
78
|
+
# that were previously marked as active, blocked or idle that can no
|
|
79
|
+
# be found on the compute cluster queue.
|
|
80
|
+
#
|
|
81
|
+
# @return [void]
|
|
82
|
+
|
|
83
|
+
def fetch_completed_jobs
|
|
84
|
+
running_job_ids = @running_jobs.map { |job| job[:moab_id] }
|
|
85
|
+
|
|
86
|
+
running_workers = DB::Worker.where('status in (:statuses)',
|
|
87
|
+
:statuses => ['active', 'idle', 'blocked'])
|
|
88
|
+
|
|
89
|
+
@completed_workers = running_workers.select do |worker|
|
|
90
|
+
!running_job_ids.include?(worker.moab_id) &&
|
|
91
|
+
worker.status != 'cancelled'
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
##
|
|
96
|
+
# Update the status of completed workers from the running jobs.
|
|
97
|
+
#
|
|
98
|
+
# @return [void]
|
|
99
|
+
|
|
100
|
+
def update_completed_workers
|
|
101
|
+
@workers += @completed_workers.map do |worker|
|
|
102
|
+
stdout = (File.exists?(worker.stdout)) ? File.new(worker.stdout).readlines.join : ""
|
|
103
|
+
worker.update({
|
|
104
|
+
cpu_used: stdout[/Resources:[ \t]*cput=([0-9]{1,2}(\:[0-9]{2})+),/, 1],
|
|
105
|
+
exit_code: stdout[/Exit code:[ \t]*(.*)$/, 1],
|
|
106
|
+
host: stdout[/Nodes:[ \t]*(.*)$/, 1],
|
|
107
|
+
memory_used: stdout[/Resources:.*,mem=([0-9]*[a-zA-Z]*),/, 1],
|
|
108
|
+
time: stdout[/Resources:.*,walltime=([0-9]{1,2}(\:[0-9]{2})+)$/, 1],
|
|
109
|
+
status: :completed,
|
|
110
|
+
})
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
data/spec/cli_spec.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CLI do
|
|
4
|
+
describe '::Helper#parse_cli_opts' do
|
|
5
|
+
it 'parses string options into hash options' do
|
|
6
|
+
string_opts = 'a=1,b=2,c=3'
|
|
7
|
+
test_hash_opts = CLI::Helper.parse_cli_opts(string_opts)
|
|
8
|
+
|
|
9
|
+
ref_hash_opts = {a: '1', b: '2', c: '3'}
|
|
10
|
+
|
|
11
|
+
expect(test_hash_opts).to eql ref_hash_opts
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/spec/library_spec.rb
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
-
describe
|
|
3
|
+
describe Library do
|
|
4
4
|
context 'when RIPELIB env is empty' do
|
|
5
|
-
before
|
|
5
|
+
before :each do
|
|
6
6
|
ENV['RIPELIB'] = ''
|
|
7
|
-
@library =
|
|
7
|
+
@library = Library
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
it 'looks in the working directory' do
|
|
11
|
-
expect(@library.paths).to eql ["#{Dir.pwd}/#{
|
|
11
|
+
expect(@library.paths).to eql ["#{Dir.pwd}/#{Repo::REPOSITORY_PATH}"]
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
it 'cannot resolve components of the test library' do
|
|
15
|
-
expect(@library.
|
|
16
|
-
expect(@library.
|
|
17
|
-
expect(@library.
|
|
15
|
+
expect(@library.find(:task, 'foo')).to eql nil
|
|
16
|
+
expect(@library.find(:task, 'bar')).to eql nil
|
|
17
|
+
expect(@library.find(:workflow, 'foobar')).to eql nil
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
context 'when RIPELIB contains the test library' do
|
|
22
|
-
before
|
|
23
|
-
@test =
|
|
24
|
-
ENV['RIPELIB'] = @test.
|
|
25
|
-
@library =
|
|
22
|
+
before :each do
|
|
23
|
+
@test = TestPack.new
|
|
24
|
+
ENV['RIPELIB'] = @test.lib_path
|
|
25
|
+
@library = Library
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
it 'looks in two directories' do
|
|
@@ -32,22 +32,22 @@ describe Ripe::Library do
|
|
|
32
32
|
it 'looks in the working directory first' do
|
|
33
33
|
# It looks in the working directory, and then in the directory
|
|
34
34
|
# specified in RIPELIB.
|
|
35
|
-
expect(@library.paths[0]).to eql "#{Dir.pwd}/#{
|
|
36
|
-
expect(@library.paths[1]).to eql @test.
|
|
35
|
+
expect(@library.paths[0]).to eql "#{Dir.pwd}/#{Repo::REPOSITORY_PATH}"
|
|
36
|
+
expect(@library.paths[1]).to eql @test.lib_path
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
it 'resolves task components of the test library' do
|
|
40
|
-
expect(@library.
|
|
41
|
-
expect(@library.
|
|
40
|
+
expect(@library.find(:task, 'foo')).to eql @test.tasks['foo']
|
|
41
|
+
expect(@library.find(:task, 'bar')).to eql @test.tasks['bar']
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
it 'resolves workflows components of the test library' do
|
|
45
|
-
expect(@library.
|
|
45
|
+
expect(@library.find(:workflow, 'foobar')).to eql @test.workflows['foobar']
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
it 'cannot resolve non-existing componenets' do
|
|
49
|
-
expect(@library.
|
|
50
|
-
expect(@library.
|
|
49
|
+
expect(@library.find(:task, 'other')).to eql nil
|
|
50
|
+
expect(@library.find(:workflow, 'other')).to eql nil
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/testpack.rb
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
1
|
module Ripe
|
|
2
2
|
class TestPack
|
|
3
|
-
attr_reader :path, :tasks, :workflows
|
|
3
|
+
attr_reader :path, :lib_path, :tasks, :workflows, :samples, :steps
|
|
4
4
|
|
|
5
5
|
def initialize
|
|
6
|
-
@path = "#{
|
|
6
|
+
@path = "#{PATH}/spec/testpack"
|
|
7
|
+
@lib_path = "#{@path}/#{Repo::REPOSITORY_PATH}"
|
|
7
8
|
@tasks = {
|
|
8
|
-
'foo' => "#{@
|
|
9
|
-
'bar' => "#{@
|
|
9
|
+
'foo' => "#{@lib_path}/tasks/foo.sh",
|
|
10
|
+
'bar' => "#{@lib_path}/tasks/bar.sh",
|
|
10
11
|
}
|
|
11
12
|
@workflows = {
|
|
12
|
-
'foobar' => "#{@
|
|
13
|
+
'foobar' => "#{@lib_path}/workflows/foobar.rb",
|
|
13
14
|
}
|
|
15
|
+
@samples = [
|
|
16
|
+
'Sample1',
|
|
17
|
+
'Sample2',
|
|
18
|
+
'Sample3'
|
|
19
|
+
]
|
|
20
|
+
@steps = [
|
|
21
|
+
'foo_input.txt',
|
|
22
|
+
'foo_output.txt',
|
|
23
|
+
'bar_output.txt'
|
|
24
|
+
]
|
|
14
25
|
end
|
|
15
26
|
end
|
|
16
27
|
end
|
|
Binary file
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
# <foo.sh>
|
|
3
|
+
|
|
4
|
+
INPUT_FOO="Sample1/foo_input.txt"
|
|
5
|
+
FOO_MESSAGE="For You"
|
|
6
|
+
OUTPUT_FOO="Sample1/foo_output.txt"
|
|
7
|
+
|
|
8
|
+
exec 1>"$LOG" 2>&1
|
|
9
|
+
|
|
10
|
+
# Foo is certainly one of the most important prerequisites to Bar.
|
|
11
|
+
|
|
12
|
+
echo "$(cat "$INPUT_FOO") $FOO_MESSAGE" > "$OUTPUT_FOO"
|
|
13
|
+
|
|
14
|
+
echo "##.DONE.##"
|
|
15
|
+
|
|
16
|
+
# </foo.sh>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
# <bar.sh>
|
|
3
|
+
|
|
4
|
+
INPUT_BAR="Sample1/foo_input.txt"
|
|
5
|
+
BAR_MESSAGE="Bar"
|
|
6
|
+
OUTPUT_BAR="Sample1/bar_output.txt"
|
|
7
|
+
|
|
8
|
+
exec 1>"$LOG" 2>&1
|
|
9
|
+
|
|
10
|
+
# Bar is the most important consequence of Foo.
|
|
11
|
+
|
|
12
|
+
echo "$(cut -d' ' -f1 "$INPUT_BAR") $BAR_MESSAGE" > "$OUTPUT_BAR"
|
|
13
|
+
|
|
14
|
+
echo "##.DONE.##"
|
|
15
|
+
|
|
16
|
+
# </bar.sh>
|