foreman 0.46.0-mingw32 → 0.50.0-mingw32

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 (68) hide show
  1. data/README.md +6 -0
  2. data/bin/foreman-runner +3 -7
  3. data/bin/taskman +8 -0
  4. data/data/example/Procfile +4 -3
  5. data/data/example/spawnee +14 -0
  6. data/data/example/spawner +7 -0
  7. data/data/export/bluepill/master.pill.erb +11 -10
  8. data/data/export/launchd/launchd.plist.erb +22 -0
  9. data/data/export/runit/log/run.erb +7 -0
  10. data/data/export/runit/run.erb +2 -2
  11. data/data/export/supervisord/app.conf.erb +12 -12
  12. data/data/export/upstart/master.conf.erb +2 -2
  13. data/data/export/upstart/process.conf.erb +3 -3
  14. data/lib/foreman.rb +4 -0
  15. data/lib/foreman/cli.rb +59 -23
  16. data/lib/foreman/engine.rb +233 -147
  17. data/lib/foreman/engine/cli.rb +105 -0
  18. data/lib/foreman/env.rb +27 -0
  19. data/lib/foreman/export.rb +2 -2
  20. data/lib/foreman/export/base.rb +107 -12
  21. data/lib/foreman/export/bluepill.rb +3 -17
  22. data/lib/foreman/export/inittab.rb +8 -11
  23. data/lib/foreman/export/launchd.rb +15 -0
  24. data/lib/foreman/export/runit.rb +14 -39
  25. data/lib/foreman/export/supervisord.rb +3 -13
  26. data/lib/foreman/export/upstart.rb +9 -27
  27. data/lib/foreman/process.rb +73 -67
  28. data/lib/foreman/procfile.rb +59 -25
  29. data/lib/foreman/version.rb +1 -1
  30. data/man/foreman.1 +5 -1
  31. data/spec/foreman/cli_spec.rb +46 -150
  32. data/spec/foreman/engine_spec.rb +47 -74
  33. data/spec/foreman/export/base_spec.rb +4 -7
  34. data/spec/foreman/export/bluepill_spec.rb +7 -6
  35. data/spec/foreman/export/inittab_spec.rb +7 -7
  36. data/spec/foreman/export/launchd_spec.rb +21 -0
  37. data/spec/foreman/export/runit_spec.rb +12 -17
  38. data/spec/foreman/export/supervisord_spec.rb +7 -56
  39. data/spec/foreman/export/upstart_spec.rb +22 -21
  40. data/spec/foreman/process_spec.rb +27 -110
  41. data/spec/foreman/procfile_spec.rb +26 -16
  42. data/spec/resources/Procfile +4 -0
  43. data/spec/resources/bin/echo +2 -0
  44. data/spec/resources/bin/env +2 -0
  45. data/spec/resources/bin/test +2 -0
  46. data/spec/resources/export/bluepill/app-concurrency.pill +6 -4
  47. data/spec/resources/export/bluepill/app.pill +6 -4
  48. data/spec/resources/export/launchd/launchd-a.default +22 -0
  49. data/spec/resources/export/launchd/launchd-b.default +22 -0
  50. data/spec/resources/export/runit/{app-alpha-1-log-run → app-alpha-1/log/run} +0 -0
  51. data/spec/resources/export/runit/{app-alpha-1-run → app-alpha-1/run} +0 -0
  52. data/spec/resources/export/runit/{app-alpha-2-log-run → app-alpha-2/log/run} +0 -0
  53. data/spec/resources/export/runit/{app-alpha-2-run → app-alpha-2/run} +0 -0
  54. data/spec/resources/export/runit/{app-bravo-1-log-run → app-bravo-1/log/run} +0 -0
  55. data/spec/resources/export/runit/{app-bravo-1-run → app-bravo-1/run} +0 -0
  56. data/spec/resources/export/supervisord/app-alpha-1.conf +24 -0
  57. data/spec/resources/export/supervisord/app-alpha-2.conf +4 -4
  58. data/spec/spec_helper.rb +57 -6
  59. metadata +29 -21
  60. data/data/export/runit/log_run.erb +0 -7
  61. data/lib/foreman/color.rb +0 -40
  62. data/lib/foreman/procfile_entry.rb +0 -26
  63. data/lib/foreman/utils.rb +0 -18
  64. data/spec/foreman/color_spec.rb +0 -31
  65. data/spec/foreman/procfile_entry_spec.rb +0 -13
  66. data/spec/resources/export/supervisord/app-env-with-comma.conf +0 -24
  67. data/spec/resources/export/supervisord/app-env.conf +0 -21
  68. data/spec/resources/export/supervisord/app.conf +0 -24
