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,101 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
module Blocks
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class represents a {Ripe::CLI::TaskCLI} that has been parametrized.
|
|
7
|
+
# In the block arborescence, {WorkingBlock}s are always leaf nodes.
|
|
8
|
+
#
|
|
9
|
+
# @see Ripe::CLI::TaskCLI
|
|
10
|
+
# @see Ripe::WorkerController::Preparer#prepare
|
|
11
|
+
|
|
12
|
+
class WorkingBlock < Block
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# @param filename [String] filename of the template file
|
|
16
|
+
# @param vars [Hash<Symbol, String>] key-value pairs
|
|
17
|
+
|
|
18
|
+
def initialize(filename, vars = {})
|
|
19
|
+
@filename = filename
|
|
20
|
+
super(File.basename(@filename), [], vars)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
# Return working block +parameters+ as a sequence of bash variable
|
|
25
|
+
# assignments.
|
|
26
|
+
#
|
|
27
|
+
# @return [String] sequence of bash variable assignments
|
|
28
|
+
|
|
29
|
+
def declarations
|
|
30
|
+
vars.map do |key, value|
|
|
31
|
+
lh = key.upcase
|
|
32
|
+
rh = value.is_a?(Array) ? "(\"#{value.join("\" \"")}\")" : "\"#{value}\""
|
|
33
|
+
"#{lh}=#{rh}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
##
|
|
38
|
+
# (see Block#command)
|
|
39
|
+
#
|
|
40
|
+
# The resulting string contains the result of the application of
|
|
41
|
+
# parameters to the +task+ from which the {WorkingBlock} was defined.
|
|
42
|
+
#
|
|
43
|
+
# @see Ripe::DB::Task
|
|
44
|
+
# @see Ripe::DSL::TaskDSL
|
|
45
|
+
|
|
46
|
+
def command
|
|
47
|
+
<<-EOF.gsub(/^[ ]+/, '')
|
|
48
|
+
|
|
49
|
+
# <#{id}>
|
|
50
|
+
|
|
51
|
+
#{declarations.join("\n")}
|
|
52
|
+
|
|
53
|
+
exec 1>"$LOG" 2>&1
|
|
54
|
+
|
|
55
|
+
#{File.new(@filename).read}
|
|
56
|
+
echo "##.DONE.##"
|
|
57
|
+
|
|
58
|
+
# </#{id}>
|
|
59
|
+
EOF
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# (see Block#prune)
|
|
64
|
+
#
|
|
65
|
+
# A {WorkingBlock} will be pruned if its targets exists, unless the
|
|
66
|
+
# +protect+ parameter is set to +true+.
|
|
67
|
+
|
|
68
|
+
def prune(protect, depend)
|
|
69
|
+
targets_exist? && !protect ? nil : self
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# (see Block#targets_exist?)
|
|
74
|
+
#
|
|
75
|
+
# For {WorkingBlock}s, if there is so much as a single target -- a block
|
|
76
|
+
# variable starting with +output_+) that does not exist, return +false+.
|
|
77
|
+
# Otherwise, return +true+.
|
|
78
|
+
|
|
79
|
+
def targets_exist?
|
|
80
|
+
statuses = @vars.select { |key, _| !key[/^output_/].nil? }.values.flatten
|
|
81
|
+
targets_exist = statuses.map { |target| File.exists? target }.inject(:&)
|
|
82
|
+
|
|
83
|
+
# If there are no targets at all, then assume that all targets exist
|
|
84
|
+
targets_exist == nil ? true : targets_exist
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
##
|
|
88
|
+
# (see Block#topology)
|
|
89
|
+
#
|
|
90
|
+
# Since a {WorkingBlock} is always a leaf node in the tree, the subtree
|
|
91
|
+
# starting at the leaf node only contains the {WorkingBlock}.
|
|
92
|
+
|
|
93
|
+
def topology
|
|
94
|
+
[@id]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
data/lib/ripe/cli.rb
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
require 'ripl' # REPL
|
|
2
|
+
require 'hirb' # Pretty output for +ActiveRecord+ objects
|
|
3
|
+
require 'thor'
|
|
4
|
+
|
|
5
|
+
require_relative '../ripe'
|
|
6
|
+
|
|
7
|
+
include Ripe
|
|
8
|
+
include Ripe::DB
|
|
9
|
+
include Ripe::DSL
|
|
10
|
+
|
|
11
|
+
module Ripe
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# This class represents the CLI interface to ripe. The methods defined in
|
|
15
|
+
# this class are wrappers for the methods defined in +Ripe::Repo+ and
|
|
16
|
+
# +Ripe::WorkerController+.
|
|
17
|
+
#
|
|
18
|
+
# @see Ripe::Repo
|
|
19
|
+
# @see Ripe::WorkerController
|
|
20
|
+
|
|
21
|
+
class CLI < Thor
|
|
22
|
+
|
|
23
|
+
desc 'init', 'Initialize ripe repository'
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# Initialize ripe repository.
|
|
27
|
+
#
|
|
28
|
+
# @see Ripe::Repo#attach_or_create
|
|
29
|
+
|
|
30
|
+
def init
|
|
31
|
+
puts "Initialized ripe repository in #{Dir.pwd}"
|
|
32
|
+
repo = Repo.new
|
|
33
|
+
repo.attach_or_create
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
desc 'console', 'Launch ripe console'
|
|
41
|
+
|
|
42
|
+
##
|
|
43
|
+
# Launch ripe console. It is a REPL bound to the context of a
|
|
44
|
+
# +Ripe::WorkerController+ initialized in the working directory.
|
|
45
|
+
|
|
46
|
+
def console
|
|
47
|
+
repo = Repo.new
|
|
48
|
+
repo.attach
|
|
49
|
+
|
|
50
|
+
unless repo.has_repository?
|
|
51
|
+
abort "Cannot launch console: ripe repo not initialized"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Do not send arguments to the REPL
|
|
55
|
+
ARGV.clear
|
|
56
|
+
|
|
57
|
+
Ripl.config[:prompt] = proc do
|
|
58
|
+
# This is the only place I could think of placing +Hirb#enable+.
|
|
59
|
+
Hirb.enable unless Hirb::View.enabled?
|
|
60
|
+
'ripe> '
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Launch the REPL session in the context of +WorkerController+.
|
|
64
|
+
Ripl.start :binding => repo.controller.instance_eval { binding }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
desc 'prepare SAMPLES', 'Prepare jobs from template workflow'
|
|
72
|
+
option :workflow, :aliases => '-w', :type => :string, :required => true,
|
|
73
|
+
:desc => 'Workflow to be applied'
|
|
74
|
+
option :options, :aliases => '-o', :type => :string, :required => false,
|
|
75
|
+
:desc => 'Options', :default => ''
|
|
76
|
+
option :start, :aliases => '-s', :type => :boolean, :required => false,
|
|
77
|
+
:desc => 'Automatically submit the prepared jobs onto the compute cluster', :default => false
|
|
78
|
+
|
|
79
|
+
##
|
|
80
|
+
# Prepare samples.
|
|
81
|
+
#
|
|
82
|
+
# @see Ripe::Repo#controller
|
|
83
|
+
# @see Ripe::WorkerController#prepare
|
|
84
|
+
|
|
85
|
+
def prepare(*samples)
|
|
86
|
+
repo = Repo.new
|
|
87
|
+
repo.attach
|
|
88
|
+
|
|
89
|
+
unless repo.has_repository?
|
|
90
|
+
abort 'Cannot launch console: ripe repo not initialized'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
abort 'No samples specified.' if samples.length == 0
|
|
94
|
+
|
|
95
|
+
workers = repo.controller.prepare(options[:workflow], samples,
|
|
96
|
+
Helper.parse_cli_opts(options[:options]))
|
|
97
|
+
|
|
98
|
+
repo.controller.start(workers) if options[:start]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
##
|
|
106
|
+
# Retrieve ripe version.
|
|
107
|
+
|
|
108
|
+
desc 'version', 'Retrieve ripe version'
|
|
109
|
+
def version
|
|
110
|
+
puts "ripe version #{Ripe::VERSION}"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
require_relative 'cli/helper.rb'
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
class CLI
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class defines helper methods for +Ripe::CLI+.
|
|
7
|
+
#
|
|
8
|
+
# @see Ripe::CLI
|
|
9
|
+
|
|
10
|
+
class Helper
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# Parses a string representing a hash in the format of +a=1,b=2,c=3+ into a
|
|
14
|
+
# hash in the format of +{a: 1, b: 2, c: 3}+.
|
|
15
|
+
#
|
|
16
|
+
# @param options [String] a hash in the format of +a=1,b=2,c=3+
|
|
17
|
+
# @return [Hash] a hash in the format of +{a: 1, b: 2, c: 3}+
|
|
18
|
+
|
|
19
|
+
def self.parse_cli_opts(options)
|
|
20
|
+
params = options.split(/,/).map do |pair|
|
|
21
|
+
key, value = pair.split(/=/)
|
|
22
|
+
{ key.to_sym => value }
|
|
23
|
+
end
|
|
24
|
+
params.inject(&:merge) || {}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
data/lib/ripe/db.rb
ADDED
data/lib/ripe/db/task.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
module DB
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class represents a +Task+ object in ripe's internal database. Its
|
|
7
|
+
# fields are defined by +Ripe::DB::TaskMigration+.
|
|
8
|
+
#
|
|
9
|
+
# @see Ripe::WorkerController
|
|
10
|
+
|
|
11
|
+
class Task < ActiveRecord::Base
|
|
12
|
+
belongs_to :worker
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# Return path to task directory, which is the same as worker directory.
|
|
16
|
+
|
|
17
|
+
def dir
|
|
18
|
+
"#{self.worker.dir}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# Return path to task-level combined +stdout+ and +stderr+ log.
|
|
23
|
+
|
|
24
|
+
def log
|
|
25
|
+
"#{self.dir}/#{self.id}.log"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
##
|
|
29
|
+
# Return path to task-level job script, which only includes the task at
|
|
30
|
+
# hand. This script is never actually executed by ripe.
|
|
31
|
+
#
|
|
32
|
+
# @see Ripe::DB::Worker#sh
|
|
33
|
+
|
|
34
|
+
def sh
|
|
35
|
+
"#{self.dir}/#{self.id}.sh"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
module DB
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class creates and destroys the +Task+ model in the internal
|
|
7
|
+
# database.
|
|
8
|
+
|
|
9
|
+
class TaskMigration < ActiveRecord::Migration
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Create model in database.
|
|
13
|
+
|
|
14
|
+
def self.up
|
|
15
|
+
create_table :tasks do |t|
|
|
16
|
+
t.belongs_to :worker
|
|
17
|
+
t.string :sample
|
|
18
|
+
t.string :block
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Destroy model in database.
|
|
24
|
+
|
|
25
|
+
def self.down
|
|
26
|
+
drop_table :tasks
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
module DB
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class represents a +Worker+ object in ripe's internal database. Its
|
|
7
|
+
# fields are defined by +Ripe::DB::WorkerMigration+.
|
|
8
|
+
#
|
|
9
|
+
# @see Ripe::WorkerController
|
|
10
|
+
|
|
11
|
+
class Worker < ActiveRecord::Base
|
|
12
|
+
has_many :tasks, dependent: :destroy
|
|
13
|
+
|
|
14
|
+
##
|
|
15
|
+
# Return path to worker directory
|
|
16
|
+
|
|
17
|
+
def dir
|
|
18
|
+
"#{Repo::REPOSITORY_PATH}/workers/#{self.id}"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# Return path to worker/job script, which includes all tasks defined in
|
|
23
|
+
# the worker. This is the script that is actually executed when the
|
|
24
|
+
# worker is run.
|
|
25
|
+
#
|
|
26
|
+
# @see Ripe::DB::Task#sh
|
|
27
|
+
|
|
28
|
+
def sh
|
|
29
|
+
"#{self.dir}/job.sh"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# Return path to the +stdout+ output of the job, which only exists after
|
|
34
|
+
# the job has been completed.
|
|
35
|
+
|
|
36
|
+
def stdout
|
|
37
|
+
"#{self.dir}/job.stdout"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# Return path to the +stderr+ output of the job, which only exists after
|
|
42
|
+
# the job has been completed.
|
|
43
|
+
|
|
44
|
+
def stderr
|
|
45
|
+
"#{self.dir}/job.stderr"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Automatically create worker directory upon object instantiation
|
|
49
|
+
|
|
50
|
+
after_create do
|
|
51
|
+
FileUtils.mkdir_p dir if !Dir.exists? dir
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Automatically remove worker directory upon object destruction
|
|
55
|
+
|
|
56
|
+
before_destroy do
|
|
57
|
+
FileUtils.rm_r dir if Dir.exists? dir
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Ripe
|
|
2
|
+
|
|
3
|
+
module DB
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# This class creates and destroys the +Worker+ model in the internal
|
|
7
|
+
# database.
|
|
8
|
+
|
|
9
|
+
class WorkerMigration < ActiveRecord::Migration
|
|
10
|
+
|
|
11
|
+
##
|
|
12
|
+
# Create model in database.
|
|
13
|
+
|
|
14
|
+
def self.up
|
|
15
|
+
create_table :workers do |t|
|
|
16
|
+
t.string :cpu_used
|
|
17
|
+
t.string :exit_code
|
|
18
|
+
t.string :handle
|
|
19
|
+
t.string :host
|
|
20
|
+
t.string :moab_id
|
|
21
|
+
t.string :memory_used
|
|
22
|
+
t.integer :ppn
|
|
23
|
+
t.string :queue
|
|
24
|
+
t.string :time
|
|
25
|
+
t.string :status, default: :unprepared
|
|
26
|
+
t.string :walltime
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# Destroy model in database.
|
|
32
|
+
|
|
33
|
+
def self.down
|
|
34
|
+
drop_table :workers
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|