ripe 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -5
  3. data/Guardfile +2 -4
  4. data/README.md +1 -0
  5. data/bin/ripe +1 -59
  6. data/lib/ripe.rb +8 -1
  7. data/lib/ripe/blocks.rb +13 -0
  8. data/lib/ripe/blocks/block.rb +142 -0
  9. data/lib/ripe/blocks/liquid_block.rb +48 -0
  10. data/lib/ripe/blocks/multi_block.rb +71 -0
  11. data/lib/ripe/blocks/parallel_block.rb +29 -0
  12. data/lib/ripe/blocks/serial_block.rb +61 -0
  13. data/lib/ripe/blocks/working_block.rb +101 -0
  14. data/lib/ripe/cli.rb +121 -0
  15. data/lib/ripe/cli/helper.rb +31 -0
  16. data/lib/ripe/db.rb +7 -0
  17. data/lib/ripe/db/task.rb +42 -0
  18. data/lib/ripe/db/task_migration.rb +33 -0
  19. data/lib/ripe/db/worker.rb +64 -0
  20. data/lib/ripe/db/worker_migration.rb +41 -0
  21. data/lib/ripe/dsl.rb +2 -4
  22. data/lib/ripe/dsl/task_dsl.rb +4 -2
  23. data/lib/ripe/dsl/workflow_dsl.rb +5 -0
  24. data/lib/ripe/library.rb +34 -45
  25. data/lib/ripe/repo.rb +24 -23
  26. data/lib/ripe/version.rb +1 -1
  27. data/lib/ripe/worker_controller.rb +72 -144
  28. data/lib/ripe/worker_controller/preparer.rb +172 -0
  29. data/lib/ripe/worker_controller/syncer.rb +118 -0
  30. data/spec/cli_spec.rb +14 -0
  31. data/spec/library_spec.rb +18 -18
  32. data/spec/spec_helper.rb +2 -0
  33. data/spec/testpack.rb +16 -5
  34. data/spec/testpack/.ripe/meta.db +0 -0
  35. data/spec/testpack/.ripe/tasks/bar.sh +3 -0
  36. data/spec/testpack/{ripe → .ripe}/tasks/foo.sh +0 -0
  37. data/spec/testpack/.ripe/workers/1/1.sh +16 -0
  38. data/spec/testpack/.ripe/workers/1/2.sh +16 -0
  39. data/spec/testpack/.ripe/workers/1/job.sh +54 -0
  40. data/spec/testpack/.ripe/workers/2/3.sh +16 -0
  41. data/spec/testpack/.ripe/workers/2/4.sh +16 -0
  42. data/spec/testpack/.ripe/workers/2/job.sh +54 -0
  43. data/spec/testpack/.ripe/workers/3/5.sh +16 -0
  44. data/spec/testpack/.ripe/workers/3/6.sh +16 -0
  45. data/spec/testpack/.ripe/workers/3/job.sh +54 -0
  46. data/spec/testpack/.ripe/workflows/foobar.rb +23 -0
  47. data/spec/testpack/{case/Sample1 → Sample1}/bar_output.txt +0 -0
  48. data/spec/testpack/{case/Sample1 → Sample1}/foo_input.txt +0 -0
  49. data/spec/testpack/{case/Sample1 → Sample1}/foo_output.txt +0 -0
  50. data/spec/testpack/{case/Sample2 → Sample2}/bar_output.txt +0 -0
  51. data/spec/testpack/{case/Sample2 → Sample2}/foo_input.txt +0 -0
  52. data/spec/testpack/{case/Sample2 → Sample2}/foo_output.txt +0 -0
  53. data/spec/testpack/{case/Sample3 → Sample3}/bar_output.txt +0 -0
  54. data/spec/testpack/{case/Sample3 → Sample3}/foo_input.txt +0 -0
  55. data/spec/testpack/{case/Sample3 → Sample3}/foo_output.txt +0 -0
  56. data/spec/worker_controller_spec.rb +143 -0
  57. metadata +66 -40
  58. data/lib/ripe/block.rb +0 -41
  59. data/lib/ripe/liquid_block.rb +0 -17
  60. data/lib/ripe/multi_block.rb +0 -35
  61. data/lib/ripe/parallel_block.rb +0 -13
  62. data/lib/ripe/serial_block.rb +0 -37
  63. data/lib/ripe/task.rb +0 -21
  64. data/lib/ripe/task_migration.rb +0 -18
  65. data/lib/ripe/worker.rb +0 -44
  66. data/lib/ripe/worker_migration.rb +0 -26
  67. data/lib/ripe/working_block.rb +0 -41
  68. data/spec/block_spec.rb +0 -7
  69. data/spec/ripe_spec.rb +0 -7
  70. data/spec/testpack/ripe/tasks/bar.sh +0 -3
  71. data/spec/testpack/ripe/workflows/foobar.rb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2961c4cc93b7823c51c6ef1dc6d717b41de56d58