@@ -5,127 +5,44 @@ require 'timeout'
5
5
  require 'tmpdir'
6
6
 
7
7
  describe Foreman::Process do
8
- subject { described_class.new entry, number, port }
9
8
 
10
- let(:number) { 1 }
11
- let(:port) { 777 }
12
- let(:command) { "script" }
13
- let(:name) { "foobar" }
14
- let(:entry) { OpenStruct.new :name => name, :command => command }
15
-
16
- its(:entry) { entry }
17
- its(:num) { number }
18
- its(:port) { port }
19
- its(:name) { "#{name}.#{port}" }
20
- its(:pid) { nil }
21
-
22
- describe '#run' do
23
- let(:pipe) { :pipe }
24
- let(:basedir) { Dir.mktmpdir }
25
- let(:env) {{ 'foo' => 'bar' }}
26
- let(:init_delta) { 0.1 }
9
+ def run(process, options={})
10
+ rd, wr = IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY")
11
+ process.run(options.merge(:output => wr))
12
+ rd.gets
13
+ end
27
14
 
28
- after { FileUtils.remove_entry_secure basedir }
15
+ describe "#run" do
29
16
 
30
- def run(cmd=command)
31
- entry.command = cmd
32
- subject.run pipe, basedir, env
33
- subject.detach && sleep(init_delta)
17
+ it "runs the process" do
18
+ process = Foreman::Process.new(resource_path("bin/test"))
19
+ run(process).should == "testing\n"
34
20
  end
35
21
 
36
- def run_file(executable, code)
37
- file = File.open("#{basedir}/script", 'w') {|it| it << code }
38
- run "#{executable} #{file.path}"
39
- sleep 1
22
+ it "can set environment" do
23
+ process = Foreman::Process.new(resource_path("bin/env FOO"), :env => { "FOO" => "bar" })
24
+ run(process).should == "bar\n"
40
25
  end
41
26
 
42
- context 'options' do
43
- it 'should set PORT for environment' do
44
- mock(subject).run_process(basedir, command, pipe) do
45
- ENV['PORT'].should == port.to_s
46
- end
47
- run
48
- end
49
-
50
- it 'should set custom variables for environment' do
51
- mock(subject).run_process(basedir, command, pipe) do
52
- ENV['foo'].should == 'bar'
53
- end
54
- run
55
- end
56
-
57
- it 'should restore environment afterwards' do
58
- mock(subject).run_process(basedir, command, pipe)
59
- run
60
- ENV.should_not include('PORT', 'foo')
61
- end
27
+ it "can set per-run environment" do
28
+ process = Foreman::Process.new(resource_path("bin/env FOO"))
29
+ run(process, :env => { "FOO" => "bar "}).should == "bar\n"
62
30
  end
63
31
 
64
- context 'process' do
65
- around do |spec|
66
- IO.pipe do |reader, writer|
67
- @reader, @writer = reader, writer
68
- spec.run
69
- end
70
- end
71
-
72
- let(:pipe) { @writer }
73
- let(:output) { @reader.read_nonblock 1024 }
74
-
75
- it 'should not block' do
76
- expect {
77
- Timeout.timeout(2*init_delta) { run 'sleep 2' }
78
- }.should_not raise_exception
79
- end
80
-
81
- it 'should be alive' do
82
- run 'sleep 1'
83
- subject.should be_alive
84
- end
85
-
86
- it 'should be dead' do
87
- run 'exit'
88
- subject.should be_dead
89
- end
90
-
91
- it 'should be killable' do
92
- run 'sleep 1'
93
- subject.kill 'TERM'
94
- subject.should be_dead
95
- end
96
-
97
- it 'should send different signals' do
98
- run_file 'ruby', <<-CODE
99
- trap "TERM", "IGNORE"
100
- loop { sleep 1 }
101
- CODE
102
- subject.should be_alive
103
- subject.kill 'TERM'
104
- subject.should be_alive
105
- subject.kill 'KILL'
106
- subject.should be_dead
107
- end
108
-
109
- it 'should redirect stdout' do
110
- run 'echo hey'
111
- output.should include('hey')
112
- end
113
-
114
- it 'should redirect stderr' do
115
- run 'echo hey >2'
116
- output.should include('hey')
117
- end
32
+ it "can handle env vars in the command" do
33
+ process = Foreman::Process.new(resource_path("bin/echo $FOO"), :env => { "FOO" => "bar" })
34
+ run(process).should == "bar\n"
35
+ end
118
36
 
