bowler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Bowler
2
+
3
+ Bowler is a gem to manage process dependencies in Foreman.
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rdoc/task"
5
+ require 'rspec/core/rake_task'
6
+
7
+ RDoc::Task.new do |rd|
8
+ rd.rdoc_files.include("lib/**/*.rb")
9
+ rd.rdoc_dir = "rdoc"
10
+ end
11
+
12
+ desc "Run specs"
13
+ RSpec::Core::RakeTask.new do |t|
14
+ t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
15
+ # Put spec opts in a file named .rspec in root
16
+ end
17
+
18
+ task :default => :spec
data/bin/bowl ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bowler'
3
+ require 'bowler/cli'
4
+
5
+ Bowler::CLI.start(ARGV)
data/lib/bowler/cli.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'logger'
2
+
3
+ module Bowler
4
+ class CLI
5
+
6
+ def self.start(processes)
7
+ tree = Bowler::DependencyTree.load
8
+ process_list = processes.map(&:to_sym)
9
+
10
+ launch_string = tree.process_list_for(process_list)
11
+
12
+ logger.info "Starting #{tree.dependencies_for(process_list).join(', ')}.."
13
+
14
+ start_foreman_with launch_string
15
+ rescue PinfileNotFound
16
+ logger.error "Bowler could not find a Pinfile in the current directory."
17
+ rescue PinfileError => e
18
+ logger.error "Bowler could not load the Pinfile due to an error: #{e}"
19
+ end
20
+
21
+ def self.logger
22
+ @logger ||= Logger.new(STDOUT)
23
+ end
24
+
25
+ def self.build_command(launch_string)
26
+ "foreman start -c #{launch_string}"
27
+ end
28
+
29
+ private
30
+ def self.start_foreman_with(launch_string)
31
+ exec ( self.build_command launch_string )
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,30 @@
1
+ module Bowler
2
+
3
+ class DependencyTree
4
+
5
+ # Load the Pinfile
6
+ def self.load(absolute_path = nil)
7
+ absolute_path ||= File.join( Dir.pwd, 'Pinfile' )
8
+ definition = DSL.evaluate(absolute_path)
9
+ self.new(definition)
10
+ end
11
+
12
+ def initialize(definition)
13
+ @definition = definition
14
+ end
15
+
16
+ def dependencies_for(processes)
17
+ processes.inject([]) do |array, p|
18
+ array += [ (@definition.tree[p] || []), p ].flatten
19
+ end.uniq
20
+ end
21
+
22
+ def process_list_for(processes)
23
+ on = dependencies_for(processes)
24
+ off = @definition.processes.reject {|i| on.include? i }
25
+
26
+ [ on.map {|x| "#{x}=1" }, off.map {|x| "#{x}=0" } ].flatten.sort.join(',')
27
+ end
28
+
29
+ end
30
+ end
data/lib/bowler/dsl.rb ADDED
@@ -0,0 +1,52 @@
1
+ module Bowler
2
+ class DSL
3
+ attr_reader :processes, :global_dependencies
4
+
5
+ def self.evaluate(pinfile)
6
+ dsl = new
7
+ dsl.eval_pinfile(pinfile)
8
+ dsl.to_definition
9
+ end
10
+
11
+ def eval_pinfile(pinfile)
12
+ raise PinfileNotFound unless File.exists?(pinfile)
13
+ file = File.read(pinfile)
14
+ instance_eval( file )
15
+ rescue SyntaxError => e
16
+ raise PinfileError, e
17
+ end
18
+
19
+ def initialize
20
+ @processes = []
21
+ @global_dependencies = []
22
+ @specified_dependencies = []
23
+ end
24
+
25
+ def dependency(*dependencies)
26
+ @global_dependencies += [dependencies].flatten
27
+ end
28
+
29
+ def process(params)
30
+ if params.is_a? Hash
31
+ parent = params.keys.first
32
+ dependencies = [params.values.first]
33
+
34
+ @processes << { :process => parent, :dependencies => [dependencies].flatten }
35
+ @specified_dependencies += dependencies.flatten
36
+ else
37
+ @processes << { :process => params, :dependencies => [ ] }
38
+ end
39
+ end
40
+
41
+ def to_definition
42
+ definition = {
43
+ :tree => @processes.each_with_object({}) {|p, hash|
44
+ hash[p[:process]] = (p[:dependencies] + @global_dependencies).uniq
45
+ },
46
+ :processes => (@processes.map {|x| x[:process]} + @global_dependencies + @specified_dependencies).uniq
47
+ }
48
+ OpenStruct.new(definition)
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,3 @@
1
+ module Bowler
2
+ VERSION = '0.0.1'
3
+ end
data/lib/bowler.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'ostruct'
2
+
3
+ module Bowler
4
+
5
+ autoload :DependencyTree, 'bowler/dependency_tree'
6
+ autoload :DSL, 'bowler/dsl'
7
+
8
+ class PinfileNotFound < Exception; end
9
+ class PinfileError < Exception; end
10
+
11
+ end
@@ -0,0 +1,50 @@
1
+ require 'bowler'
2
+ require_relative 'helpers/definition_helper'
3
+
4
+ module Bowler
5
+
6
+ describe DependencyTree do
7
+
8
+ include DefinitionHelper
9
+
10
+ context "given a Pinfile" do
11
+ it "should load a dependency tree" do
12
+ tree = DependencyTree.load File.join( File.dirname(__FILE__), 'fixtures', 'dependency_tree_pinfile' )
13
+
14
+ tree.should be_instance_of DependencyTree
15
+ tree.dependencies_for([:foo]).should =~ [:bar, :foo, :required]
16
+ tree.dependencies_for([:nyan]).should =~ [:bar, :foo, :nyan, :required]
17
+ end
18
+ end
19
+
20
+ context "given an array of one process" do
21
+ before do
22
+ @tree = DependencyTree.new stub_definition
23
+ end
24
+
25
+ it "should find the correct dependencies" do
26
+ @tree.dependencies_for([:app1]).should =~ [:app2, :app3, :app1]
27
+ end
28
+
29
+ it "should give a correct process list" do
30
+ @tree.process_list_for([:app2]).should == "a=0,app1=0,app2=1,app3=1,b=0,c=0,other=0"
31
+ end
32
+ end
33
+
34
+ context "given an array of multiple processes" do
35
+ before do
36
+ @tree = DependencyTree.new stub_definition
37
+ end
38
+
39
+ it "should find the correct dependencies" do
40
+ @tree.dependencies_for([:app1, :other]).should =~ [:app2, :app3, :app1, :a, :b, :c, :other]
41
+ end
42
+
43
+ it "should give a correct process list" do
44
+ @tree.process_list_for([:app2, :other]).should == "a=1,app1=0,app2=1,app3=1,b=1,c=1,other=1"
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ end
data/spec/dsl_spec.rb ADDED
@@ -0,0 +1,71 @@
1
+ require 'bowler'
2
+
3
+ module Bowler
4
+
5
+ describe DSL do
6
+
7
+ include DefinitionHelper
8
+
9
+ context "given a valid pinfile" do
10
+ it "should return a valid definition" do
11
+ path_to_pinfile = File.join( File.dirname(__FILE__), 'fixtures', 'dsl_valid_pinfile' )
12
+ definition = DSL.evaluate path_to_pinfile
13
+
14
+ definition.should be_instance_of OpenStruct
15
+ definition.tree.should == {
16
+ :app => [ :database, :tiles, :templates ],
17
+ :tiles => [ :database, :templates ]
18
+ }
19
+ definition.processes.should =~ [ :app, :database, :templates, :tiles ]
20
+ end
21
+ end
22
+
23
+ context "given an invalid pinfile" do
24
+ it "should raise a gem-defined exception" do
25
+ path_to_pinfile = File.join( File.dirname(__FILE__), 'fixtures', 'dsl_invalid_pinfile' )
26
+ expect do
27
+ DSL.evaluate path_to_pinfile
28
+ end.to raise_error(PinfileError)
29
+ end
30
+ end
31
+
32
+ context "given a process" do
33
+ before do
34
+ @dsl = DSL.new
35
+ @dsl.process :test
36
+ end
37
+
38
+ it "should update the processes list with the specified process" do
39
+ @dsl.processes.should == [{ :process => :test, :dependencies => [] }]
40
+ @dsl.to_definition.processes.should == [ :test ]
41
+ end
42
+ end
43
+
44
+ context "given a process with dependencies" do
45
+ before do
46
+ @dsl = DSL.new
47
+ @dsl.process :test => [ :dependency1, :dependency2 ]
48
+ end
49
+
50
+ it "should update the processes list with all specified processes" do
51
+ @dsl.processes.should == [{ :process => :test, :dependencies => [:dependency1, :dependency2] }]
52
+ @dsl.to_definition.processes.should =~ [ :dependency1, :dependency2, :test ]
53
+ end
54
+ end
55
+
56
+ context "given global dependencies" do
57
+ before do
58
+ @dsl = DSL.new
59
+ @dsl.dependency :global1, :global2
60
+ @dsl.dependency :global3
61
+ end
62
+
63
+ it "should update the processes list with all specified processes" do
64
+ @dsl.global_dependencies.should =~ [:global1, :global2, :global3]
65
+ @dsl.to_definition.processes.should =~ [ :global1, :global2, :global3 ]
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,5 @@
1
+ dependency :required
2
+
3
+ process :foo => :bar
4
+ process :nyan => [:foo, :bar]
5
+ process :rick
@@ -0,0 +1,3 @@
1
+ dependey :templates
2
+
3
+ process :app => [:database,,,]
@@ -0,0 +1,4 @@
1
+ dependency :templates
2
+
3
+ process :app => [:database, :tiles]
4
+ process :tiles => :database
@@ -0,0 +1,19 @@
1
+ module Bowler
2
+ module DefinitionHelper
3
+
4
+ require 'ostruct'
5
+
6
+ def stub_definition
7
+ OpenStruct.new ({
8
+ :processes => [ :app1, :app2, :app3, :other, :a, :b, :c ],
9
+ :tree => {
10
+ :app1 => [ :app2, :app3 ],
11
+ :app2 => [ :app3 ],
12
+ :app3 => [ ],
13
+ :other => [ :a, :b, :c ]
14
+ }
15
+ })
16
+ end
17
+
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bowler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jordan Hatch
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-16 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: foreman
16
+ requirement: &70276368515620 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70276368515620
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70276368514980 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 0.9.2.2
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70276368514980
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ requirement: &70276368514300 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 2.8.0
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70276368514300
47
+ description:
48
+ email:
49
+ - jordan@jordanh.net
50
+ executables:
51
+ - bowl
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - lib/bowler/cli.rb
56
+ - lib/bowler/dependency_tree.rb
57
+ - lib/bowler/dsl.rb
58
+ - lib/bowler/version.rb
59
+ - lib/bowler.rb
60
+ - README.md
61
+ - Rakefile
62
+ - spec/dependency_tree_spec.rb
63
+ - spec/dsl_spec.rb
64
+ - spec/fixtures/dependency_tree_pinfile
65
+ - spec/fixtures/dsl_invalid_pinfile
66
+ - spec/fixtures/dsl_valid_pinfile
67
+ - spec/helpers/definition_helper.rb
68
+ - bin/bowl
69
+ homepage:
70
+ licenses: []
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ segments:
82
+ - 0
83
+ hash: 1393360155367898551
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ segments:
91
+ - 0
92
+ hash: 1393360155367898551
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 1.8.12
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: A wrapper for large Foreman-managed apps with dependent processes
99
+ test_files:
100
+ - spec/dependency_tree_spec.rb
101
+ - spec/dsl_spec.rb
102
+ - spec/fixtures/dependency_tree_pinfile
103
+ - spec/fixtures/dsl_invalid_pinfile
104
+ - spec/fixtures/dsl_valid_pinfile
105
+ - spec/helpers/definition_helper.rb