foreman 0.27.0 → 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/README.md +39 -0
- data/bin/runner +36 -0
- data/data/export/bluepill/master.pill.erb +3 -3
- data/lib/foreman/cli.rb +34 -32
- data/lib/foreman/engine.rb +97 -78
- data/lib/foreman/export/base.rb +12 -5
- data/lib/foreman/export/bluepill.rb +5 -7
- data/lib/foreman/export/inittab.rb +11 -13
- data/lib/foreman/export/runit.rb +24 -25
- data/lib/foreman/export/upstart.rb +9 -11
- data/lib/foreman/export.rb +21 -0
- data/lib/foreman/helpers.rb +45 -0
- data/lib/foreman/process.rb +88 -6
- data/lib/foreman/procfile.rb +8 -7
- data/lib/foreman/procfile_entry.rb +22 -0
- data/lib/foreman/utils.rb +4 -1
- data/lib/foreman/version.rb +1 -1
- data/lib/foreman.rb +13 -1
- data/man/foreman.1 +5 -1
- data/spec/foreman/cli_spec.rb +77 -7
- data/spec/foreman/engine_spec.rb +13 -26
- data/spec/foreman/export/base_spec.rb +22 -0
- data/spec/foreman/export/bluepill_spec.rb +23 -7
- data/spec/foreman/export/inittab_spec.rb +40 -0
- data/spec/foreman/export/runit_spec.rb +18 -12
- data/spec/foreman/export/upstart_spec.rb +40 -8
- data/spec/foreman/export_spec.rb +22 -0
- data/spec/foreman/helpers_spec.rb +26 -0
- data/spec/foreman/process_spec.rb +131 -2
- data/spec/foreman_spec.rb +8 -7
- data/spec/helper_spec.rb +18 -0
- data/spec/resources/export/bluepill/app-concurrency.pill +47 -0
- data/spec/resources/export/bluepill/app.pill +1 -22
- data/spec/resources/export/inittab/inittab.concurrency +4 -0
- data/spec/resources/export/inittab/inittab.default +4 -0
- data/spec/spec_helper.rb +31 -3
- metadata +19 -15
- data/README.markdown +0 -49
|
@@ -3,37 +3,35 @@ require "foreman/export"
|
|
|
3
3
|
|
|
4
4
|
class Foreman::Export::Upstart < Foreman::Export::Base
|
|
5
5
|
|
|
6
|
-
def export
|
|
6
|
+
def export
|
|
7
7
|
error("Must specify a location") unless location
|
|
8
8
|
|
|
9
9
|
FileUtils.mkdir_p location
|
|
10
10
|
|
|
11
|
-
app =
|
|
12
|
-
user =
|
|
13
|
-
log_root =
|
|
14
|
-
template_root =
|
|
11
|
+
app = self.app || File.basename(engine.directory)
|
|
12
|
+
user = self.user || app
|
|
13
|
+
log_root = self.log || "/var/log/#{app}"
|
|
14
|
+
template_root = self.template
|
|
15
15
|
|
|
16
16
|
Dir["#{location}/#{app}*.conf"].each do |file|
|
|
17
17
|
say "cleaning up: #{file}"
|
|
18
18
|
FileUtils.rm(file)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
concurrency = Foreman::Utils.parse_concurrency(options[:concurrency])
|
|
22
|
-
|
|
23
21
|
master_template = export_template("upstart", "master.conf.erb", template_root)
|
|
24
22
|
master_config = ERB.new(master_template).result(binding)
|
|
25
23
|
write_file "#{location}/#{app}.conf", master_config
|
|
26
24
|
|
|
27
25
|
process_template = export_template("upstart", "process.conf.erb", template_root)
|
|
28
26
|
|
|
29
|
-
engine.
|
|
30
|
-
next if (conc = concurrency[process.name]) < 1
|
|
27
|
+
engine.procfile.entries.each do |process|
|
|
28
|
+
next if (conc = self.concurrency[process.name]) < 1
|
|
31
29
|
process_master_template = export_template("upstart", "process_master.conf.erb", template_root)
|
|
32
30
|
process_master_config = ERB.new(process_master_template).result(binding)
|
|
33
31
|
write_file "#{location}/#{app}-#{process.name}.conf", process_master_config
|
|
34
32
|
|
|
35
|
-
1.upto(concurrency[process.name]) do |num|
|
|
36
|
-
port = engine.port_for(process, num,
|
|
33
|
+
1.upto(self.concurrency[process.name]) do |num|
|
|
34
|
+
port = engine.port_for(process, num, self.port)
|
|
37
35
|
process_config = ERB.new(process_template).result(binding)
|
|
38
36
|
write_file "#{location}/#{app}-#{process.name}-#{num}.conf", process_config
|
|
39
37
|
end
|
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"
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Foreman::Helpers
|
|
2
|
+
# Copied whole sale from, https://github.com/defunkt/resque/
|
|
3
|
+
|
|
4
|
+
# Given a word with dashes, returns a camel cased version of it.
|
|
5
|
+
#
|
|
6
|
+
# classify('job-name') # => 'JobName'
|
|
7
|
+
def classify(dashed_word)
|
|
8
|
+
dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
|
|
9
|
+
end # Tries to find a constant with the name specified in the argument string:
|
|
10
|
+
|
|
11
|
+
#
|
|
12
|
+
# constantize("Module") # => Module
|
|
13
|
+
# constantize("Test::Unit") # => Test::Unit
|
|
14
|
+
#
|
|
15
|
+
# The name is assumed to be the one of a top-level constant, no matter
|
|
16
|
+
# whether it starts with "::" or not. No lexical context is taken into
|
|
17
|
+
# account:
|
|
18
|
+
#
|
|
19
|
+
# C = 'outside'
|
|
20
|
+
# module M
|
|
21
|
+
# C = 'inside'
|
|
22
|
+
# C # => 'inside'
|
|
23
|
+
# constantize("C") # => 'outside', same as ::C
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
26
|
+
# NameError is raised when the constant is unknown.
|
|
27
|
+
def constantize(camel_cased_word)
|
|
28
|
+
camel_cased_word = camel_cased_word.to_s
|
|
29
|
+
|
|
30
|
+
names = camel_cased_word.split('::')
|
|
31
|
+
names.shift if names.empty? || names.first.empty?
|
|
32
|
+
|
|
33
|
+
constant = Object
|
|
34
|
+
names.each do |name|
|
|
35
|
+
args = Module.method(:const_get).arity != 1 ? [false] : []
|
|
36
|
+
|
|
37
|
+
if constant.const_defined?(name, *args)
|
|
38
|
+
constant = constant.const_get(name)
|
|
39
|
+
else
|
|
40
|
+
constant = constant.const_missing(name)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
constant
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/foreman/process.rb
CHANGED
|
@@ -1,14 +1,96 @@
|
|
|
1
1
|
require "foreman"
|
|
2
|
+
require "rubygems"
|
|
2
3
|
|
|
3
4
|
class Foreman::Process
|
|
4
5
|
|
|
5
|
-
attr_reader :
|
|
6
|
-
attr_reader :
|
|
7
|
-
|
|
6
|
+
attr_reader :entry
|
|
7
|
+
attr_reader :num
|
|
8
|
+
attr_reader :pid
|
|
9
|
+
attr_reader :port
|
|
8
10
|
|
|
9
|
-
def initialize(
|
|
10
|
-
@
|
|
11
|
-
@
|
|
11
|
+
def initialize(entry, num, port)
|
|
12
|
+
@entry = entry
|
|
13
|
+
@num = num
|
|
14
|
+
@port = port
|
|
12
15
|
end
|
|
13
16
|
|
|
17
|
+
def run(pipe, basedir, environment)
|
|
18
|
+
with_environment(environment.merge("PORT" => port.to_s)) do
|
|
19
|
+
run_process basedir, entry.command, pipe
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def name
|
|
24
|
+
"%s.%s" % [ entry.name, num ]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def kill(signal)
|
|
28
|
+
pid && Process.kill(signal, pid)
|
|
29
|
+
rescue Errno::ESRCH
|
|
30
|
+
false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def detach
|
|
34
|
+
pid && Process.detach(pid)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def alive?
|
|
38
|
+
kill(0)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def dead?
|
|
42
|
+
!alive?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def fork_with_io(command, basedir)
|
|
48
|
+
reader, writer = IO.pipe
|
|
49
|
+
command = replace_command_env(command)
|
|
50
|
+
pid = if Foreman.windows?
|
|
51
|
+
Dir.chdir(basedir) do
|
|
52
|
+
Process.spawn command, :out => writer, :err => writer
|
|
53
|
+
end
|
|
54
|
+
elsif Foreman.jruby?
|
|
55
|
+
require "posix/spawn"
|
|
56
|
+
POSIX::Spawn.spawn(Foreman.runner, "-d", basedir, command, {
|
|
57
|
+
:out => writer, :err => writer
|
|
58
|
+
})
|
|
59
|
+
else
|
|
60
|
+
fork do
|
|
61
|
+
writer.sync = true
|
|
62
|
+
$stdout.reopen writer
|
|
63
|
+
$stderr.reopen writer
|
|
64
|
+
reader.close
|
|
65
|
+
exec Foreman.runner, "-d", basedir, command
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
[ reader, pid ]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def run_process(basedir, command, pipe)
|
|
72
|
+
io, @pid = fork_with_io(command, basedir)
|
|
73
|
+
output pipe, "started with pid %d" % @pid
|
|
74
|
+
Thread.new do
|
|
75
|
+
until io.eof?
|
|
76
|
+
output pipe, io.gets
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def output(pipe, message)
|
|
82
|
+
pipe.puts "%s,%s" % [ name, message ]
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def replace_command_env(command)
|
|
86
|
+
command.gsub(/\$(\w+)/) { |e| ENV[e[1..-1]] }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def with_environment(environment)
|
|
90
|
+
original = ENV.to_hash
|
|
91
|
+
ENV.update environment
|
|
92
|
+
yield
|
|
93
|
+
ensure
|
|
94
|
+
ENV.replace original
|
|
95
|
+
end
|
|
14
96
|
end
|
data/lib/foreman/procfile.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "foreman"
|
|
2
|
+
require "foreman/procfile_entry"
|
|
2
3
|
|
|
3
4
|
# A valid Procfile entry is captured by this regex.
|
|
4
5
|
# All other lines are ignored.
|
|
@@ -10,18 +11,18 @@ require "foreman"
|
|
|
10
11
|
#
|
|
11
12
|
class Foreman::Procfile
|
|
12
13
|
|
|
13
|
-
attr_reader :
|
|
14
|
+
attr_reader :entries
|
|
14
15
|
|
|
15
16
|
def initialize(filename)
|
|
16
|
-
@
|
|
17
|
+
@entries = parse_procfile(filename)
|
|
17
18
|
end
|
|
18
19
|
|
|
19
|
-
def
|
|
20
|
-
|
|
20
|
+
def [](name)
|
|
21
|
+
entries.detect { |entry| entry.name == name }
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
def
|
|
24
|
-
|
|
24
|
+
def process_names
|
|
25
|
+
entries.map(&:name)
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
private
|
|
@@ -29,7 +30,7 @@ private
|
|
|
29
30
|
def parse_procfile(filename)
|
|
30
31
|
File.read(filename).split("\n").map do |line|
|
|
31
32
|
if line =~ /^([A-Za-z0-9_]+):\s*(.+)$/
|
|
32
|
-
Foreman::
|
|
33
|
+
Foreman::ProcfileEntry.new($1, $2)
|
|
33
34
|
end
|
|
34
35
|
end.compact
|
|
35
36
|
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require "foreman"
|
|
2
|
+
|
|
3
|
+
class Foreman::ProcfileEntry
|
|
4
|
+
|
|
5
|
+
attr_reader :name
|
|
6
|
+
attr_reader :command
|
|
7
|
+
attr_accessor :color
|
|
8
|
+
|
|
9
|
+
def initialize(name, command)
|
|
10
|
+
@name = name
|
|
11
|
+
@command = command
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def spawn(num, pipe, basedir, environment, base_port)
|
|
15
|
+
(1..num).to_a.map do |n|
|
|
16
|
+
process = Foreman::Process.new(self, n, base_port + (n-1))
|
|
17
|
+
process.run(pipe, basedir, environment)
|
|
18
|
+
process
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
data/lib/foreman/utils.rb
CHANGED
|
@@ -5,7 +5,10 @@ class Foreman::Utils
|
|
|
5
5
|
def self.parse_concurrency(concurrency)
|
|
6
6
|
begin
|
|
7
7
|
pairs = concurrency.to_s.gsub(/\s/, "").split(",")
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
default = concurrency.nil? ? 1 : 0
|
|
10
|
+
|
|
11
|
+
pairs.inject(Hash.new(default)) do |hash, pair|
|
|
9
12
|
process, amount = pair.split("=")
|
|
10
13
|
hash.update(process => amount.to_i)
|
|
11
14
|
end
|
data/lib/foreman/version.rb
CHANGED
data/lib/foreman.rb
CHANGED
|
@@ -9,5 +9,17 @@ module Foreman
|
|
|
9
9
|
require 'foreman/engine'
|
|
10
10
|
Foreman::Engine.load_env!(env_file)
|
|
11
11
|
end
|
|
12
|
-
end
|
|
13
12
|
|
|
13
|
+
def self.runner
|
|
14
|
+
File.expand_path("../../bin/runner", __FILE__)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.jruby?
|
|
18
|
+
defined?(RUBY_PLATFORM) and RUBY_PLATFORM == "java"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.windows?
|
|
22
|
+
defined?(RUBY_PLATFORM) and RUBY_PLATFORM =~ /(win|w)32$/
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
data/man/foreman.1
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
.\" generated with Ronn/v0.7.3
|
|
2
2
|
.\" http://github.com/rtomayko/ronn/tree/0.7.3
|
|
3
3
|
.
|
|
4
|
-
.TH "FOREMAN" "1" "
|
|
4
|
+
.TH "FOREMAN" "1" "January 2012" "Foreman 0.33.1" "Foreman Manual"
|
|
5
5
|
.
|
|
6
6
|
.SH "NAME"
|
|
7
7
|
\fBforeman\fR \- manage Procfile\-based applications
|
|
@@ -68,6 +68,10 @@ Specify the user the application should be run as\. Defaults to the app name
|
|
|
68
68
|
These options control all modes of foreman\'s operation\.
|
|
69
69
|
.
|
|
70
70
|
.TP
|
|
71
|
+
\fB\-d\fR, \fB\-\-directory\fR
|
|
72
|
+
Specify an alternate application root\. This defaults to the directory containing the Procfile\.
|
|
73
|
+
.
|
|
74
|
+
.TP
|
|
71
75
|
\fB\-e\fR, \fB\-\-env\fR
|
|
72
76
|
Specify an alternate environment file\. You can specify more than one file by using: \fB\-\-env file1,file2\fR\.
|
|
73
77
|
.
|
data/spec/foreman/cli_spec.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
require "foreman/cli"
|
|
3
3
|
|
|
4
|
-
describe "Foreman::CLI" do
|
|
4
|
+
describe "Foreman::CLI", :fakefs do
|
|
5
5
|
subject { Foreman::CLI.new }
|
|
6
6
|
|
|
7
7
|
describe "start" do
|
|
@@ -27,10 +27,21 @@ describe "Foreman::CLI" 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")
|
|
33
|
-
mock
|
|
42
|
+
mock_export = mock(Foreman::Export::Upstart)
|
|
43
|
+
mock(Foreman::Export::Upstart).new("/upstart", is_a(Foreman::Engine), { "env" => "envfile" }) { mock_export }
|
|
44
|
+
mock_export.export
|
|
34
45
|
foreman %{ export upstart /upstart --env envfile }
|
|
35
46
|
end
|
|
36
47
|
end
|
|
@@ -47,10 +58,18 @@ describe "Foreman::CLI" do
|
|
|
47
58
|
describe "with a Procfile" do
|
|
48
59
|
before(:each) { write_procfile }
|
|
49
60
|
|
|
50
|
-
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
|
+
|
|
51
70
|
it "prints an error" do
|
|
52
|
-
mock_error(subject, "
|
|
53
|
-
subject.export("
|
|
71
|
+
mock_error(subject, "foo") do
|
|
72
|
+
subject.export("errorful")
|
|
54
73
|
end
|
|
55
74
|
end
|
|
56
75
|
end
|
|
@@ -60,7 +79,9 @@ describe "Foreman::CLI" do
|
|
|
60
79
|
|
|
61
80
|
it "runs successfully" do
|
|
62
81
|
dont_allow(subject).error
|
|
63
|
-
mock
|
|
82
|
+
mock_export = mock(Foreman::Export::Upstart)
|
|
83
|
+
mock(Foreman::Export::Upstart).new("/tmp/foo", is_a(Foreman::Engine), {}) { mock_export }
|
|
84
|
+
mock_export.export
|
|
64
85
|
subject.export("upstart", "/tmp/foo")
|
|
65
86
|
end
|
|
66
87
|
end
|
|
@@ -72,7 +93,7 @@ describe "Foreman::CLI" do
|
|
|
72
93
|
before { write_procfile }
|
|
73
94
|
|
|
74
95
|
it "displays the jobs" do
|
|
75
|
-
mock(subject).
|
|
96
|
+
mock(subject).puts("valid procfile detected (alpha, bravo)")
|
|
76
97
|
subject.check
|
|
77
98
|
end
|
|
78
99
|
end
|
|
@@ -90,4 +111,53 @@ describe "Foreman::CLI" do
|
|
|
90
111
|
end
|
|
91
112
|
end
|
|
92
113
|
|
|
114
|
+
describe "run" do
|
|
115
|
+
describe "with a valid Procfile" do
|
|
116
|
+
before { write_procfile }
|
|
117
|
+
|
|
118
|
+
describe "and a command" do
|
|
119
|
+
let(:command) { ["ls", "-l"] }
|
|
120
|
+
|
|
121
|
+
before(:each) do
|
|
122
|
+
stub(subject).exec
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "should load the environment file" do
|
|
126
|
+
write_env
|
|
127
|
+
preserving_env do
|
|
128
|
+
subject.run *command
|
|
129
|
+
ENV["FOO"].should == "bar"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
ENV["FOO"].should be_nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "should runute the command as a string" do
|
|
136
|
+
mock(subject).exec(command.join(" "))
|
|
137
|
+
subject.run *command
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe "and a non-existent command" do
|
|
142
|
+
let(:command) { "iuhtngrglhulhdfg" }
|
|
143
|
+
|
|
144
|
+
it "should print an error" do
|
|
145
|
+
mock_error(subject, "command not found: #{command}") do
|
|
146
|
+
subject.run command
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
describe "and a non-executable command" do
|
|
152
|
+
let(:command) { __FILE__ }
|
|
153
|
+
|
|
154
|
+
it "should print an error" do
|
|
155
|
+
mock_error(subject, "not executable: #{command}") do
|
|
156
|
+
subject.run command
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
93
163
|
end
|
data/spec/foreman/engine_spec.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require "spec_helper"
|
|
2
2
|
require "foreman/engine"
|
|
3
3
|
|
|
4
|
-
describe "Foreman::Engine" do
|
|
4
|
+
describe "Foreman::Engine", :fakefs do
|
|
5
5
|
subject { Foreman::Engine.new("Procfile", {}) }
|
|
6
6
|
|
|
7
7
|
describe "initialize" do
|
|
@@ -24,8 +24,9 @@ describe "Foreman::Engine" do
|
|
|
24
24
|
describe "start" do
|
|
25
25
|
it "forks the processes" do
|
|
26
26
|
write_procfile
|
|
27
|
-
mock(
|
|
28
|
-
mock(
|
|
27
|
+
mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./alpha", is_a(IO))
|
|
28
|
+
mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./bravo", is_a(IO))
|
|
29
|
+
mock(subject).watch_for_output
|
|
29
30
|
mock(subject).watch_for_termination
|
|
30
31
|
subject.start
|
|
31
32
|
end
|
|
@@ -33,29 +34,14 @@ describe "Foreman::Engine" do
|
|
|
33
34
|
it "handles concurrency" do
|
|
34
35
|
write_procfile
|
|
35
36
|
engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2")
|
|
36
|
-
mock(
|
|
37
|
-
mock(
|
|
38
|
-
mock(engine).
|
|
37
|
+
mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./alpha", is_a(IO)).twice
|
|
38
|
+
mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./bravo", is_a(IO)).never
|
|
39
|
+
mock(engine).watch_for_output
|
|
39
40
|
mock(engine).watch_for_termination
|
|
40
41
|
engine.start
|
|
41
42
|
end
|
|
42
43
|
end
|
|
43
44
|
|
|
44
|
-
describe "execute" do
|
|
45
|
-
it "runs the processes" do
|
|
46
|
-
write_procfile
|
|
47
|
-
mock(subject).fork(subject.procfile["alpha"])
|
|
48
|
-
mock(subject).watch_for_termination
|
|
49
|
-
subject.execute("alpha")
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it "shows an error running a process that doesnt exist" do
|
|
53
|
-
write_procfile
|
|
54
|
-
mock(subject).puts("ERROR: no such process: foo")
|
|
55
|
-
lambda { subject.execute("foo") }.should raise_error(SystemExit)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
|
|
59
45
|
describe "environment" do
|
|
60
46
|
before(:each) do
|
|
61
47
|
write_procfile
|
|
@@ -66,9 +52,10 @@ describe "Foreman::Engine" do
|
|
|
66
52
|
File.open("/tmp/env", "w") { |f| f.puts("FOO=baz") }
|
|
67
53
|
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env")
|
|
68
54
|
stub(engine).info
|
|
55
|
+
mock(engine).spawn_processes
|
|
69
56
|
mock(engine).watch_for_termination
|
|
70
57
|
engine.environment.should == {"FOO"=>"baz"}
|
|
71
|
-
engine.
|
|
58
|
+
engine.start
|
|
72
59
|
end
|
|
73
60
|
|
|
74
61
|
it "should read more than one if specified" do
|
|
@@ -76,9 +63,10 @@ describe "Foreman::Engine" do
|
|
|
76
63
|
File.open("/tmp/env2", "w") { |f| f.puts("BAZ=qux") }
|
|
77
64
|
engine = Foreman::Engine.new("Procfile", :env => "/tmp/env1,/tmp/env2")
|
|
78
65
|
stub(engine).info
|
|
66
|
+
mock(engine).spawn_processes
|
|
79
67
|
mock(engine).watch_for_termination
|
|
80
68
|
engine.environment.should == { "FOO"=>"bar", "BAZ"=>"qux" }
|
|
81
|
-
engine.
|
|
69
|
+
engine.start
|
|
82
70
|
end
|
|
83
71
|
|
|
84
72
|
it "should fail if specified and doesnt exist" do
|
|
@@ -89,11 +77,10 @@ describe "Foreman::Engine" do
|
|
|
89
77
|
it "should read .env if none specified" do
|
|
90
78
|
File.open(".env", "w") { |f| f.puts("FOO=qoo") }
|
|
91
79
|
engine = Foreman::Engine.new("Procfile")
|
|
92
|
-
|
|
80
|
+
mock(engine).spawn_processes
|
|
93
81
|
mock(engine).watch_for_termination
|
|
94
|
-
mock(engine).fork_individual(anything, anything, anything)
|
|
95
82
|
engine.environment.should == {"FOO"=>"qoo"}
|
|
96
|
-
engine.
|
|
83
|
+
engine.start
|
|
97
84
|
end
|
|
98
85
|
end
|
|
99
86
|
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
|
|
@@ -3,18 +3,34 @@ require "foreman/engine"
|
|
|
3
3
|
require "foreman/export/bluepill"
|
|
4
4
|
require "tmpdir"
|
|
5
5
|
|
|
6
|
-
describe Foreman::Export::Bluepill do
|
|
6
|
+
describe Foreman::Export::Bluepill, :fakefs do
|
|
7
7
|
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
|
|
8
|
-
let(:engine)
|
|
9
|
-
let(:
|
|
8
|
+
let(:engine) { Foreman::Engine.new(procfile) }
|
|
9
|
+
let(:options) { Hash.new }
|
|
10
|
+
let(:bluepill) { Foreman::Export::Bluepill.new("/tmp/init", engine, options) }
|
|
10
11
|
|
|
11
12
|
before(:each) { load_export_templates_into_fakefs("bluepill") }
|
|
12
13
|
before(:each) { stub(bluepill).say }
|
|
13
14
|
|
|
14
15
|
it "exports to the filesystem" do
|
|
15
|
-
bluepill.export
|
|
16
|
-
|
|
17
|
-
File.read("/tmp/init/app.pill").should == example_export_file("bluepill/app.pill")
|
|
16
|
+
bluepill.export
|
|
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
|
|
28
|
+
let(:options) { Hash[:concurrency => "alpha=2"] }
|
|
29
|
+
|
|
30
|
+
it "exports to the filesystem with concurrency" do
|
|
31
|
+
bluepill.export
|
|
32
|
+
normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app-concurrency.pill"))
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
@@ -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
|