foreman 0.37.0.pre5 → 0.37.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.
data/lib/foreman/cli.rb CHANGED
@@ -40,22 +40,11 @@ class Foreman::CLI < Thor
40
40
  method_option :port, :type => :numeric, :aliases => "-p"
41
41
  method_option :user, :type => :string, :aliases => "-u"
42
42
  method_option :template, :type => :string, :aliases => "-t"
43
- method_option :concurrency, :type => :string, :aliases => "-c",
44
- :banner => '"alpha=5,bar=3"'
43
+ method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"'
45
44
 
46
45
  def export(format, location=nil)
47
46
  check_procfile!
48
-
49
- begin
50
- require "foreman/export/#{ format.tr('-', '_') }"
51
- classy_format = classify(format)
52
- formatter = constantize("Foreman::Export::#{ classy_format }")
53
- rescue NameError => ex
54
- error "Unknown export format: #{format} (no class Foreman::Export::#{ classy_format })."
55
- rescue LoadError => ex
56
- error "Unknown export format: #{format} (unable to load file 'foreman/export/#{ format.tr('-', '_') }')."
57
- end
58
-
47
+ formatter = Foreman::Export.formatter(format)
59
48
  formatter.new(location, engine, options).export
60
49
  rescue Foreman::Export::Exception => ex
61
50
  error ex.message
@@ -65,7 +54,7 @@ class Foreman::CLI < Thor
65
54
 
66
55
  def check
67
56
  error "no processes defined" unless engine.procfile.entries.length > 0
68
- display "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
57
+ puts "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
69
58
  end
70
59
 
71
60
  desc "run COMMAND", "Run a command using your application's environment"
@@ -95,19 +84,11 @@ private ######################################################################
95
84
  options[:procfile] || "Procfile"
96
85
  end
97
86
 
98
- def display(message)
99
- puts message
100
- end
101
-
102
87
  def error(message)
103
88
  puts "ERROR: #{message}"
104
89
  exit 1
105
90
  end
106
91
 
107
- def procfile_exists?(procfile)
108
- File.exist?(procfile)
109
- end
110
-
111
92
  def options
112
93
  original_options = super
113
94
  return original_options unless File.exists?(".foreman")
@@ -78,9 +78,17 @@ private ######################################################################
78
78
  end
79
79
 
80
80
  def terminate_gracefully
81
+ return if @terminating
82
+ @terminating = true
81
83
  info "sending SIGTERM to all processes"
82
84
  kill_all "SIGTERM"
83
- Timeout.timeout(5) { Process.waitall }
85
+ Timeout.timeout(5) do
86
+ while running_processes.length > 0
87
+ pid, status = Process.wait2
88
+ process = running_processes.delete(pid)
89
+ info "process terminated", process.name
90
+ end
91
+ end
84
92
  rescue Timeout::Error
85
93
  info "sending SIGKILL to all processes"
86
94
  kill_all "SIGKILL"
@@ -112,16 +120,16 @@ private ######################################################################
112
120
  process = running_processes.delete(pid)
113
121
  info "process terminated", process.name
114
122
  terminate_gracefully
115
- kill_all
116
123
  rescue Errno::ECHILD
117
124
  end
118
125
 
119
126
  def info(message, name="system", color=Term::ANSIColor.white)
120
- print color
121
- print "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(name)} | "
122
- print Term::ANSIColor.reset
123
- print message.chomp
124
- puts ""
127
+ output = ""
128
+ output += color
129
+ output += "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(name)} | "
130
+ output += Term::ANSIColor.reset
131
+ output += message.chomp
132
+ puts output
125
133
  end
126
134
 
127
135
  def print(message=nil)
@@ -1,9 +1,30 @@
1
1
  require "foreman"
2
+ require "foreman/helpers"
2
3
 
3
4
  module Foreman::Export
5
+ extend Foreman::Helpers
6
+
4
7
  class Exception < ::Exception; end
8
+
9
+ def self.formatter(format)
10
+ begin
11
+ require "foreman/export/#{ format.tr('-', '_') }"
12
+ classy_format = classify(format)
13
+ formatter = constantize("Foreman::Export::#{ classy_format }")
14
+ rescue NameError => ex
15
+ error "Unknown export format: #{format} (no class Foreman::Export::#{ classy_format })."
16
+ rescue LoadError => ex
17
+ error "Unknown export format: #{format} (unable to load file 'foreman/export/#{ format.tr('-', '_') }')."
18
+ end
19
+ end
20
+
21
+ def self.error(message)
22
+ raise Foreman::Export::Exception.new(message)
23
+ end
24
+
5
25
  end
6
26
 
27
+
7
28
  require "foreman/export/base"
8
29
  require "foreman/export/inittab"
9
30
  require "foreman/export/upstart"