119
- it 'should handle variables' do
120
- run 'echo $PORT'
121
- output.should include('777')
122
- end
37
+ it "can handle per-run env vars in the command" do
38
+ process = Foreman::Process.new(resource_path("bin/echo $FOO"))
39
+ run(process, :env => { "FOO" => "bar" }).should == "bar\n"
40
+ end
123
41
 
124
- it 'should handle arguments' do
125
- pending
126
- run %{ sh -c "trap '' TERM; sleep 10" }
127
- subject.should be_alive
128
- end
42
+ it "should output utf8 properly" do
43
+ process = Foreman::Process.new(resource_path("bin/utf8"))
44
+ run(process).should == "\xFF\x03\n"
129
45
  end
130
46
  end
47
+
131
48
  end
@@ -3,29 +3,39 @@ require 'foreman/procfile'
3
3
  require 'pathname'
4
4
  require 'tmpdir'
5
5
 
6
- describe Foreman::Procfile do
7
- subject { described_class.new }
6
+ describe Foreman::Procfile, :fakefs do
7
+ subject { Foreman::Procfile.new }
8
8
 
9
- let(:testdir) { Pathname(Dir.tmpdir) }
10
- let(:procfile) { testdir + 'Procfile' }
9
+ it "can load from a file" do
10
+ write_procfile
11
+ subject.load "Procfile"
12
+ subject["alpha"].should == "./alpha"
13
+ subject["bravo"].should == "./bravo"
14
+ end
15
+
16
+ it "loads a passed-in Procfile" do
17
+ write_procfile
18
+ procfile = Foreman::Procfile.new("Procfile")
19
+ procfile["alpha"].should == "./alpha"
20
+ procfile["bravo"].should == "./bravo"
21
+ end
11
22
 
12
23
  it "can have a process appended to it" do
13
- subject << ['alpha', './alpha']
14
- subject['alpha'].should be_a(Foreman::ProcfileEntry)
24
+ subject["charlie"] = "./charlie"
25
+ subject["charlie"].should == "./charlie"
15
26
  end
16
27
 
17
- it "can write itself out to a file" do
18
- subject << ['alpha', './alpha']
19
- subject.write(procfile)
20
- procfile.read.should == "alpha: ./alpha\n"
28
+ it "can write to a string" do
29
+ subject["foo"] = "./foo"
30
+ subject["bar"] = "./bar"
31
+ subject.to_s.should == "foo: ./foo\nbar: ./bar"
21
32
  end
22
33
 
23
- it "can re-read entries from a file" do
24
- procfile.open('w') { |io| io.puts "gamma: ./radiation", "theta: ./rate" }
25
- subject << ['alpha', './alpha']
26
- subject.load(procfile)
27
- subject.process_names.should have(2).members
28
- subject.process_names.should include('gamma', 'theta')
34
+ it "can write to a file" do
35
+ subject["foo"] = "./foo"
36
+ subject["bar"] = "./bar"
37
+ subject.save "/tmp/proc"
38
+ File.read("/tmp/proc").should == "foo: ./foo\nbar: ./bar\n"
29
39
  end
30
40
 
31
41
  end
@@ -0,0 +1,4 @@
1
+ echo: bin/echo echoing
2
+ env: bin/env FOO
3
+ test: bin/test
4
+ utf8: bin/utf8
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ echo $*
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ echo ${!1}
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ echo "testing"
@@ -11,13 +11,14 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
11
11
 
12
12
  process.working_dir = "/tmp/app"
13
13
  process.daemonize = true
14
- process.environment = {"PORT" => "5000"}
14
+ process.environment = {"PORT"=>"5000"}
15
15
  process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
16
+ process.stop_grace_time = 45.seconds
16
17
 
17
18
  process.stdout = process.stderr = "/var/log/app/app-alpha-1.log"
18
19
 
19
20
  process.monitor_children do |children|
