foreman 0.23.1 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,2 +1,2 @@
1
1
  ticker: ruby ./ticker $PORT
2
- error : ruby ./error
2
+ error: ruby ./error
@@ -3,7 +3,7 @@ Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/
3
3
  app.uid = "<%= user %>"
4
4
  app.gid = "<%= user %>"
5
5
 
6
- <% engine.processes.values.each do |process| %>
6
+ <% engine.processes.each do |process| %>
7
7
  <% 1.upto(concurrency[process.name]) do |num| %>
8
8
  <% port = engine.port_for(process, num, options[:port]) %>
9
9
  app.process("<%= process.name %>-<%=num%>") do |process|
@@ -24,4 +24,4 @@ Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/
24
24
  end
25
25
  <% end %>
26
26
  <% end %>
27
- end
27
+ end
data/lib/foreman/cli.rb CHANGED
@@ -53,9 +53,8 @@ class Foreman::CLI < Thor
53
53
  desc "check", "Validate your application's Procfile"
54
54
 
55
55
  def check
56
- processes = engine.processes_in_order.map { |p| p.first }
57
- error "no processes defined" unless processes.length > 0
58
- display "valid procfile detected (#{processes.join(', ')})"
56
+ error "no processes defined" unless engine.processes.length > 0
57
+ display "valid procfile detected (#{engine.processes.map(&:name).join(', ')})"
59
58
  end
60
59
 
61
60
  private ######################################################################
@@ -1,5 +1,6 @@
1
1
  require "foreman"
2
2
  require "foreman/process"
3
+ require "foreman/procfile"
3
4
  require "foreman/utils"
4
5
  require "pty"
5
6
  require "tempfile"
@@ -19,45 +20,17 @@ class Foreman::Engine
19
20
  COLORS = [ cyan, yellow, green, magenta, red ]
20
21
 
21
22
  def initialize(procfile, options={})
22
- @procfile = read_procfile(procfile)
23
+ @procfile = Foreman::Procfile.new(procfile)
23
24
  @directory = File.expand_path(File.dirname(procfile))
24
25
  @options = options
25
26
  @environment = read_environment_files(options[:env])
26
27
  end
27
28
 
28
- def processes
29
- @processes ||= begin
30
- @order = []
31
- procfile.split("\n").inject({}) do |hash, line|
32
- next hash if line.strip == ""
33
- name, command = line.split(/\s*:\s+/, 2)
34
- unless command
35
- warn_deprecated_procfile!
36
- name, command = line.split(/ +/, 2)
37
- end
38
- process = Foreman::Process.new(name, command)
39
- process.color = next_color
40
- @order << process.name
41
- hash.update(process.name => process)
42
- end
43
- end
44
- end
45
-
46
- def process_order
47
- processes
48
- @order.uniq
49
- end
50
-
51
- def processes_in_order
52
- process_order.map do |name|
53
- [name, processes[name]]
54
- end
55
- end
56
-
57
29
  def start
58
30
  proctitle "ruby: foreman master"
59
31
 
60
- processes_in_order.each do |name, process|
32
+ processes.each do |process|
33
+ process.color = next_color
61
34
  fork process
62
35
  end
63
36
 
@@ -68,8 +41,7 @@ class Foreman::Engine
68
41
  end
69
42
 
70
43
  def execute(name)
71
-
72
- fork processes[name]
44
+ fork procfile[name]
73
45
 
74
46
  trap("TERM") { puts "SIGTERM received"; terminate_gracefully }
75
47
  trap("INT") { puts "SIGINT received"; terminate_gracefully }
@@ -77,9 +49,13 @@ class Foreman::Engine
77
49
  watch_for_termination
78
50
  end
79
51
 
52
+ def processes
53
+ procfile.processes
54
+ end
55
+
80
56
  def port_for(process, num, base_port=nil)
81
57
  base_port ||= 5000
82
- offset = processes_in_order.map { |p| p.first }.index(process.name) * 100
58
+ offset = procfile.process_names.index(process.name) * 100
83
59
  base_port.to_i + offset + num - 1
84
60
  end
85
61
 
@@ -134,6 +110,24 @@ private ######################################################################
134
110
  end
135
111
  end
136
112
 
