ripe 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -2
- data/Gemfile +0 -2
- data/Guardfile +3 -2
- data/Rakefile +0 -5
- data/bin/ripe +25 -24
- data/lib/ripe/dsl/task_dsl.rb +84 -0
- data/lib/ripe/dsl/workflow_dsl.rb +92 -0
- data/lib/ripe/dsl.rb +4 -0
- data/lib/ripe/library.rb +61 -0
- data/lib/ripe/repo.rb +92 -0
- data/lib/ripe/version.rb +1 -1
- data/lib/ripe/worker.rb +6 -18
- data/lib/ripe/worker_controller.rb +52 -0
- data/lib/ripe.rb +1 -1
- data/ripe.gemspec +5 -3
- data/spec/library_spec.rb +53 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/testpack/case/Sample1/bar_output.txt +1 -0
- data/spec/testpack/case/Sample1/foo_input.txt +1 -0
- data/spec/testpack/case/Sample1/foo_output.txt +1 -0
- data/spec/testpack/case/Sample2/bar_output.txt +1 -0
- data/spec/testpack/case/Sample2/foo_input.txt +1 -0
- data/spec/testpack/case/Sample2/foo_output.txt +1 -0
- data/spec/testpack/case/Sample3/bar_output.txt +1 -0
- data/spec/testpack/case/Sample3/foo_input.txt +1 -0
- data/spec/testpack/case/Sample3/foo_output.txt +1 -0
- data/spec/testpack/ripe/tasks/bar.sh +3 -0
- data/spec/testpack/ripe/tasks/foo.sh +3 -0
- data/spec/testpack/ripe/workflows/foobar.rb +23 -0
- data/spec/testpack.rb +16 -0
- metadata +57 -24
- data/lib/ripe/controller.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2961c4cc93b7823c51c6ef1dc6d717b41de56d58
|
4
|
+
data.tar.gz: 5f80f681106b6b747f88fd9a3797ae661db7557f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b7edf637ca227eb6ac31ec0dd32bf7efbae0a54fda49e474f313850c554d45c55f03c767b315101f872cf11164c7a500f50b440fd9228f4afb2da42c34fa578
|
7
|
+
data.tar.gz: d8829b666f606a54c56c29e5a21a68ca04a177ce4a859fc83a8c9a0758c9d0f86d42e0ba671b31b996ac8313671e8bd849d731f2b8c420693cf0cc9096830534
|
data/.travis.yml
CHANGED
@@ -3,7 +3,8 @@ cache: bundler
|
|
3
3
|
rvm:
|
4
4
|
- 2.1.5
|
5
5
|
script: bundle exec rake spec
|
6
|
+
branches:
|
7
|
+
only:
|
8
|
+
- develop
|
6
9
|
notifications:
|
7
10
|
email: false
|
8
|
-
slack:
|
9
|
-
secure: "RlmKttTKbJlU1xu6blqP3HWwzH4KpvvdatvxkFWB1t3mBE3vRWC8FgiNpxYFs/6+TdctGOWRGW/i6CUaXbPwn3nyrlN+yxHmqNrJFg8dS2jQoM1/xBUZXdDhABMvw8qWzG26RSfGlvvO0P78rILawil+5/2z9e1XcUVmf0RL+gc="
|
data/Gemfile
CHANGED
data/Guardfile
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
guard :rspec, cmd: 'rspec' do
|
2
2
|
watch(%r{^spec/.+_spec\.rb$})
|
3
|
-
watch(%r{^lib/ripe/(.+)\.rb$})
|
4
|
-
watch('spec/spec_helper.rb')
|
3
|
+
watch(%r{^lib/ripe/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
4
|
+
watch('spec/spec_helper.rb') { "spec" }
|
5
|
+
watch('spec/testpack.rb') { "spec" }
|
5
6
|
end
|
data/Rakefile
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'rspec/core/rake_task'
|
2
2
|
require 'bundler/gem_tasks'
|
3
|
-
require 'rdoc/task'
|
4
3
|
|
5
4
|
# Default directory to look in is `/specs`
|
6
5
|
# Run with `rake spec`
|
@@ -9,8 +8,4 @@ RSpec::Core::RakeTask.new(:spec) do |task|
|
|
9
8
|
# task.rspec_opts = ['--color', '--format', 'nested']
|
10
9
|
end
|
11
10
|
|
12
|
-
RDoc::Task.new(:rdoc => 'rdoc',
|
13
|
-
:clobber_rdoc => 'rdoc:clean',
|
14
|
-
:rerdoc => 'rdoc:force')
|
15
|
-
|
16
11
|
# task :default => :spec
|
data/bin/ripe
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require_relative '../lib/ripe'
|
4
|
+
require_relative '../lib/ripe/dsl'
|
5
|
+
require 'ripl' # REPL
|
6
|
+
require 'hirb' # Pretty output for +ActiveRecord+ objects
|
4
7
|
require 'thor'
|
5
8
|
|
6
9
|
include Ripe
|
7
|
-
|
8
|
-
# Look for workflows and blocks in ./.ripe wherever invoked, then in
|
9
|
-
# directories specified in the $RIPELIB environment variable.
|
10
|
-
$RIPELIBS = "#{ENV['PWD']}/.ripe:#{ENV['RIPELIB']}".split(/:/)
|
11
|
-
|
12
|
-
def Task(handle, vars = {})
|
13
|
-
WorkingBlock.new($RIPELIBS.map{ |path| "#{path}/tasks/#{handle}.sh" }.select{ |path| File.exists? path }.first, vars)
|
14
|
-
end
|
10
|
+
include Ripe::DSL
|
15
11
|
|
16
12
|
class CLI < Thor
|
17
13
|
desc 'console', 'Enter ripe console'
|
18
14
|
def console
|
19
|
-
|
20
|
-
|
15
|
+
repo = Repo.new
|
16
|
+
repo.attach
|
21
17
|
|
22
|
-
|
23
|
-
|
18
|
+
# Do not send arguments to the REPL
|
19
|
+
ARGV.clear
|
24
20
|
|
25
|
-
|
26
|
-
|
21
|
+
Ripl.config[:prompt] = proc do
|
22
|
+
# This is the only place I could think of placing +Hirb#enable+.
|
23
|
+
Hirb.enable unless Hirb::View.enabled?
|
24
|
+
'ripe> '
|
25
|
+
end
|
27
26
|
|
28
|
-
|
27
|
+
# Launch the REPL session in the context of +WorkerController+.
|
28
|
+
Ripl.start :binding => repo.controller.instance_eval { binding }
|
29
29
|
end
|
30
30
|
|
31
31
|
desc 'prepare SAMPLES', 'Prepare jobs from template workflow'
|
@@ -34,7 +34,7 @@ class CLI < Thor
|
|
34
34
|
option :options, :aliases => '-o', :type => :string, :required => false,
|
35
35
|
:desc => 'Options', :default => ''
|
36
36
|
def prepare(*samples)
|
37
|
-
|
37
|
+
abort "No samples specified." if (samples.length == 0)
|
38
38
|
|
39
39
|
additional_vars = options[:options].split(/,/).map do |pair|
|
40
40
|
key, value = pair.split(/=/)
|
@@ -42,15 +42,16 @@ class CLI < Thor
|
|
42
42
|
end
|
43
43
|
additional_vars = additional_vars.inject(&:merge) || {}
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
require_relative
|
45
|
+
repo = Repo.new
|
46
|
+
|
47
|
+
filename = repo.library.find_workflow(options[:workflow])
|
48
|
+
abort "Could not find workflow #{@handle}." if filename == nil
|
49
|
+
require_relative filename # Imports +$workflow+ from the workflow component
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
51
|
+
repo.attach_or_create # Create .ripe if it doesn't exist
|
52
|
+
repo.controller.prepare(samples,
|
53
|
+
$workflow.callback,
|
54
|
+
$workflow.params.merge(additional_vars))
|
54
55
|
end
|
55
56
|
|
56
57
|
desc 'version', 'Retrieve ripe version'
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Ripe
|
2
|
+
|
3
|
+
module DSL
|
4
|
+
|
5
|
+
##
|
6
|
+
# Create a +WorkingBlock+ using a DSL. It is syntactic sugar for
|
7
|
+
#
|
8
|
+
# foo = WorkingBlock.new('/path/to/foo', {
|
9
|
+
# param1: 'val1',
|
10
|
+
# param2: 'val2',
|
11
|
+
# })
|
12
|
+
#
|
13
|
+
# in the form of:
|
14
|
+
#
|
15
|
+
# foo = task 'foo' do
|
16
|
+
# param :param1, 'val1'
|
17
|
+
# param :param2, 'val2'
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# foo = task 'foo' do |t|
|
21
|
+
# t.param :param1, 'val1'
|
22
|
+
# t.param :param2, 'val2'
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# It internally uses +Ripe::DSL::TaskDSL+ to provide the DSL.
|
26
|
+
#
|
27
|
+
# @see Ripe::DSL::TaskDSL
|
28
|
+
# @see Ripe::DSL::WorkflowDSL
|
29
|
+
# @see Ripe::DSL::task
|
30
|
+
#
|
31
|
+
# @param handle [String] the name of the task
|
32
|
+
# @param block [Proc] executes block in the context of +TaskDSL+
|
33
|
+
# @return [WorkingBlock, nil]
|
34
|
+
|
35
|
+
def task(handle, &block)
|
36
|
+
filename = Repo.new.library.find_task(handle)
|
37
|
+
abort "Could not find task #{handle}." if filename == nil
|
38
|
+
|
39
|
+
params = TaskDSL.new(handle, &block).params
|
40
|
+
WorkingBlock.new(filename, params)
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# This class provides a DSL for defining a task. It should only be called
|
45
|
+
# by #task.
|
46
|
+
|
47
|
+
class TaskDSL
|
48
|
+
|
49
|
+
attr_reader :params
|
50
|
+
|
51
|
+
##
|
52
|
+
# Create a new +Task+ DSL
|
53
|
+
#
|
54
|
+
# @param handle [String] the name of the task
|
55
|
+
# @param block [Proc] executes block in the context of +TaskDSL+
|
56
|
+
|
57
|
+
def initialize(handle, &block)
|
58
|
+
@handle = handle
|
59
|
+
@params = {}
|
60
|
+
|
61
|
+
if block_given?
|
62
|
+
if block.arity == 1
|
63
|
+
yield self
|
64
|
+
else
|
65
|
+
instance_eval &block
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Register a parameter
|
72
|
+
#
|
73
|
+
# @param key [Symbol] the parameter name
|
74
|
+
# @param value [String] its value
|
75
|
+
|
76
|
+
def param(key, value)
|
77
|
+
@params.merge!({ key => value })
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Ripe
|
2
|
+
|
3
|
+
module DSL
|
4
|
+
|
5
|
+
##
|
6
|
+
# Create a +Workflow+ using a DSL. It is syntactic sugar for
|
7
|
+
#
|
8
|
+
# workflow 'foobar' do
|
9
|
+
# param :node_count, 1
|
10
|
+
# param :ppn, 8
|
11
|
+
# param :project_name, 'abc-012-ab'
|
12
|
+
# param :queue, 'queue'
|
13
|
+
# param :walltime, '12:00:00'
|
14
|
+
#
|
15
|
+
# describe do |sample, params|
|
16
|
+
# # task
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# The block given in +describe+ has two mandatory arguments:
|
21
|
+
# - sample: the name of the sample
|
22
|
+
# - params: the parameters defined at the workflow-level
|
23
|
+
#
|
24
|
+
# It internally uses +Ripe::DSL::WorkflowDSL+ to provide the DSL.
|
25
|
+
#
|
26
|
+
# @see Ripe::DSL::TaskDSL
|
27
|
+
# @see Ripe::DSL::WorkflowDSL
|
28
|
+
# @see Ripe::DSL::workflow
|
29
|
+
#
|
30
|
+
# @param handle [String] the name of the workflow
|
31
|
+
# @param block [Proc] executes block in the context of +WorkflowDSL+
|
32
|
+
|
33
|
+
def workflow(handle, &block)
|
34
|
+
$workflow = WorkflowDSL.new(handle, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# This class provides a DSL for defining a workflow. It should only be
|
39
|
+
# called by #workflow.
|
40
|
+
|
41
|
+
class WorkflowDSL
|
42
|
+
|
43
|
+
attr_reader :handle, :params, :callback
|
44
|
+
|
45
|
+
##
|
46
|
+
# Create a new +Workflow+ DSL
|
47
|
+
#
|
48
|
+
# @param handle [String] the name of the workflow
|
49
|
+
# @param block [Proc] executes block in the context of +WorkflowDSL+
|
50
|
+
|
51
|
+
def initialize(handle, &block)
|
52
|
+
@handle = handle
|
53
|
+
@params = { handle: handle }
|
54
|
+
@callback = nil
|
55
|
+
|
56
|
+
if block_given?
|
57
|
+
if block.arity == 1
|
58
|
+
yield self
|
59
|
+
else
|
60
|
+
instance_eval &block
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Register a parameter
|
67
|
+
#
|
68
|
+
# @param key [Symbol] the parameter name
|
69
|
+
# @param value [String] its value
|
70
|
+
|
71
|
+
def param(key, value)
|
72
|
+
@params.merge!({ key => value })
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Describe the workflow in terms of a task.
|
77
|
+
#
|
78
|
+
# @see Ripe::WorkerController#prepare
|
79
|
+
#
|
80
|
+
# @param block [Proc] a callback function that takes as arguments the name
|
81
|
+
# of sample and a hash of parameters provided by the workflow and by the
|
82
|
+
# command line.
|
83
|
+
|
84
|
+
def describe(&block)
|
85
|
+
@callback = block
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/lib/ripe/dsl.rb
ADDED
data/lib/ripe/library.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Ripe
|
2
|
+
|
3
|
+
##
|
4
|
+
# This class represents a library containing all the components accessible
|
5
|
+
# to ripe (tasks and workflows) based on what is contained in the +RIPELIB+
|
6
|
+
# environment variable.
|
7
|
+
|
8
|
+
class Library
|
9
|
+
|
10
|
+
attr_reader :paths
|
11
|
+
|
12
|
+
##
|
13
|
+
# Create a new library spanning all paths in the +RIPELIB+ environment
|
14
|
+
# variable.
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
# Prepends the working directory to the list of paths so that the
|
18
|
+
# working directory is always looked in first.
|
19
|
+
|
20
|
+
@paths = "#{Dir.pwd}/#{Repo::REPOSITORY_PATH}:#{ENV['RIPELIB']}".split(/:/)
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Search throughout the library for a task component by the name of
|
25
|
+
# +handle+. When there is more than one match, give precendence to the
|
26
|
+
# component whose path is declared first.
|
27
|
+
#
|
28
|
+
# @param handle [String] Task to search for
|
29
|
+
# @return [String, nil] Return the full path of the component if found,
|
30
|
+
# and +nil+ otherwise.
|
31
|
+
|
32
|
+
def find_task(handle)
|
33
|
+
search = @paths.map do |path|
|
34
|
+
filename = "#{path}/tasks/#{handle}.sh"
|
35
|
+
(File.exists? filename) ? filename : nil
|
36
|
+
end
|
37
|
+
|
38
|
+
search.compact.first
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Search throughout the library for a workflow component by the name of
|
43
|
+
# +handle+. When there is more than one match, give precendence to
|
44
|
+
# component whose path is declared first.
|
45
|
+
#
|
46
|
+
# @param handle [String] Workflow to search for
|
47
|
+
# @return [String, nil] Return the full path of the component if found,
|
48
|
+
# and +nil+ otherwise.
|
49
|
+
|
50
|
+
def find_workflow(handle)
|
51
|
+
search = @paths.map do |path|
|
52
|
+
filename = "#{path}/workflows/#{handle}.rb"
|
53
|
+
(File.exists? filename) ? filename : nil
|
54
|
+
end
|
55
|
+
|
56
|
+
search.compact.first
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/lib/ripe/repo.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'fileutils'
|
3
|
+
require_relative 'block'
|
4
|
+
require_relative 'worker'
|
5
|
+
require_relative 'worker_controller'
|
6
|
+
require_relative 'worker_migration'
|
7
|
+
require_relative 'working_block'
|
8
|
+
require_relative 'library'
|
9
|
+
require_relative 'liquid_block'
|
10
|
+
require_relative 'task'
|
11
|
+
require_relative 'task_migration'
|
12
|
+
|
13
|
+
module Ripe
|
14
|
+
|
15
|
+
##
|
16
|
+
# This class represents a ripe session. It is similar to the concept of a
|
17
|
+
# +git+ repository and is the starting point of the package. It
|
18
|
+
# instantiates:
|
19
|
+
#
|
20
|
+
# * a library containing information as to where to retrieve ripe
|
21
|
+
# components such as tasks and workflows;
|
22
|
+
# * a database that contains all worker metadata; and
|
23
|
+
# * a controller that communicates the database with the compute cluster
|
24
|
+
# interface.
|
25
|
+
#
|
26
|
+
# @see Ripe::WorkerController
|
27
|
+
# @see Ripe::Library
|
28
|
+
|
29
|
+
class Repo
|
30
|
+
|
31
|
+
REPOSITORY_PATH = '.ripe'
|
32
|
+
DATABASE_PATH = "#{REPOSITORY_PATH}/meta.db"
|
33
|
+
WORKERS_PATH = "#{REPOSITORY_PATH}/workers"
|
34
|
+
|
35
|
+
attr_reader :library, :controller
|
36
|
+
|
37
|
+
##
|
38
|
+
# Initialize a repository
|
39
|
+
|
40
|
+
def initialize
|
41
|
+
@has_repository = File.exists? REPOSITORY_PATH
|
42
|
+
@library = Library.new
|
43
|
+
@controller = WorkerController.instance
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Attach to an existing database
|
48
|
+
|
49
|
+
def attach
|
50
|
+
ActiveRecord::Base.establish_connection({
|
51
|
+
adapter: 'sqlite3',
|
52
|
+
database: DATABASE_PATH,
|
53
|
+
})
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Attach to an existing database, and creates one if none is found.
|
58
|
+
|
59
|
+
def attach_or_create
|
60
|
+
@has_repository ? attach : create
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Create a database
|
65
|
+
|
66
|
+
def create
|
67
|
+
FileUtils.mkdir_p(REPOSITORY_PATH)
|
68
|
+
@has_repository = true
|
69
|
+
|
70
|
+
begin
|
71
|
+
attach
|
72
|
+
|
73
|
+
# Create the tables
|
74
|
+
WorkerMigration.up
|
75
|
+
TaskMigration.up
|
76
|
+
rescue
|
77
|
+
destroy
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Destroy the ripe repository, including the database and the worker
|
83
|
+
# output.
|
84
|
+
|
85
|
+
def destroy
|
86
|
+
FileUtils.rm(DATABASE_PATH) if File.exists? DATABASE_PATH
|
87
|
+
FileUtils.rm(WORKERS_PATH) if Dir.exists? WORKERS_PATH
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/lib/ripe/version.rb
CHANGED
data/lib/ripe/worker.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
require 'active_record'
|
2
2
|
require 'fileutils'
|
3
3
|
require_relative 'task'
|
4
|
+
require_relative 'worker_controller'
|
4
5
|
|
5
6
|
module Ripe
|
6
7
|
class Worker < ActiveRecord::Base
|
7
8
|
has_many :tasks, dependent: :destroy
|
8
9
|
|
9
10
|
def dir
|
10
|
-
"
|
11
|
+
"#{Repo::REPOSITORY_PATH}/workers/#{self.id}"
|
11
12
|
end
|
12
13
|
|
13
14
|
def sh
|
@@ -30,27 +31,14 @@ module Ripe
|
|
30
31
|
FileUtils.rm_r dir if Dir.exists? dir
|
31
32
|
end
|
32
33
|
|
33
|
-
def self.sync
|
34
|
-
WorkerController.instance.sync
|
35
|
-
end
|
36
|
-
|
37
|
-
def start!
|
38
|
-
raise "Worker #{id} could not be started: not prepared" unless self.status == 'prepared'
|
39
|
-
start
|
40
|
-
end
|
41
|
-
|
42
34
|
def start
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
def cancel!
|
47
|
-
raise "Worker #{id} could not be cancelled: not started" unless ['queueing', 'idle', 'blocked', 'active'].include? self.status
|
48
|
-
cancel
|
35
|
+
raise "Worker #{id} could not be started: not prepared" unless self.status == 'prepared'
|
36
|
+
WorkerController.instance.start(self)
|
49
37
|
end
|
50
38
|
|
51
39
|
def cancel
|
52
|
-
|
53
|
-
|
40
|
+
raise "Worker #{id} could not be cancelled: not started" unless ['queueing', 'idle', 'blocked', 'active'].include? self.status
|
41
|
+
WorkerController.instance.cancel(self)
|
54
42
|
end
|
55
43
|
end
|
56
44
|
end
|
@@ -2,9 +2,28 @@ require 'singleton'
|
|
2
2
|
require_relative 'worker'
|
3
3
|
|
4
4
|
module Ripe
|
5
|
+
|
6
|
+
##
|
7
|
+
# This class controls workers as well as their relationship with regards to
|
8
|
+
# the compute cluster: worker preparation, submission, cancellation as well
|
9
|
+
# as sync.
|
10
|
+
|
5
11
|
class WorkerController
|
12
|
+
|
6
13
|
include Singleton
|
7
14
|
|
15
|
+
##
|
16
|
+
# Prepares workers by applying the workflow callback and its parameters to
|
17
|
+
# each sample.
|
18
|
+
#
|
19
|
+
# @see Ripe::DSL::WorkflowDSL#describe
|
20
|
+
#
|
21
|
+
# @param samples [List] list of samples to apply the callback to
|
22
|
+
# @param callback [Proc] a callback function that takes as arguments the name
|
23
|
+
# of sample and a hash of parameters provided by the workflow and by the
|
24
|
+
# command line.
|
25
|
+
# @param vars [Hash] a list of worker-wide parameters
|
26
|
+
|
8
27
|
def prepare(samples, callback, vars = {})
|
9
28
|
vars = {
|
10
29
|
wd: Dir.pwd,
|
@@ -78,6 +97,29 @@ module Ripe
|
|
78
97
|
end
|
79
98
|
end
|
80
99
|
|
100
|
+
##
|
101
|
+
# Submit a job to the compute cluster system
|
102
|
+
#
|
103
|
+
# @param worker [Worker] the worker to submit
|
104
|
+
|
105
|
+
def start(worker)
|
106
|
+
worker.update(status: :queueing,
|
107
|
+
moab_id: `qsub '#{worker.sh}'`.strip.split(/\./).first)
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Cancel a job in the compute cluster system
|
112
|
+
#
|
113
|
+
# @param worker [Worker] the worker to cancel
|
114
|
+
|
115
|
+
def cancel(worker)
|
116
|
+
`canceljob #{worker.moab_id}`
|
117
|
+
worker.update(status: :cancelled)
|
118
|
+
end
|
119
|
+
|
120
|
+
##
|
121
|
+
# Synchronize the status of jobs with the internal list of workers.
|
122
|
+
|
81
123
|
def sync
|
82
124
|
lists = {idle: '-i', blocked: '-b', active: '-r'}
|
83
125
|
lists = lists.map do |status, op|
|
@@ -134,5 +176,15 @@ module Ripe
|
|
134
176
|
end
|
135
177
|
end
|
136
178
|
end
|
179
|
+
|
180
|
+
def list(n = 20)
|
181
|
+
Worker.last(n)
|
182
|
+
end
|
183
|
+
|
184
|
+
def edit(*args)
|
185
|
+
system("$EDITOR #{args.join(' ')}")
|
186
|
+
end
|
187
|
+
|
137
188
|
end
|
189
|
+
|
138
190
|
end
|
data/lib/ripe.rb
CHANGED
data/ripe.gemspec
CHANGED
@@ -20,17 +20,19 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.7"
|
22
22
|
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "yard", "~> 0.8"
|
23
24
|
spec.add_development_dependency "rspec", "~> 3.2"
|
24
25
|
spec.add_development_dependency "rspec-nc", "~> 0.2"
|
25
26
|
spec.add_development_dependency "guard-rspec", "~> 4.5"
|
26
|
-
spec.add_development_dependency "
|
27
|
+
spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4"
|
27
28
|
|
28
29
|
spec.add_runtime_dependency "activerecord", "~> 4.2"
|
29
30
|
spec.add_runtime_dependency "fileutils", "~> 0.7"
|
30
31
|
spec.add_runtime_dependency "liquid", "~> 3.0"
|
31
32
|
spec.add_runtime_dependency "sqlite3", "~> 1.3"
|
33
|
+
|
34
|
+
spec.add_runtime_dependency "ripl", "~> 0.7"
|
32
35
|
spec.add_runtime_dependency "hirb", "~> 0.7"
|
33
|
-
|
36
|
+
|
34
37
|
spec.add_runtime_dependency "thor", "~> 0.19"
|
35
|
-
spec.add_runtime_dependency "wirb", "~> 1.0"
|
36
38
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Ripe::Library do
|
4
|
+
context 'when RIPELIB env is empty' do
|
5
|
+
before(:each) do
|
6
|
+
ENV['RIPELIB'] = ''
|
7
|
+
@library = Ripe::Library.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'looks in the working directory' do
|
11
|
+
expect(@library.paths).to eql ["#{Dir.pwd}/#{Ripe::Repo::REPOSITORY_PATH}"]
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'cannot resolve components of the test library' do
|
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
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when RIPELIB contains the test library' do
|
22
|
+
before(:each) do
|
23
|
+
@test = Ripe::TestPack.new
|
24
|
+
ENV['RIPELIB'] = @test.path
|
25
|
+
@library = Ripe::Library.new
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'looks in two directories' do
|
29
|
+
expect(@library.paths.length).to eql 2
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'looks in the working directory first' do
|
33
|
+
# It looks in the working directory, and then in the directory
|
34
|
+
# specified in RIPELIB.
|
35
|
+
expect(@library.paths[0]).to eql "#{Dir.pwd}/#{Ripe::Repo::REPOSITORY_PATH}"
|
36
|
+
expect(@library.paths[1]).to eql @test.path
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'resolves task components of the test library' do
|
40
|
+
expect(@library.find_task('foo')).to eql @test.tasks['foo']
|
41
|
+
expect(@library.find_task('bar')).to eql @test.tasks['bar']
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'resolves workflows components of the test library' do
|
45
|
+
expect(@library.find_workflow('foobar')).to eql @test.workflows['foobar']
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'cannot resolve non-existing componenets' do
|
49
|
+
expect(@library.find_task('other')).to eql nil
|
50
|
+
expect(@library.find_workflow('other')).to eql nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
One Bar
|
@@ -0,0 +1 @@
|
|
1
|
+
One Foo
|
@@ -0,0 +1 @@
|
|
1
|
+
One Foo For You
|
@@ -0,0 +1 @@
|
|
1
|
+
Two Bar
|
@@ -0,0 +1 @@
|
|
1
|
+
Two Foo
|
@@ -0,0 +1 @@
|
|
1
|
+
Two Foo For You
|
@@ -0,0 +1 @@
|
|
1
|
+
Three Bar
|
@@ -0,0 +1 @@
|
|
1
|
+
Three Foo
|
@@ -0,0 +1 @@
|
|
1
|
+
Three Foo For You
|
@@ -0,0 +1,23 @@
|
|
1
|
+
workflow 'foobar' do
|
2
|
+
param :node_count, 1
|
3
|
+
param :ppn, 8
|
4
|
+
param :project_name, 'abc-012-ab'
|
5
|
+
param :queue, 'queue'
|
6
|
+
param :walltime, '12:00:00'
|
7
|
+
|
8
|
+
describe do |sample, params|
|
9
|
+
foo = task 'foo' do
|
10
|
+
param :input_foo, "#{sample}/input_foo"
|
11
|
+
param :foo_message, 'FOO'
|
12
|
+
param :output_foo, "#{sample}/output_foo"
|
13
|
+
end
|
14
|
+
|
15
|
+
bar = task 'bar' do
|
16
|
+
param :input_bar, "#{sample}/input_bar"
|
17
|
+
param :bar_message, 'BAR'
|
18
|
+
param :output_bar, "#{sample}/output_bar"
|
19
|
+
end
|
20
|
+
|
21
|
+
foo + bar
|
22
|
+
end
|
23
|
+
end
|
data/spec/testpack.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Ripe
|
2
|
+
class TestPack
|
3
|
+
attr_reader :path, :tasks, :workflows
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@path = "#{Ripe::PATH}/spec/testpack/ripe"
|
7
|
+
@tasks = {
|
8
|
+
'foo' => "#{@path}/tasks/foo.sh",
|
9
|
+
'bar' => "#{@path}/tasks/bar.sh",
|
10
|
+
}
|
11
|
+
@workflows = {
|
12
|
+
'foobar' => "#{@path}/workflows/foobar.rb",
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ripe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicolas De Jay
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-05-
|
11
|
+
date: 2015-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: yard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.8'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.8'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rspec
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,19 +95,19 @@ dependencies:
|
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '4.5'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
98
|
+
name: codeclimate-test-reporter
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
101
|
- - "~>"
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: '4
|
103
|
+
version: '0.4'
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version: '4
|
110
|
+
version: '0.4'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: activerecord
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,7 +165,7 @@ dependencies:
|
|
151
165
|
- !ruby/object:Gem::Version
|
152
166
|
version: '1.3'
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
168
|
+
name: ripl
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
156
170
|
requirements:
|
157
171
|
- - "~>"
|
@@ -165,19 +179,19 @@ dependencies:
|
|
165
179
|
- !ruby/object:Gem::Version
|
166
180
|
version: '0.7'
|
167
181
|
- !ruby/object:Gem::Dependency
|
168
|
-
name:
|
182
|
+
name: hirb
|
169
183
|
requirement: !ruby/object:Gem::Requirement
|
170
184
|
requirements:
|
171
185
|
- - "~>"
|
172
186
|
- !ruby/object:Gem::Version
|
173
|
-
version: '
|
187
|
+
version: '0.7'
|
174
188
|
type: :runtime
|
175
189
|
prerelease: false
|
176
190
|
version_requirements: !ruby/object:Gem::Requirement
|
177
191
|
requirements:
|
178
192
|
- - "~>"
|
179
193
|
- !ruby/object:Gem::Version
|
180
|
-
version: '
|
194
|
+
version: '0.7'
|
181
195
|
- !ruby/object:Gem::Dependency
|
182
196
|
name: thor
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -192,20 +206,6 @@ dependencies:
|
|
192
206
|
- - "~>"
|
193
207
|
- !ruby/object:Gem::Version
|
194
208
|
version: '0.19'
|
195
|
-
- !ruby/object:Gem::Dependency
|
196
|
-
name: wirb
|
197
|
-
requirement: !ruby/object:Gem::Requirement
|
198
|
-
requirements:
|
199
|
-
- - "~>"
|
200
|
-
- !ruby/object:Gem::Version
|
201
|
-
version: '1.0'
|
202
|
-
type: :runtime
|
203
|
-
prerelease: false
|
204
|
-
version_requirements: !ruby/object:Gem::Requirement
|
205
|
-
requirements:
|
206
|
-
- - "~>"
|
207
|
-
- !ruby/object:Gem::Version
|
208
|
-
version: '1.0'
|
209
209
|
description:
|
210
210
|
email:
|
211
211
|
- ndj+rubygems@pinkfilter.org
|
@@ -225,10 +225,14 @@ files:
|
|
225
225
|
- bin/ripe
|
226
226
|
- lib/ripe.rb
|
227
227
|
- lib/ripe/block.rb
|
228
|
-
- lib/ripe/
|
228
|
+
- lib/ripe/dsl.rb
|
229
|
+
- lib/ripe/dsl/task_dsl.rb
|
230
|
+
- lib/ripe/dsl/workflow_dsl.rb
|
231
|
+
- lib/ripe/library.rb
|
229
232
|
- lib/ripe/liquid_block.rb
|
230
233
|
- lib/ripe/multi_block.rb
|
231
234
|
- lib/ripe/parallel_block.rb
|
235
|
+
- lib/ripe/repo.rb
|
232
236
|
- lib/ripe/serial_block.rb
|
233
237
|
- lib/ripe/task.rb
|
234
238
|
- lib/ripe/task_migration.rb
|
@@ -240,8 +244,22 @@ files:
|
|
240
244
|
- ripe.gemspec
|
241
245
|
- share/moab.sh
|
242
246
|
- spec/block_spec.rb
|
247
|
+
- spec/library_spec.rb
|
243
248
|
- spec/ripe_spec.rb
|
244
249
|
- spec/spec_helper.rb
|
250
|
+
- spec/testpack.rb
|
251
|
+
- spec/testpack/case/Sample1/bar_output.txt
|
252
|
+
- spec/testpack/case/Sample1/foo_input.txt
|
253
|
+
- spec/testpack/case/Sample1/foo_output.txt
|
254
|
+
- spec/testpack/case/Sample2/bar_output.txt
|
255
|
+
- spec/testpack/case/Sample2/foo_input.txt
|
256
|
+
- spec/testpack/case/Sample2/foo_output.txt
|
257
|
+
- spec/testpack/case/Sample3/bar_output.txt
|
258
|
+
- spec/testpack/case/Sample3/foo_input.txt
|
259
|
+
- spec/testpack/case/Sample3/foo_output.txt
|
260
|
+
- spec/testpack/ripe/tasks/bar.sh
|
261
|
+
- spec/testpack/ripe/tasks/foo.sh
|
262
|
+
- spec/testpack/ripe/workflows/foobar.rb
|
245
263
|
homepage: https://github.com/ndejay/ripe
|
246
264
|
licenses:
|
247
265
|
- MIT
|
@@ -268,5 +286,20 @@ specification_version: 4
|
|
268
286
|
summary: Abstraction layer between the MOAB/Torque stack and your pipeline.
|
269
287
|
test_files:
|
270
288
|
- spec/block_spec.rb
|
289
|
+
- spec/library_spec.rb
|
271
290
|
- spec/ripe_spec.rb
|
272
291
|
- spec/spec_helper.rb
|
292
|
+
- spec/testpack.rb
|
293
|
+
- spec/testpack/case/Sample1/bar_output.txt
|
294
|
+
- spec/testpack/case/Sample1/foo_input.txt
|
295
|
+
- spec/testpack/case/Sample1/foo_output.txt
|
296
|
+
- spec/testpack/case/Sample2/bar_output.txt
|
297
|
+
- spec/testpack/case/Sample2/foo_input.txt
|
298
|
+
- spec/testpack/case/Sample2/foo_output.txt
|
299
|
+
- spec/testpack/case/Sample3/bar_output.txt
|
300
|
+
- spec/testpack/case/Sample3/foo_input.txt
|
301
|
+
- spec/testpack/case/Sample3/foo_output.txt
|
302
|
+
- spec/testpack/ripe/tasks/bar.sh
|
303
|
+
- spec/testpack/ripe/tasks/foo.sh
|
304
|
+
- spec/testpack/ripe/workflows/foobar.rb
|
305
|
+
has_rdoc:
|
data/lib/ripe/controller.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
require 'active_record'
|
2
|
-
require 'fileutils'
|
3
|
-
require_relative 'block'
|
4
|
-
require_relative 'worker'
|
5
|
-
require_relative 'worker_controller'
|
6
|
-
require_relative 'worker_migration'
|
7
|
-
require_relative 'working_block'
|
8
|
-
require_relative 'liquid_block'
|
9
|
-
require_relative 'task'
|
10
|
-
require_relative 'task_migration'
|
11
|
-
|
12
|
-
module Ripe
|
13
|
-
class Controller
|
14
|
-
def initialize
|
15
|
-
@repository_path = '.ripe'
|
16
|
-
@has_repository = Dir.exists? @repository_path
|
17
|
-
end
|
18
|
-
|
19
|
-
def attach
|
20
|
-
ActiveRecord::Base.establish_connection({
|
21
|
-
adapter: 'sqlite3',
|
22
|
-
database: "#{@repository_path}/meta.db"
|
23
|
-
})
|
24
|
-
end
|
25
|
-
|
26
|
-
def attach_or_create
|
27
|
-
@has_repository ? attach : create
|
28
|
-
end
|
29
|
-
|
30
|
-
def create
|
31
|
-
FileUtils.mkdir_p(@repository_path)
|
32
|
-
@has_repository = true
|
33
|
-
|
34
|
-
begin
|
35
|
-
attach
|
36
|
-
WorkerMigration.up
|
37
|
-
TaskMigration.up
|
38
|
-
rescue
|
39
|
-
destroy
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def destroy
|
44
|
-
FileUtils.rm("#{@repository_path}/meta.db") if File.exists? "#{@repository_path}/meta.db"
|
45
|
-
FileUtils.rm("#{@repository_path}/workers") if Dir.exists? "#{@repository_path}/workers"
|
46
|
-
end
|
47
|
-
|
48
|
-
def prepare(samples, callback, vars = {})
|
49
|
-
WorkerController.instance.prepare(samples, callback, vars)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|