20
- children.stop_command "kill -QUIT {{PID}}"
21
+ children.stop_command "kill {{PID}}"
21
22
  end
22
23
 
23
24
  process.group = "app-alpha"
@@ -29,13 +30,14 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
29
30
 
30
31
  process.working_dir = "/tmp/app"
31
32
  process.daemonize = true
32
- process.environment = {"PORT" => "5001"}
33
+ process.environment = {"PORT"=>"5001"}
33
34
  process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
35
+ process.stop_grace_time = 45.seconds
34
36
 
35
37
  process.stdout = process.stderr = "/var/log/app/app-alpha-2.log"
36
38
 
37
39
  process.monitor_children do |children|
38
- children.stop_command "kill -QUIT {{PID}}"
40
+ children.stop_command "kill {{PID}}"
39
41
  end
40
42
 
41
43
  process.group = "app-alpha"
@@ -11,13 +11,14 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
11
11
 
12
12
  process.working_dir = "/tmp/app"
13
13
  process.daemonize = true
14
- process.environment = {"PORT" => "5000"}
14
+ process.environment = {"PORT"=>"5000"}
15
15
  process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
16
+ process.stop_grace_time = 45.seconds
16
17
 
17
18
  process.stdout = process.stderr = "/var/log/app/app-alpha-1.log"
18
19
 
19
20
  process.monitor_children do |children|
20
- children.stop_command "kill -QUIT {{PID}}"
21
+ children.stop_command "kill {{PID}}"
21
22
  end
22
23
 
23
24
  process.group = "app-alpha"
@@ -28,13 +29,14 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
28
29
 
29
30
  process.working_dir = "/tmp/app"
30
31
  process.daemonize = true
31
- process.environment = {"PORT" => "5100"}
32
+ process.environment = {"PORT"=>"5100"}
32
33
  process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
34
+ process.stop_grace_time = 45.seconds
33
35
 
34
36
  process.stdout = process.stderr = "/var/log/app/app-bravo-1.log"
35
37
 
36
38
  process.monitor_children do |children|
37
- children.stop_command "kill -QUIT {{PID}}"
39
+ children.stop_command "kill {{PID}}"
38
40
  end
39
41
 
40
42
  process.group = "app-bravo"
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string>app-alpha-1</string>
7
+ <key>ProgramArguments</key>
8
+ <array>
9
+ <string>./alpha</string>
10
+ </array>
11
+ <key>KeepAlive</key>
12
+ <true/>
13
+ <key>RunAtLoad</key>
14
+ <true/>
15
+ <key>StandardErrorPath</key>
16
+ <string>/var/log/app/app-alpha-1.log</string>
17
+ <key>UserName</key>
18
+ <string>app</string>
19
+ <key>WorkingDirectory</key>
20
+ <string>/tmp/app</string>
21
+ </dict>
22
+ </plist>
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>Label</key>
6
+ <string>app-bravo-1</string>
7
+ <key>ProgramArguments</key>
8
+ <array>
9
+ <string>./bravo</string>
10
+ </array>
11
+ <key>KeepAlive</key>
12
+ <true/>
13
+ <key>RunAtLoad</key>
14
+ <true/>
15
+ <key>StandardErrorPath</key>
16
+ <string>/var/log/app/app-bravo-1.log</string>
17
+ <key>UserName</key>
18
+ <string>app</string>
19
+ <key>WorkingDirectory</key>
20
+ <string>/tmp/app</string>
21
+ </dict>
22
+ </plist>
@@ -0,0 +1,24 @@
1
+
2
+ [program:app-alpha-1]
3
+ command=./alpha
4
+ autostart=true
5
+ autorestart=true
6
+ stopsignal=QUIT
7
+ stdout_logfile=/var/log/app/alpha-1.log
8
+ stderr_logfile=/var/log/app/alpha-1.error.log
9
+ user=app
10
+ directory=/tmp/app
11
+ environment=PORT="5000"
12
+ [program:app-bravo-1]
13
+ command=./bravo
14
+ autostart=true
15
+ autorestart=true
16
+ stopsignal=QUIT
17
+ stdout_logfile=/var/log/app/bravo-1.log
18
+ stderr_logfile=/var/log/app/bravo-1.error.log
19
+ user=app
20
+ directory=/tmp/app
21
+ environment=PORT="5100"
22
+
23
+ [group:app]
24
+ programs=app-alpha-1,app-bravo-1
@@ -4,8 +4,8 @@ command=./alpha
4
4
  autostart=true