113
+ def terminate_gracefully
114
+ info "sending SIGTERM to all processes"
115
+ kill_all "SIGTERM"
116
+ Timeout.timeout(3) { Process.waitall }
117
+ rescue Timeout::Error
118
+ info "sending SIGKILL to all processes"
119
+ kill_all "SIGKILL"
120
+ end
121
+
122
+ def watch_for_termination
123
+ pid, status = Process.wait2
124
+ process = running_processes.delete(pid)
125
+ info "process terminated", process
126
+ terminate_gracefully
127
+ kill_all
128
+ rescue Errno::ECHILD
129
+ end
130
+
137
131
  def info(message, process=nil)
138
132
  print process.color if process
139
133
  print "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(process)} | "
@@ -149,7 +143,7 @@ private ######################################################################
149
143
 
150
144
  def longest_process_name
151
145
  @longest_process_name ||= begin
152
- longest = processes.keys.map { |name| name.length }.sort.last
146
+ longest = procfile.process_names.map { |name| name.length }.sort.last
153
147
  longest = 6 if longest < 6 # system
154
148
  longest
155
149
  end
@@ -160,30 +154,10 @@ private ######################################################################
160
154
  name.ljust(longest_process_name + 3) # add 3 for process number padding
161
155
  end
162
156
 
163
- def print_info
164
- info "currently running processes:"
165
- running_processes.each do |pid, process|
166
- info "pid #{pid}", process
167
- end
168
- end
169
-
170
157
  def proctitle(title)
171
158
  $0 = title
172
159
  end
173
160
 
174
- def read_procfile(procfile)
175
- File.read(procfile)
176
- end
177
-
178
- def watch_for_termination
179
- pid, status = Process.wait2
180
- process = running_processes.delete(pid)
181
- info "process terminated", process
182
- terminate_gracefully
183
- kill_all
184
- rescue Errno::ECHILD
185
- end
186
-
187
161
  def running_processes
188
162
  @running_processes ||= {}
189
163
  end
@@ -194,14 +168,6 @@ private ######################################################################
194
168
  @current_color >= COLORS.length ? "" : COLORS[@current_color]
195
169
  end
196
170
 
197
- def warn_deprecated_procfile!
198
- return if @already_warned_deprecated
199
- @already_warned_deprecated = true
200
- puts "!!! This format of Procfile is deprecated, and will not work starting in v0.12"
201
- puts "!!! Use a colon to separate the process name from the command"
202
- puts "!!! e.g. web: thin start"
203
- end
204
-
205
171
  def read_environment_files(filenames)
206
172
  environment = {}
207
173
 
@@ -225,13 +191,4 @@ private ######################################################################
225
191
  end
226
192
  end
227
193
 
228
- def terminate_gracefully
229
- info "sending SIGTERM to all processes"
230
- kill_all "SIGTERM"
231
- Timeout.timeout(3) { Process.waitall }
232
- rescue Timeout::Error
233
- info "sending SIGKILL to all processes"
234
- kill_all "SIGKILL"
235
- end
236
-
237
194
  end
@@ -26,7 +26,7 @@ class Foreman::Export::Upstart < Foreman::Export::Base
26
26
 
27
27
  process_template = export_template("upstart", "process.conf.erb", template_root)
28
28
 
29
- engine.processes.values.each do |process|
29
+ engine.processes.each do |process|
30
30
  process_master_template = export_template("upstart", "process_master.conf.erb", template_root)
31
31
  process_master_config = ERB.new(process_master_template).result(binding)
32
32
  write_file "#{location}/#{app}-#{process.name}.conf", process_master_config
@@ -0,0 +1,37 @@
1
+ require "foreman"
2
+
3
+ # A valid Procfile entry is captured by this regex.
4
+ # All other lines are ignored.
5
+ #
6
+ # /^([A-Za-z0-9_]+):\s*(.+)$/
7
+ #
8
+ # $1 = name
9
+ # $2 = command
10
+ #
11
+ class Foreman::Procfile
12
+
13
+ attr_reader :processes
14
+
15
+ def initialize(filename)
16
+ @processes = parse_procfile(filename)
17
+ end
18
+
19
+ def process_names
20
+ processes.map(&:name)
21
+ end
22
+
23
+ def [](name)
24
+ processes.detect { |process| process.name == name }
25
+ end
26
+
27
+ private
28
+
29
+ def parse_procfile(filename)
30
+ File.read(filename).split("\n").map do |line|
31
+ if line =~ /^([A-Za-z0-9_]+):\s*(.+)$/
32
+ Foreman::Process.new($1, $2)
33
+ end
34
+ end.compact
35
+ end
36
+
37
+ end
@@ -1,5 +1,5 @@
1
1
  module Foreman
