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 +3 -22
- data/lib/foreman/engine.rb +15 -7
- data/lib/foreman/export.rb +21 -0
- data/lib/foreman/export/inittab.rb +4 -4
- data/lib/foreman/helpers.rb +2 -7
- data/lib/foreman/process.rb +1 -1
- data/lib/foreman/version.rb +1 -1
- data/spec/foreman/cli_spec.rb +21 -4
- data/spec/foreman/export/base_spec.rb +22 -0
- data/spec/foreman/export/bluepill_spec.rb +8 -1
- data/spec/foreman/export/inittab_spec.rb +40 -0
- data/spec/foreman/export/upstart_spec.rb +11 -0
- data/spec/foreman/export_spec.rb +22 -0
- data/spec/foreman/helpers_spec.rb +26 -0
- data/spec/foreman_spec.rb +6 -0
- data/spec/resources/export/inittab/inittab.concurrency +4 -0
- data/spec/resources/export/inittab/inittab.default +4 -0
- data/spec/spec_helper.rb +14 -2
- metadata +14 -9
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
|
-
|
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")
|
data/lib/foreman/engine.rb
CHANGED
@@ -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)
|
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
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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)
|
data/lib/foreman/export.rb
CHANGED
@@ -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
|
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(
|
31
|
-
else
|
32
|
-
puts inittab
|
32
|
+
write_file(location, inittab)
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
data/lib/foreman/helpers.rb
CHANGED
@@ -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
|
data/lib/foreman/process.rb
CHANGED
data/lib/foreman/version.rb
CHANGED
data/spec/foreman/cli_spec.rb
CHANGED
@@ -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
|
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, "
|
55
|
-
subject.export("
|
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).
|
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
|
-
|
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
|
|
data/spec/foreman/export_spec.rb
CHANGED
@@ -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
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
|
-
|
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
|
5
|
-
prerelease:
|
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-
|
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: &
|
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: *
|
24
|
+
version_requirements: *70149919501700
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: thor
|
27
|
-
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: *
|
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:
|
120
|
+
version: '0'
|
116
121
|
requirements: []
|
117
122
|
rubyforge_project:
|
118
123
|
rubygems_version: 1.8.15
|