5
5
  autorestart=true
6
6
  stopsignal=QUIT
7
- stdout_logfile=/var/log/app/alpha-1-out.log
8
- stderr_logfile=/var/log/app/alpha-1-err.log
7
+ stdout_logfile=/var/log/app/alpha-1.log
8
+ stderr_logfile=/var/log/app/alpha-1.error.log
9
9
  user=app
10
10
  directory=/tmp/app
11
11
  environment=PORT="5000"
@@ -14,8 +14,8 @@ command=./alpha
14
14
  autostart=true
15
15
  autorestart=true
16
16
  stopsignal=QUIT
17
- stdout_logfile=/var/log/app/alpha-2-out.log
18
- stderr_logfile=/var/log/app/alpha-2-err.log
17
+ stdout_logfile=/var/log/app/alpha-2.log
18
+ stderr_logfile=/var/log/app/alpha-2.error.log
19
19
  user=app
20
20
  directory=/tmp/app
21
21
  environment=PORT="5001"
data/spec/spec_helper.rb CHANGED
@@ -6,6 +6,7 @@ SimpleCov.start do
6
6
  end
7
7
 
8
8
  require "rspec"
9
+ require "timecop"
9
10
  require "fakefs/safe"
10
11
  require "fakefs/spec_helpers"
11
12
 
@@ -23,7 +24,38 @@ def mock_error(subject, message)
23
24
  end
24
25
 
25
26
  def foreman(args)
26
- Foreman::CLI.start(args.split(" "))
27
+ capture_stdout do
28
+ begin
29
+ Foreman::CLI.start(args.split(" "))
30
+ rescue SystemExit
31
+ end
32
+ end
33
+ end
34
+
35
+ def forked_foreman(args)
36
+ rd, wr = IO.pipe("BINARY")
37
+ Process.spawn("bundle exec bin/foreman #{args}", :out => wr, :err => wr)
38
+ wr.close
39
+ rd.read
40
+ end
41
+
42
+ def fork_and_capture(&blk)
43
+ rd, wr = IO.pipe("BINARY")
44
+ pid = fork do
45
+ rd.close
46
+ wr.sync = true
47
+ $stdout.reopen wr
48
+ $stderr.reopen wr
49
+ blk.call
50
+ $stdout.flush
51
+ $stdout.close
52
+ end
53
+ wr.close
54
+ Process.wait pid
55
+ buffer = ""
56
+ until rd.eof?
57
+ buffer += rd.gets
58
+ end
27
59
  end
28
60
 
29
61
  def mock_exit(&block)
@@ -55,13 +87,21 @@ def write_env(env=".env", options={"FOO"=>"bar"})
55
87
  end
56
88
  end
57
89
 
58
- def load_export_templates_into_fakefs(type)
90
+ def without_fakefs
59
91
  FakeFS.deactivate!
60
- files = Dir[File.expand_path("../../data/export/#{type}/**", __FILE__)].inject({}) do |hash, file|
61
- hash.update(file => File.read(file))
62
- end
92
+ ret = yield
63
93
  FakeFS.activate!
64
- files.each do |filename, contents|
94
+ ret
95
+ end
96
+
97
+ def load_export_templates_into_fakefs(type)
98
+ without_fakefs do
99
+ Dir[File.expand_path("../../data/export/#{type}/**/*", __FILE__)].inject({}) do |hash, file|
100
+ next(hash) if File.directory?(file)
101
+ hash.update(file => File.read(file))
102
+ end
103
+ end.each do |filename, contents|
104
+ FileUtils.mkdir_p File.dirname(filename)
65
105
  File.open(filename, "w") do |f|
66
106
  f.puts contents
67
107
  end
@@ -93,6 +133,17 @@ def normalize_space(s)
93
133
  s.gsub(/\n[\n\s]*/, "\n")
94
134
  end
95
135
 
136
+ def capture_stdout
137
+ old_stdout = $stdout.dup
138
+ rd, wr = IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY")
139
+ $stdout = wr
140
+ yield
141
+ wr.close
142
+ rd.read
143
+ ensure
144
+ $stdout = old_stdout
145
+ end
146
+
96
147
  RSpec.configure do |config|
97
148
  config.treat_symbols_as_metadata_keys_with_true_values = true
98
149
  config.color_enabled = true