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.
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