@@ -24,12 +24,12 @@ class Foreman::Export::Inittab < Foreman::Export::Base
24
24
 
25
25
  inittab = inittab.join("\n") + "\n"
26
26
 
27
- if fname
27
+ if location == "-"
28
+ puts inittab
29
+ else
28
30
  FileUtils.mkdir_p(log_root) rescue error "could not create #{log_root}"
29
31
  FileUtils.chown(user, nil, log_root) rescue error "could not chown #{log_root} to #{user}"
30
- write_file(fname, inittab)
31
- else
32
- puts inittab
32
+ write_file(location, inittab)
33
33
  end
34
34
  end
35
35
 
@@ -6,9 +6,8 @@ module Foreman::Helpers
6
6
  # classify('job-name') # => 'JobName'
7
7
  def classify(dashed_word)
8
8
  dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
9
- end
9
+ end # Tries to find a constant with the name specified in the argument string:
10
10
 
11
- # Tries to find a constant with the name specified in the argument string:
12
11
  #
13
12
  # constantize("Module") # => Module
14
13
  # constantize("Test::Unit") # => Test::Unit
@@ -28,10 +27,6 @@ module Foreman::Helpers
28
27
  def constantize(camel_cased_word)
29
28
  camel_cased_word = camel_cased_word.to_s
30
29
 
31
- if camel_cased_word.include?('-')
32
- camel_cased_word = classify(camel_cased_word)
33
- end
34
-
35
30
  names = camel_cased_word.split('::')
36
31
  names.shift if names.empty? || names.first.empty?
37
32
 
@@ -47,4 +42,4 @@ module Foreman::Helpers
47
42
  end
48
43
  constant
49
44
  end
50
- end
45
+ end
@@ -63,7 +63,7 @@ private
63
63
  $stderr.reopen writer
64
64
  reader.close
65
65
  exec Foreman.runner, "-d", basedir, command
66
- end
66
+ end
67
67
  end
68
68
  [ reader, pid ]
69
69
  end
@@ -1,5 +1,5 @@
1
1
  module Foreman
2
2
 
3
- VERSION = "0.37.0.pre5"
3
+ VERSION = "0.37.0"
4
4
 
5
5
  end
@@ -27,6 +27,15 @@ describe "Foreman::CLI", :fakefs do
27
27
 
28
28
  describe "export" do
29
29
  describe "options" do
30
+ it "uses .foreman" do
31
+ write_procfile
32
+ File.open(".foreman", "w") { |f| f.puts "concurrency: alpha=2" }
33
+ mock_export = mock(Foreman::Export::Upstart)
34
+ mock(Foreman::Export::Upstart).new("/upstart", is_a(Foreman::Engine), { "concurrency" => "alpha=2" }) { mock_export }
35
+ mock_export.export
36
+ foreman %{ export upstart /upstart }
37
+ end
38
+
30
39
  it "respects --env" do
31
40
  write_procfile
32
41
  write_env("envfile")
@@ -49,10 +58,18 @@ describe "Foreman::CLI", :fakefs do
49
58
  describe "with a Procfile" do
50
59
  before(:each) { write_procfile }
51
60
 
52
- describe "with an invalid formatter" do
61
+ describe "with a formatter with a generic error" do
62
+ before do
63
+ mock(Foreman::Export).formatter("errorful") { Class.new(Foreman::Export::Base) do
64
+ def export
65
+ raise Foreman::Export::Exception.new("foo")
66
+ end
67
+ end }
68
+ end
69
+
53
70
  it "prints an error" do
54
- mock_error(subject, "Unknown export format: invalidformatter (unable to load file 'foreman/export/invalidformatter').") do
55
- subject.export("invalidformatter")
71
+ mock_error(subject, "foo") do
72
+ subject.export("errorful")
56
73
  end
57
74
  end
58
75
  end
@@ -76,7 +93,7 @@ describe "Foreman::CLI", :fakefs do
76
93
  before { write_procfile }
77
94
 
78
95
  it "displays the jobs" do
79
- mock(subject).display("valid procfile detected (alpha, bravo)")
96
+ mock(subject).puts("valid procfile detected (alpha, bravo)")
80
97
  subject.check
81
98
  end
82
99
  end
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+ require "foreman/export/base"
3
+
4
+ describe "Foreman::Export::Base" do
5
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
6
+ let(:location) { "/tmp/init" }
7
+ let(:engine) { Foreman::Engine.new(procfile) }
8
+ let(:subject) { Foreman::Export::Base.new(location, engine) }
9
+
10
+ it "has a say method for displaying info" do
11
+ mock(subject).puts("[foreman export] foo")
12
+ subject.send(:say, "foo")
13
+ end
14
+
15
+ it "export needs to be overridden" do
16
+ lambda { subject.export }.should raise_error("export method must be overridden")
17
+ end
18
+
19
+ it "raises errors as a Foreman::Export::Exception" do
20
+ lambda { subject.send(:error, "foo") }.should raise_error(Foreman::Export::Exception, "foo")
21
+ end
22
+ end
@@ -17,7 +17,14 @@ describe Foreman::Export::Bluepill, :fakefs do
17
17
  normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app.pill"))