2
2
 
3
- VERSION = "0.23.1"
3
+ VERSION = "0.24.0"
4
4
 
5
5
  end
@@ -15,21 +15,8 @@ describe "Foreman::Engine" do
15
15
  before { write_procfile }
16
16
 
17
17
  it "reads the processes" do
18
- subject.processes["alpha"].command.should == "./alpha"
19
- subject.processes["bravo"].command.should == "./bravo"
20
- end
21
- end
22
-
23
- describe "with a deprecated Procfile" do
24
- before do
25
- File.open("Procfile", "w") do |file|
26
- file.puts "name command"
27
- end
28
- end
29
-
30
- it "should print a deprecation warning" do
31
- mock(subject).warn_deprecated_procfile!
32
- subject.processes.length.should == 1
18
+ subject.procfile["alpha"].command.should == "./alpha"
19
+ subject.procfile["bravo"].command.should == "./bravo"
33
20
  end
34
21
  end
35
22
  end
@@ -37,8 +24,8 @@ describe "Foreman::Engine" do
37
24
  describe "start" do
38
25
  it "forks the processes" do
39
26
  write_procfile
40
- mock(subject).fork(subject.processes["alpha"])
41
- mock(subject).fork(subject.processes["bravo"])
27
+ mock(subject).fork(subject.procfile["alpha"])
28
+ mock(subject).fork(subject.procfile["bravo"])
42
29
  mock(subject).watch_for_termination
43
30
  subject.start
44
31
  end
@@ -46,9 +33,9 @@ describe "Foreman::Engine" do
46
33
  it "handles concurrency" do
47
34
  write_procfile
48
35
  engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2")
49
- mock(engine).fork_individual(engine.processes["alpha"], 1, 5000)
50
- mock(engine).fork_individual(engine.processes["alpha"], 2, 5001)
51
- mock(engine).fork_individual(engine.processes["bravo"], 1, 5100)
36
+ mock(engine).fork_individual(engine.procfile["alpha"], 1, 5000)
37
+ mock(engine).fork_individual(engine.procfile["alpha"], 2, 5001)
38
+ mock(engine).fork_individual(engine.procfile["bravo"], 1, 5100)
52
39
  mock(engine).watch_for_termination
53
40
  engine.start
54
41
  end
@@ -57,14 +44,13 @@ describe "Foreman::Engine" do
57
44
  describe "execute" do
58
45
  it "runs the processes" do
59
46
  write_procfile
60
- mock(subject).fork(subject.processes["alpha"])
47
+ mock(subject).fork(subject.procfile["alpha"])
61
48
  mock(subject).watch_for_termination
62
49
  subject.execute("alpha")
63
50
  end
64
51
  end
65
52
 
66
53
  describe "environment" do
67
-
68
54
  before(:each) do
69
55
  write_procfile
70
56
  stub(Process).fork
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.1
4
+ version: 0.24.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2011-10-04 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: term-ansicolor
16
- requirement: &70129124490300 !ruby/object:Gem::Requirement
16
+ requirement: &70155363724260 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.0.5
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70129124490300
24
+ version_requirements: *70155363724260
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: thor
27
- requirement: &70129124481440 !ruby/object:Gem::Requirement
27
+ requirement: &70155363722660 !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: *70129124481440
35
+ version_requirements: *70155363722660
36
36
  description: Process manager for applications with multiple components
37
37
  email: ddollar@gmail.com
38
38
  executables:
@@ -59,6 +59,7 @@ files:
59
59
  - lib/foreman/export/upstart.rb
60
60
  - lib/foreman/export.rb
61
61
  - lib/foreman/process.rb
62
+ - lib/foreman/procfile.rb
62
63
  - lib/foreman/utils.rb
63
64
  - lib/foreman/version.rb
64
65
  - lib/foreman.rb
@@ -93,7 +94,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
93
94
  version: '0'
94
95
  segments:
95
96
  - 0
96
- hash: 4036267716300472320
97
+ hash: 3975386254476166563
97
98
  required_rubygems_version: !ruby/object:Gem::Requirement
98
99
  none: false
99
100
  requirements:
@@ -102,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
102
103
  version: '0'
103
104
  segments:
104
105
  - 0
105
- hash: 4036267716300472320
106
+ hash: 3975386254476166563
106
107
  requirements: []
107
108
  rubyforge_project:
108
109
  rubygems_version: 1.8.10