Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

define procfile regex, refactoring

  • Loading branch information...
commit d26ca669a15e9a853236082fd76d9e4018d42c1d 1 parent a3e758a
David Dollar ddollar authored
2  data/example/Procfile
View
@@ -1,2 +1,2 @@
ticker: ruby ./ticker $PORT
-error : ruby ./error
+error: ruby ./error
4 data/export/bluepill/master.pill.erb
View
@@ -3,7 +3,7 @@ Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/
app.uid = "<%= user %>"
app.gid = "<%= user %>"
-<% engine.processes.values.each do |process| %>
+<% engine.processes.each do |process| %>
<% 1.upto(concurrency[process.name]) do |num| %>
<% port = engine.port_for(process, num, options[:port]) %>
app.process("<%= process.name %>-<%=num%>") do |process|
@@ -24,4 +24,4 @@ Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/
end
<% end %>
<% end %>
-end
+end
5 lib/foreman/cli.rb
View
@@ -53,9 +53,8 @@ def export(format, location=nil)
desc "check", "Validate your application's Procfile"
def check
- processes = engine.processes_in_order.map { |p| p.first }
- error "no processes defined" unless processes.length > 0
- display "valid procfile detected (#{processes.join(', ')})"
+ error "no processes defined" unless engine.processes.length > 0
+ display "valid procfile detected (#{engine.processes.map(&:name).join(', ')})"
end
private ######################################################################
101 lib/foreman/engine.rb
View
@@ -1,5 +1,6 @@
require "foreman"
require "foreman/process"
+require "foreman/procfile"
require "foreman/utils"
require "pty"
require "tempfile"
@@ -19,45 +20,17 @@ class Foreman::Engine
COLORS = [ cyan, yellow, green, magenta, red ]
def initialize(procfile, options={})
- @procfile = read_procfile(procfile)
+ @procfile = Foreman::Procfile.new(procfile)
@directory = File.expand_path(File.dirname(procfile))
@options = options
@environment = read_environment_files(options[:env])
end
- def processes
- @processes ||= begin
- @order = []
- procfile.split("\n").inject({}) do |hash, line|
- next hash if line.strip == ""
- name, command = line.split(/\s*:\s+/, 2)
- unless command
- warn_deprecated_procfile!
- name, command = line.split(/ +/, 2)
- end
- process = Foreman::Process.new(name, command)
- process.color = next_color
- @order << process.name
- hash.update(process.name => process)
- end
- end
- end
-
- def process_order
- processes
- @order.uniq
- end
-
- def processes_in_order
- process_order.map do |name|
- [name, processes[name]]
- end
- end
-
def start
proctitle "ruby: foreman master"
- processes_in_order.each do |name, process|
+ processes.each do |process|
+ process.color = next_color
fork process
end
@@ -68,8 +41,7 @@ def start
end
def execute(name)
-
- fork processes[name]
+ fork procfile[name]
trap("TERM") { puts "SIGTERM received"; terminate_gracefully }
trap("INT") { puts "SIGINT received"; terminate_gracefully }
@@ -77,9 +49,13 @@ def execute(name)
watch_for_termination
end
+ def processes
+ procfile.processes
+ end
+
def port_for(process, num, base_port=nil)
base_port ||= 5000
- offset = processes_in_order.map { |p| p.first }.index(process.name) * 100
+ offset = procfile.process_names.index(process.name) * 100
base_port.to_i + offset + num - 1
end
@@ -134,6 +110,24 @@ def kill_all(signal="SIGTERM")
end
end
+ def terminate_gracefully
+ info "sending SIGTERM to all processes"
+ kill_all "SIGTERM"
+ Timeout.timeout(3) { Process.waitall }
+ rescue Timeout::Error
+ info "sending SIGKILL to all processes"
+ kill_all "SIGKILL"
+ end
+
+ def watch_for_termination
+ pid, status = Process.wait2
+ process = running_processes.delete(pid)
+ info "process terminated", process
+ terminate_gracefully
+ kill_all
+ rescue Errno::ECHILD
+ end
+
def info(message, process=nil)
print process.color if process
print "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(process)} | "
@@ -149,7 +143,7 @@ def error(message)
def longest_process_name
@longest_process_name ||= begin
- longest = processes.keys.map { |name| name.length }.sort.last
+ longest = procfile.process_names.map { |name| name.length }.sort.last
longest = 6 if longest < 6 # system
longest
end
@@ -160,30 +154,10 @@ def pad_process_name(process)
name.ljust(longest_process_name + 3) # add 3 for process number padding
end
- def print_info
- info "currently running processes:"
- running_processes.each do |pid, process|
- info "pid #{pid}", process
- end
- end
-
def proctitle(title)
$0 = title
end
- def read_procfile(procfile)
- File.read(procfile)
- end
-
- def watch_for_termination
- pid, status = Process.wait2
- process = running_processes.delete(pid)
- info "process terminated", process
- terminate_gracefully
- kill_all
- rescue Errno::ECHILD
- end
-
def running_processes
@running_processes ||= {}
end
@@ -194,14 +168,6 @@ def next_color
@current_color >= COLORS.length ? "" : COLORS[@current_color]
end
- def warn_deprecated_procfile!
- return if @already_warned_deprecated
- @already_warned_deprecated = true
- puts "!!! This format of Procfile is deprecated, and will not work starting in v0.12"
- puts "!!! Use a colon to separate the process name from the command"
- puts "!!! e.g. web: thin start"
- end
-
def read_environment_files(filenames)
environment = {}
@@ -225,13 +191,4 @@ def read_environment(filename)
end
end
- def terminate_gracefully
- info "sending SIGTERM to all processes"
- kill_all "SIGTERM"
- Timeout.timeout(3) { Process.waitall }
- rescue Timeout::Error
- info "sending SIGKILL to all processes"
- kill_all "SIGKILL"
- end
-
end
2  lib/foreman/export/upstart.rb
View
@@ -26,7 +26,7 @@ def export(location, options={})
process_template = export_template("upstart", "process.conf.erb", template_root)
- engine.processes.values.each do |process|
+ engine.processes.each do |process|
process_master_template = export_template("upstart", "process_master.conf.erb", template_root)
process_master_config = ERB.new(process_master_template).result(binding)
write_file "#{location}/#{app}-#{process.name}.conf", process_master_config
37 lib/foreman/procfile.rb
View
@@ -0,0 +1,37 @@
+require "foreman"
+
+# A valid Procfile entry is captured by this regex.
+# All other lines are ignored.
+#
+# /^([A-Za-z0-9_]+):\s*(.+)$/
+#
+# $1 = name
+# $2 = command
+#
+class Foreman::Procfile
+
+ attr_reader :processes
+
+ def initialize(filename)
+ @processes = parse_procfile(filename)
+ end
+
+ def process_names
+ processes.map(&:name)
+ end
+
+ def [](name)
+ processes.detect { |process| process.name == name }
+ end
+
+private
+
+ def parse_procfile(filename)
+ File.read(filename).split("\n").map do |line|
+ if line =~ /^([A-Za-z0-9_]+):\s*(.+)$/
+ Foreman::Process.new($1, $2)
+ end
+ end.compact
+ end
+
+end
30 spec/foreman/engine_spec.rb
View
@@ -15,21 +15,8 @@
before { write_procfile }
it "reads the processes" do
- subject.processes["alpha"].command.should == "./alpha"
- subject.processes["bravo"].command.should == "./bravo"
- end
- end
-
- describe "with a deprecated Procfile" do
- before do
- File.open("Procfile", "w") do |file|
- file.puts "name command"
- end
- end
-
- it "should print a deprecation warning" do
- mock(subject).warn_deprecated_procfile!
- subject.processes.length.should == 1
+ subject.procfile["alpha"].command.should == "./alpha"
+ subject.procfile["bravo"].command.should == "./bravo"
end
end
end
@@ -37,8 +24,8 @@
describe "start" do
it "forks the processes" do
write_procfile
- mock(subject).fork(subject.processes["alpha"])
- mock(subject).fork(subject.processes["bravo"])
+ mock(subject).fork(subject.procfile["alpha"])
+ mock(subject).fork(subject.procfile["bravo"])
mock(subject).watch_for_termination
subject.start
end
@@ -46,9 +33,9 @@
it "handles concurrency" do
write_procfile
engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2")
- mock(engine).fork_individual(engine.processes["alpha"], 1, 5000)
- mock(engine).fork_individual(engine.processes["alpha"], 2, 5001)
- mock(engine).fork_individual(engine.processes["bravo"], 1, 5100)
+ mock(engine).fork_individual(engine.procfile["alpha"], 1, 5000)
+ mock(engine).fork_individual(engine.procfile["alpha"], 2, 5001)
+ mock(engine).fork_individual(engine.procfile["bravo"], 1, 5100)
mock(engine).watch_for_termination
engine.start
end
@@ -57,14 +44,13 @@
describe "execute" do
it "runs the processes" do
write_procfile
- mock(subject).fork(subject.processes["alpha"])
+ mock(subject).fork(subject.procfile["alpha"])
mock(subject).watch_for_termination
subject.execute("alpha")
end
end
describe "environment" do
-
before(:each) do
write_procfile
stub(Process).fork
Please sign in to comment.
Something went wrong with that request. Please try again.