4
- data.tar.gz: 5f80f681106b6b747f88fd9a3797ae661db7557f
3
+ metadata.gz: 28ae834d0a84d2072400169910c39825c1c37aa3
4
+ data.tar.gz: 2b1be6510c88ad3679dc69e4b198eea81d050734
5
5
  SHA512:
6
- metadata.gz: 8b7edf637ca227eb6ac31ec0dd32bf7efbae0a54fda49e474f313850c554d45c55f03c767b315101f872cf11164c7a500f50b440fd9228f4afb2da42c34fa578
7
- data.tar.gz: d8829b666f606a54c56c29e5a21a68ca04a177ce4a859fc83a8c9a0758c9d0f86d42e0ba671b31b996ac8313671e8bd849d731f2b8c420693cf0cc9096830534
6
+ metadata.gz: cac0941044a07fe4b97a8fda9f68e52881bc6be0943efafb6d104e0fa6e0c45e4f219ad25431b6099aa30e6fac3847fa79cc28d472b13f3cce59f852fe52fb60
7
+ data.tar.gz: c43fcd8a697350737a8b02fef384d40bcc6666954f0ce2e8204efb1a88f9a4661099c4c2598cbe654d1ca86dcc9e89d8c28ab456b1ea34c4a4dd5b59e8780603
data/.travis.yml CHANGED
@@ -1,10 +1,5 @@
1
1
  language: ruby
2
2
  cache: bundler
3
- rvm:
4
- - 2.1.5
5
3
  script: bundle exec rake spec
6
- branches:
7
- only:
8
- - develop
9
4
  notifications:
10
5
  email: false
data/Guardfile CHANGED
@@ -1,6 +1,4 @@
1
1
  guard :rspec, cmd: 'rspec' do