18
18
  end
19
19
 
20
- context "with concurrency" do
20
+ it "cleans up if exporting into an existing dir" do
21
+ mock(FileUtils).rm("/tmp/init/app.pill")
22
+
23
+ bluepill.export
24
+ bluepill.export
25
+ end
26
+
27
+ context "with concurrency" do
21
28
  let(:options) { Hash[:concurrency => "alpha=2"] }
22
29
 
23
30
  it "exports to the filesystem with concurrency" do
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+ require "foreman/engine"
3
+ require "foreman/export/inittab"
4
+ require "tmpdir"
5
+
6
+ describe Foreman::Export::Inittab, :fakefs do
7
+ let(:location) { "/tmp/inittab" }
8
+ let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
9
+ let(:location) { "/tmp/inittab" }
10
+ let(:engine) { Foreman::Engine.new(procfile) }
11
+ let(:options) { Hash.new }
12
+ let(:inittab) { Foreman::Export::Inittab.new(location, engine, options) }
13
+
14
+ before(:each) { load_export_templates_into_fakefs("inittab") }
15
+ before(:each) { stub(inittab).say }
16
+
17
+ it "exports to the filesystem" do
18
+ inittab.export
19
+ File.read("/tmp/inittab").should == example_export_file("inittab/inittab.default")
20
+ end
21
+
22
+ context "to stdout" do
23
+ let(:location) { "-" }
24
+
25
+ it "exports to stdout" do
26
+ mock(inittab).puts example_export_file("inittab/inittab.default")
27
+ inittab.export
28
+ end
29
+ end
30
+
31
+ context "with concurrency" do
32
+ let(:options) { Hash[:concurrency => "alpha=2"] }
33
+
34
+ it "exports to the filesystem with concurrency" do
35
+ inittab.export
36
+ File.read("/tmp/inittab").should == example_export_file("inittab/inittab.concurrency")
37
+ end
38
+ end
39
+
40
+ end
@@ -22,6 +22,17 @@ describe Foreman::Export::Upstart, :fakefs do
22
22
  File.read("/tmp/init/app-bravo-1.conf").should == example_export_file("upstart/app-bravo-1.conf")
23
23
  end
24
24
 
25
+ it "cleans up if exporting into an existing dir" do
26
+ mock(FileUtils).rm("/tmp/init/app.conf")
27
+ mock(FileUtils).rm("/tmp/init/app-alpha.conf")
28
+ mock(FileUtils).rm("/tmp/init/app-alpha-1.conf")
29
+ mock(FileUtils).rm("/tmp/init/app-bravo.conf")
30
+ mock(FileUtils).rm("/tmp/init/app-bravo-1.conf")
31
+
32
+ upstart.export
33
+ upstart.export
34
+ end
35
+
25
36
  context "with concurrency" do
26
37
  let(:options) { Hash[:concurrency => "alpha=2"] }
27
38
 
@@ -1,2 +1,24 @@
1
1
  require "spec_helper"
2
2
  require "foreman/export"
3
+
4
+ describe "Foreman::Export" do
5
+ subject { Foreman::Export }
6
+
7
+ describe "with a formatter that doesn't declare the appropriate class" do
8
+ it "prints an error" do
9
+ mock(subject).require("foreman/export/invalidformatter")
10
+ mock_export_error("Unknown export format: invalidformatter (no class Foreman::Export::Invalidformatter).") do
11
+ subject.formatter("invalidformatter")
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "with an invalid formatter" do
17
+
18
+ it "prints an error" do
19
+ mock_export_error("Unknown export format: invalidformatter (unable to load file 'foreman/export/invalidformatter').") do
20
+ subject.formatter("invalidformatter")
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+ require "foreman/helpers"
3
+
4
+ describe "Foreman::Helpers" do
5
+ before do
6
+ module Foo
7
+ class Bar; end
8
+ end
9
+ end
10
+
11
+ after do
12
+ Object.send(:remove_const, :Foo)
13
+ end
14
+
15
+ subject { o = Object.new; o.extend(Foreman::Helpers); o }
16
+
17
+ it "should classify words" do
18
+ subject.classify("foo").should == "Foo"
19
+ subject.classify("foo-bar").should == "FooBar"
20
+ end
21
+
22
+ it "should constantize words" do
23
+ subject.constantize("Object").should == Object
24
+ subject.constantize("Foo::Bar").should == Foo::Bar
25
+ end
26
+ end
data/spec/foreman_spec.rb CHANGED
@@ -25,4 +25,10 @@ describe Foreman do
25
25
  ENV['FOO'].should == 'bar'
