ripe 0.1.0 → 0.2.0
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 +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
|