2
- watch(%r{^spec/.+_spec\.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" }
2
+ watch(%r{^spec/.+\.rb$}) { 'spec' }
3
+ watch(%r{^lib/ripe/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
6
4
  end
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Ripe
2
+ [![Gem Version](https://badge.fury.io/rb/ripe.svg)](http://badge.fury.io/rb/ripe)
2
3
  [![Build Status](https://travis-ci.org/ndejay/ripe.svg)](https://travis-ci.org/ndejay/ripe)
3
4
  [![Code Climate](https://codeclimate.com/github/ndejay/ripe/badges/gpa.svg)](https://codeclimate.com/github/ndejay/ripe)
4
5
  [![Test Coverage](https://codeclimate.com/github/ndejay/ripe/badges/coverage.svg)](https://codeclimate.com/github/ndejay/ripe)
data/bin/ripe CHANGED
@@ -1,63 +1,5 @@
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
7
- require 'thor'
8
4
 
9
- include Ripe
10
- include Ripe::DSL
11
-
12
- class CLI < Thor
13
- desc 'console', 'Enter ripe console'
14
- def console
15
- repo = Repo.new
16
- repo.attach
17
-
18
- # Do not send arguments to the REPL
19
- ARGV.clear
20
-
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
26
-
27
- # Launch the REPL session in the context of +WorkerController+.
28
- Ripl.start :binding => repo.controller.instance_eval { binding }
29
- end
30
-
31
- desc 'prepare SAMPLES', 'Prepare jobs from template workflow'
32
- option :workflow, :aliases => '-w', :type => :string, :required => true,
33
- :desc => 'Workflow to be applied'
34
- option :options, :aliases => '-o', :type => :string, :required => false,
35
- :desc => 'Options', :default => ''
36
- def prepare(*samples)
37
- abort "No samples specified." if (samples.length == 0)
38
-
39
- additional_vars = options[:options].split(/,/).map do |pair|
40
- key, value = pair.split(/=/)
41
- { key.to_sym => value }
42
- end
43
- additional_vars = additional_vars.inject(&:merge) || {}
44
-
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
-
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))
55
- end
56
-
57
- desc 'version', 'Retrieve ripe version'
58
- def version
59
- puts "ripe version #{Ripe::VERSION}"
60
- end
61
- end
62
-
63
- CLI.start(ARGV)
5
+ Ripe::CLI.start(ARGV)
data/lib/ripe.rb CHANGED
@@ -1,5 +1,12 @@
1
- require_relative 'ripe/version'
1
+ require_relative 'ripe/blocks'
2
+ require_relative 'ripe/db'
3
+ require_relative 'ripe/dsl'
4
+ require_relative 'ripe/library'
2
5
  require_relative 'ripe/repo'
6
+ require_relative 'ripe/worker_controller'
7
+
8
+ require_relative 'ripe/cli'
9
+ require_relative 'ripe/version'
3
10
 
4
11
  module Ripe
5
12
  PATH = File.expand_path('..', File.dirname(__FILE__))
@@ -0,0 +1,13 @@
1
+ module Ripe
2
+ module Blocks
3
+ # Forward declaration to prevent cyclic dependencies
4
+ class Block; end
5
+ end
6
+ end
7
+
8
+ require_relative 'blocks/multi_block'
9
+ require_relative 'blocks/block'
10
+ require_relative 'blocks/parallel_block'
11
+ require_relative 'blocks/serial_block'
12
+ require_relative 'blocks/working_block'
13
+ require_relative 'blocks/liquid_block'
@@ -0,0 +1,142 @@
1
+ module Ripe
2
+
3
+ module Blocks
4
+
5
+ ##
6
+ # This class represents the fundamental building block of ripe.
7
+ #
8
+ # @abstract
9
+ #
10
+ # @attr_reader id [String] a mandatory, but optionally unique identifier
11
+ # for the block
12
+ # @attr_reader blocks [Array<Block>] list of children blocks
13
+ # @attr vars [Hash<Symbol, String>] key-value pairs
14
+ #
15
+ # @see Ripe::WorkerController::Preparer
16
+
17
+ class Block
18
+
19
+ attr_reader :id, :blocks
20
+
21
+ attr_accessor :vars
22
+
23
+ ##
24
+ # @param id [String] a mandatory, but optionally unique identifier
25
+ # for the block
26
+ # @param blocks [Array<Block>] list of children blocks
27
+ # @param vars [Hash<Symbol, String>] key-value pairs
28
+
29
+ def initialize(id, blocks = [], vars = {})
30
+ @id, @blocks, @vars = id, blocks, vars
31
+ end
32
+
33
+ ##
34
+ # Return the string command of the subtree starting at the current block.
35
+ #
36
+ # @return [String] subtree command
37
+
38
+ def command
39
+ ''
40
+ end
41
+
42
+ ##
43
+ # Prune the subtree starting at the current block.
44
+ #
45
+ # @param protect [Boolean] if the current block (and recursively, its
46
+ # children) should be protected from pruning -- setting this parameter
47
+ # to +true+ guarantees that the block will not be pruned
48
+ # @param depend [Boolean] if the current block is unprotected because
49
+ # its parent (serially) needs to be executed
50
+ # @return [Block, nil] a +Block+ representing the subtree that has not
51
+ # been pruned, and +nil+ otherwise
52
+
53
+ def prune(protect, depend)
54
+ self
55
+ end
56
+
57
+ ##
58
+ # Test whether all targets for the current block exist.
59
+ #
60
+ # @return [Boolean] whether all targets exist
61
+
62
+ def targets_exist?
63
+ # {Block} is an abstract class. By default, assume that no targets
64
+ # exist.
65
+ false
66
+ end
67
+
68
+ ##
69
+ # Return the topology of the subtree starting at the current block in a
70
+ # nested list format. The first element of any nested list is the
71
+ # identifier of the corresponding block in the subtree, and the
72
+ # subsequent elements are each a subtree corresponding to the children
73
+ # blocks of the current subtree.
74
+ #
75
+ # @return [Array<Symbol, Array>] topology nested list
76
+
77
+ def topology
78
+ []
79
+ end
80
+
81
+ ##
82
+ # Compose a new parallel block from two blocks. This method provides
83
+ # syntactic sugar in the form:
84
+ #
85
+ # Block1 | Block2 | Block3
86
+ #
87
+ # @param block [Block] a block
88
+ # @return [Block] parallel block composition of the current block with
89
+ # the block passed in the argument list
90
+
91
+ def |(block)
92
+ ParallelBlock.new(self, block)
93
+ end
94
+
95
+ ##
96
+ # Compose a new serial block from two blocks. This method provides
97
+ # syntactic sugar in the form:
98
+ #
99
+ # Block1 + Block2 + Block3
100
+ #
101
+ # @param (see #|)
102
+ # @return [Block] serial block composition of the current block with
103
+ # the block passed in the argument list
104
+
105
+ def +(block)
106
+ SerialBlock.new(self, block)
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+
113
+ end
114
+
115
+ ##
116
+ # +NilClass+ is monkey-patched+ to provide syntactic sugar for +Block#|+ and
117
+ # +Block#\++ by treating +nil+ like an empty block.
118
+ #
119
+ # @see Ripe::Blocks::Block
120
+
121
+ class NilClass
122
+
123
+ ##
124
+ # If attempting to compose a new block with a +nil+ element, ignore the +nil+
125
+ # element.
126
+ #
127
+ # @param (see Ripe::Blocks::Block#|)
128
+ # @return [Block] the +block+ parameter
129
+
130
+ def |(block)
131
+ raise NoMethodError unless Ripe::Blocks::Block > block.class
132
+ block
133
+ end
134
+
135
+ ##
136
+ # (see #|)
137
+
138
+ def +(block)
139
+ self.|(block)
140
+ end
141
+
142
+ end
@@ -0,0 +1,48 @@
1
+ require 'liquid'
2
+
3
+ module Ripe
4
+
5
+ module Blocks
6
+
7
+ ##
8
+ # This class represents a working block that should be processed using the
9
+ # Liquid templating engine, rather than the simple +bash+ engine defined in
10
+ # {WorkingBlock}.
11
+ #
12
+ # @see Ripe::Blocks::WorkingBlock
13
+
14
+ class LiquidBlock < WorkingBlock
15
+
16
+ ##
17
+ # @param filename [String] filename of the template file
18
+ # @param vars [Hash<Symbol, String>] key-value pairs
19
+
20
+ def initialize(filename, vars = {})
21
+ super(filename, vars)
22
+ end
23
+
24
+ ##
25
+ # Return liquid block +parameters+ as a +Hash<Symbol, Object>+.
26
+ #
27
+ # @return [Hash<Symbol, Object>] liquid block +parameters+
28
+
29
+ def declarations
30
+ @vars.inject({}) { |memo, (k, v)| memo[k.to_s] = v; memo }
31
+ end
32
+
33
+ ##
34
+ # (see Block#command)
35
+ #
36
+ # The resulting string contains the render result of the liquid template
37
+ # based on the parameters specified in +vars+.
38
+
39
+ def command
40
+ template = Liquid::Template.parse(File.new(@filename).read)
41
+ template.render(declarations)
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+
48
+ end
@@ -0,0 +1,71 @@
1
+ module Ripe
2
+
3
+ module Blocks
4
+
5
+ ##
6
+ # This class represents a block composition, that is, a placeholder block
7
+ # that joins multiple blocks together.
8
+ #
9
+ # This class only exists to provide a superclass for {ParallelBlock} and
10
+ # {SerialBlock}.
11
+ #
12
+ # @abstract
13
+ #
14
+ # @see Ripe::Blocks::ParallelBlock
15
+ # @see Ripe::Blocks::SerialBlock
16
+
17
+ class MultiBlock < Block
18
+
19
+ ##
20
+ # @param id [String] a mandatory, but optionally unique identifier
21
+ # for the block
22
+ # @param blocks [Array<Block>] list of children blocks
23
+
24
+ def initialize(id, *blocks)
25
+ # Ignore nil objects
26
+ super(id, blocks.compact, {})
27
+ end
28
+
29
+ ##
30
+ # (see Block#prune)
31
+ #
32
+ # Unless the block is protected, attempt to prune all children blocks.
33
+ # If all blocks are pruned, return nothing. If a single block remains,
34
+ # return that block. If more than one block remains, return the current
35
+ # {MultiBlock}.
36
+
37
+ def prune(protect, depend)
38
+ if !protect
39
+ @blocks = @blocks.map { |block| block.prune(protect, depend) }.compact
40
+ case @blocks.length
41
+ when 0; nil
42
+ when 1; @blocks.first
43
+ else; self
44
+ end
45
+ else
46
+ self
47
+ end
48
+ end
49
+
50
+ ##
51
+ # (see Block#targets_exist?)
52
+ #
53
+ # A {MultiBlock}'s targets exist if the targets of all its # children
54
+ # exist.
55
+
56
+ def targets_exist?
57
+ @blocks.map(&:targets_exist?).inject(:&)
58
+ end
59
+
60
+ ##
61
+ # (see Block#topology)
62
+
63
+ def topology
64
+ [@id] + @blocks.map(&:topology)
65
+ end
66
+
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,29 @@
1
+ module Ripe
2
+
3
+ module Blocks
4
+
5
+ ##
6
+ # This class represents a parallel composition of blocks, in that the
7
+ # children blocks of an instance of this class are to be run in parallel.
8
+
9
+ class ParallelBlock < MultiBlock
10
+
11
+ ##
12
+ # @param blocks [Array<Block>] list of children blocks
13
+
14
+ def initialize(*blocks)
15
+ super(:|, *blocks)
16
+ end
17
+
18
+ ##
19
+ # (see Block#command)
20
+
21
+ def command
22
+ @blocks.map { |block| "(\n%s\n) & " % block.command }.join('') + 'wait'
23
+ end
24
+
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,61 @@
1
+ module Ripe
2
+
3
+ module Blocks
4
+
5
+ ##
6
+ # This class represents a parallel composition of blocks, in that the
7
+ # children blocks of an instance of this class are to be run in serial.
8
+
9
+ class SerialBlock < MultiBlock
10
+
11
+ ##
12
+ # @param blocks [Array<Block>] list of children blocks
13
+
14
+ def initialize(*blocks)
15
+ super(:+, *blocks)
16
+ end
17
+
18
+ ##
19
+ # (see Block#command)
20
+
21
+ def command
22
+ @blocks.map { |block| "(\n%s\n)" % block.command }.join(' ; ')
23
+ end
24
+
25
+ alias :super_prune :prune
26
+
27
+ ##
28
+ # (see MultiBlock#prune)
29
+ #
30
+ # A {SerialBlock} differs from a {MultiBlock} or {ParallelBlock} in that
31
+ # there is a linear dependency for its children blocks as they are to be
32
+ # run in serial. If a given block must be run, then all subsequent
33
+ # blocks that depend on it must be run as well.
34
+
35
+ def prune(protect, depend)
36
+ return super_prune(protect, depend) if !depend
37
+ return self if protect
38
+
39
+ @blocks = @blocks.map do |block|
40
+ new_protect = !block.targets_exist?
41
+ new_block = block.prune(protect, depend)
42
+ protect = new_protect
43
+ new_block
44
+ end
45
+ @blocks = @blocks.compact
46
+
47
+ case @blocks.length
48
+ when 0
49
+ nil
50
+ when 1
51
+ @blocks.first
52
+ else
53
+ self
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ end
60
+
61
+ end