26
26
  end
27
27
  end
28
+
29
+ describe "runner" do
30
+ it "should exist" do
31
+ File.exists?(Foreman.runner).should == true
32
+ end
33
+ end
28
34
  end
@@ -0,0 +1,4 @@
1
+ # ----- foreman app processes -----
2
+ AP01:4:respawn:/bin/su - app -c 'PORT=5000 ./alpha >> /var/log/app/alpha-1.log 2>&1'
3
+ AP02:4:respawn:/bin/su - app -c 'PORT=5001 ./alpha >> /var/log/app/alpha-2.log 2>&1'
4
+ # ----- end foreman app processes -----
@@ -0,0 +1,4 @@
1
+ # ----- foreman app processes -----
2
+ AP01:4:respawn:/bin/su - app -c 'PORT=5000 ./alpha >> /var/log/app/alpha-1.log 2>&1'
3
+ AP02:4:respawn:/bin/su - app -c 'PORT=5100 ./bravo >> /var/log/app/bravo-1.log 2>&1'
4
+ # ----- end foreman app processes -----
data/spec/spec_helper.rb CHANGED
@@ -1,10 +1,20 @@
1
1
  require "rubygems"
2
+
3
+ require "simplecov"
4
+ SimpleCov.start do
5
+ add_filter "/spec/"
6
+ end
7
+
2
8
  require "rspec"
3
9
  require "fakefs/safe"
4
10
  require "fakefs/spec_helpers"
5
11
 
6
12
  $:.unshift File.expand_path("../../lib", __FILE__)
7
13
 
14
+ def mock_export_error(message)
15
+ lambda { yield }.should raise_error(Foreman::Export::Exception, message)
16
+ end
17
+
8
18
  def mock_error(subject, message)
9
19
  mock_exit do
10
20
  mock(subject).puts("ERROR: #{message}")
@@ -37,9 +47,11 @@ def write_procfile(procfile="Procfile", alpha_env="")
37
47
  File.expand_path(procfile)
38
48
  end
39
49
 
40
- def write_env(env=".env")
50
+ def write_env(env=".env", options={"FOO"=>"bar"})
41
51
  File.open(env, "w") do |file|
42
- file.puts "FOO=bar"
52
+ options.each do |key, val|
53
+ file.puts "#{key}=#{val}"
54
+ end
43
55
  end
44
56
  end
45
57
 
metadata CHANGED
@@ -1,19 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.37.0.pre5
5
- prerelease: 7
4
+ version: 0.37.0
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - David Dollar
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-24 00:00:00.000000000 Z
12
+ date: 2012-01-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: term-ansicolor
16
- requirement: &70240847722740 !ruby/object:Gem::Requirement
16
+ requirement: &70149919501700 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.0.7
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70240847722740
24
+ version_requirements: *70149919501700
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: thor
27
- requirement: &70240847721920 !ruby/object:Gem::Requirement
27
+ requirement: &70149919500700 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: 0.13.6
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70240847721920
35
+ version_requirements: *70149919500700
36
36
  description: Process manager for applications with multiple components
37
37
  email: ddollar@gmail.com
38
38
  executables:
@@ -72,15 +72,20 @@ files:
72
72
  - README.md
73
73
  - spec/foreman/cli_spec.rb
74
74
  - spec/foreman/engine_spec.rb
75
+ - spec/foreman/export/base_spec.rb
75
76
  - spec/foreman/export/bluepill_spec.rb
77
+ - spec/foreman/export/inittab_spec.rb
76
78
  - spec/foreman/export/runit_spec.rb
77
79
  - spec/foreman/export/upstart_spec.rb
78
80
  - spec/foreman/export_spec.rb
81
+ - spec/foreman/helpers_spec.rb
79
82
  - spec/foreman/process_spec.rb
80
83
  - spec/foreman_spec.rb
81
84
  - spec/helper_spec.rb
82
85
  - spec/resources/export/bluepill/app-concurrency.pill
83
86
  - spec/resources/export/bluepill/app.pill
87
+ - spec/resources/export/inittab/inittab.concurrency
88
+ - spec/resources/export/inittab/inittab.default
84
89
  - spec/resources/export/runit/app-alpha-1-log-run
85
90
  - spec/resources/export/runit/app-alpha-1-run
86
91
  - spec/resources/export/runit/app-alpha-2-log-run
@@ -110,9 +115,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
115
  required_rubygems_version: !ruby/object:Gem::Requirement
111
116
  none: false
112
117
  requirements:
113
- - - ! '>'
118
+ - - ! '>='
114
119
  - !ruby/object:Gem::Version
115
- version: 1.3.1
120
+ version: '0'
116
121
  requirements: []
117
122
  rubyforge_project:
118
123
  rubygems_version: 1.8.15