Compare commits

..
2 Commits
Author SHA1 Message Date
David Dollar d0f5b2412c 0.7.4 2010-09-17 09:30:20 -04:00
David Dollar 15ab54bc18 include files from export in the gem 2010-09-17 09:30:09 -04:00
17 changed files with 45 additions and 74 deletions
+2 -3
View File
@@ -3,14 +3,13 @@ source "http://rubygems.org"
group :development do group :development do
gem 'parka' gem 'parka'
gem 'rake' gem 'rake'
gem 'ronn'
end end
group :test do group :test do
gem 'fakefs', '~> 0.2.1' gem 'fakefs', '~> 0.2.1'
gem 'rcov', '~> 0.9.8' gem 'rcov', '~> 0.9.8'
gem 'rr', '~> 1.0.2' gem 'rr', '~> 0.10.11'
gem 'rspec', '~> 2.0.0' gem 'rspec', '~> 2.0.0.beta.19'
end end
gem 'term-ansicolor', '~> 1.0.5' gem 'term-ansicolor', '~> 1.0.5'
+3 -11
View File
@@ -3,22 +3,15 @@ GEM
specs: specs:
diff-lcs (1.1.2) diff-lcs (1.1.2)
fakefs (0.2.1) fakefs (0.2.1)
hpricot (0.8.2)
mime-types (1.16) mime-types (1.16)
mustache (0.11.2)
parka (0.3.1) parka (0.3.1)
rest-client rest-client
thor thor
rake (0.8.7) rake (0.8.7)
rcov (0.9.8) rcov (0.9.8)
rdiscount (1.6.5)
rest-client (1.6.0) rest-client (1.6.0)
mime-types (>= 1.16) mime-types (>= 1.16)
ronn (0.7.3) rr (0.10.11)
hpricot (>= 0.8.2)
mustache (>= 0.7.0)
rdiscount (>= 1.5.8)
rr (1.0.2)
rspec (2.0.0.beta.19) rspec (2.0.0.beta.19)
rspec-core (= 2.0.0.beta.19) rspec-core (= 2.0.0.beta.19)
rspec-expectations (= 2.0.0.beta.19) rspec-expectations (= 2.0.0.beta.19)
@@ -38,8 +31,7 @@ DEPENDENCIES
parka parka
rake rake
rcov (~> 0.9.8) rcov (~> 0.9.8)
ronn rr (~> 0.10.11)
rr (~> 1.0.2) rspec (~> 2.0.0.beta.19)
rspec (~> 2.0.0)
term-ansicolor (~> 1.0.5) term-ansicolor (~> 1.0.5)
thor (~> 0.13.6) thor (~> 0.13.6)
-4
View File
@@ -1,4 +0,0 @@
tick
tick
./never_die:6:in `sleep': Interrupt
from ./never_die:6
@@ -3,4 +3,4 @@ stop on stopping <%= app %>-<%= process.name %>
respawn respawn
chdir <%= engine.directory %> chdir <%= engine.directory %>
exec su - <%= user %> -c 'export PORT=<%= port %>; <%= process.command %> >> <%= log_root %>/<%=process.name%>-<%=num%>.log 2>&1' exec su <%= user %> -c "PORT=<%= port %> <%= process.command %> >> <%= log_root %>/<%=process.name%>-<%=num%>.log 2>&1"
+1
View File
@@ -9,4 +9,5 @@ Parka::Specification.new do |gem|
gem.executables = "foreman" gem.executables = "foreman"
gem.files << "man/foreman.1" gem.files << "man/foreman.1"
gem.files << Dir["export/**/*"]
end end
+1 -1
View File
@@ -1,6 +1,6 @@
module Foreman module Foreman
VERSION = "0.9.2" VERSION = "0.7.4"
class AppDoesNotExist < Exception; end class AppDoesNotExist < Exception; end
+3 -3
View File
@@ -5,7 +5,7 @@ require "thor"
class Foreman::CLI < Thor class Foreman::CLI < Thor
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile" class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: ./Procfile"
desc "start [PROCESS]", "Start the application, or a specific process" desc "start [PROCESS]", "Start the application, or a specific process"
@@ -50,7 +50,7 @@ class Foreman::CLI < Thor
private ###################################################################### private ######################################################################
def check_procfile! def check_procfile!
error("#{procfile} does not exist.") unless File.exist?(procfile) error("Procfile does not exist.") unless File.exist?(procfile)
end end
def engine def engine
@@ -58,7 +58,7 @@ private ######################################################################
end end
def procfile def procfile
options[:procfile] || "Procfile" options[:procfile] || "./Procfile"
end end
private ###################################################################### private ######################################################################
+18 -35
View File
@@ -22,38 +22,25 @@ class Foreman::Engine
def processes def processes
@processes ||= begin @processes ||= begin
@order = []
procfile.split("\n").inject({}) do |hash, line| procfile.split("\n").inject({}) do |hash, line|
next if line.strip == "" next if line.strip == ""
name, command = line.split(" ", 2) name, command = line.split(" ", 2)
process = Foreman::Process.new(name, command) process = Foreman::Process.new(name, command)
process.color = next_color process.color = next_color
@order << process.name
hash.update(process.name => process) hash.update(process.name => process)
end end
end 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(options={}) def start(options={})
proctitle "ruby: foreman master" proctitle "ruby: foreman master"
processes_in_order.each do |name, process| processes.each do |name, process|
fork process, options fork process, options
end end
trap("TERM") { puts "SIGTERM received"; kill_all("TERM") } trap("TERM") { kill_and_exit("TERM") }
trap("INT") { puts "SIGINT received"; kill_all("INT") } trap("INT") { kill_and_exit("INT") }
watch_for_termination watch_for_termination
end end
@@ -61,15 +48,15 @@ class Foreman::Engine
def execute(name, options={}) def execute(name, options={})
fork processes[name], options fork processes[name], options
trap("TERM") { puts "SIGTERM received"; kill_all("TERM") } trap("TERM") { kill_and_exit("TERM") }
trap("INT") { puts "SIGINT received"; kill_all("INT") } trap("INT") { kill_and_exit("INT") }
watch_for_termination watch_for_termination
end end
def port_for(process, num, base_port=nil) def port_for(process, num, base_port=nil)
base_port ||= 5000 base_port ||= 5000
offset = processes_in_order.map { |p| p.first }.index(process.name) * 100 offset = processes.keys.sort.index(process.name) * 100
base_port.to_i + offset + num - 1 base_port.to_i + offset + num - 1
end end
@@ -79,13 +66,12 @@ private ######################################################################
concurrency = Foreman::Utils.parse_concurrency(options[:concurrency]) concurrency = Foreman::Utils.parse_concurrency(options[:concurrency])
1.upto(concurrency[process.name]) do |num| 1.upto(concurrency[process.name]) do |num|
fork_individual(process, num, port_for(process, num, options[:port])) fork_individual(process, port_for(process, num, options[:port]))
end end
end end
def fork_individual(process, num, port) def fork_individual(process, port)
ENV["PORT"] = port.to_s ENV["PORT"] = port.to_s
ENV["PS"] = "#{process.name}.#{num}"
pid = Process.fork do pid = Process.fork do
run(process) run(process)
@@ -98,31 +84,29 @@ private ######################################################################
def run(process, log_to_file=true) def run(process, log_to_file=true)
proctitle "ruby: foreman #{process.name}" proctitle "ruby: foreman #{process.name}"
begin Dir.chdir directory do
Dir.chdir directory do FileUtils.mkdir_p "log"
FileUtils.mkdir_p "log" command = process.command
command = process.command
begin
PTY.spawn("#{process.command} 2>&1") do |stdin, stdout, pid| PTY.spawn("#{process.command} 2>&1") do |stdin, stdout, pid|
until stdin.eof? until stdin.eof?
info stdin.gets, process info stdin.gets, process
end end
end end
end rescue PTY::ChildExited, Interrupt
rescue PTY::ChildExited, Interrupt
begin
info "process exiting", process info "process exiting", process
rescue Interrupt
end end
end end
end end
def kill_all(signal="TERM") def kill_and_exit(signal="TERM")
info "terminating" info "terminating"
running_processes.each do |pid, process| running_processes.each do |pid, process|
info "killing #{process.name} in pid #{pid}" info "killing #{process.name} in pid #{pid}"
Process.kill(signal, pid) Process.kill(signal, pid)
end end
exit 0
end end
def info(message, process=nil) def info(message, process=nil)
@@ -142,8 +126,8 @@ private ######################################################################
end end
def pad_process_name(process) def pad_process_name(process)
name = process ? "#{ENV["PS"]}" : "system" name = process ? "#{process.name}:#{ENV["PORT"]}" : "system"
name.ljust(longest_process_name + 3) # add 3 for process number padding name.ljust(longest_process_name + 6) # add 6 for port padding
end end
def print_info def print_info
@@ -165,8 +149,7 @@ private ######################################################################
pid, status = Process.wait2 pid, status = Process.wait2
process = running_processes.delete(pid) process = running_processes.delete(pid)
info "process terminated", process info "process terminated", process
kill_all kill_and_exit
Process.waitall
end end
def running_processes def running_processes
+1 -1
View File
@@ -24,7 +24,7 @@ private ######################################################################
end end
def export_template(name) def export_template(name)
File.read(File.expand_path("../../../../data/export/#{name}", __FILE__)) File.read(File.expand_path("../../../../export/#{name}", __FILE__))
end end
def write_file(filename, contents) def write_file(filename, contents)
+2 -2
View File
@@ -27,8 +27,8 @@ class Foreman::Export::Inittab < Foreman::Export::Base
inittab = inittab.join("\n") + "\n" inittab = inittab.join("\n") + "\n"
if fname if fname
FileUtils.mkdir_p(log_root) rescue error "could not create #{log_root}" FileUtils.mkdir_p(log_root)
FileUtils.chown(user, nil, log_root) rescue error "could not chown #{log_root} to #{user}" FileUtils.chown(user, nil, log_root)
write_file(fname, inittab) write_file(fname, inittab)
else else
puts inittab puts inittab
+10 -10
View File
@@ -1,4 +1,4 @@
foreman(1) -- manage Psfile-based applications foreman(1) -- manage Procfile-based applications
================================================ ================================================
## SYNOPSIS ## SYNOPSIS
@@ -8,8 +8,8 @@ foreman(1) -- manage Psfile-based applications
## DESCRIPTION ## DESCRIPTION
**Foreman** is a manager for Psfile-based applications. Its aim is to **Foreman** is a manager for Procfile-based applications. Its aim is to
abstract away the details of the Psfile format, and allow you to either run abstract away the details of the Procfile format, and allow you to either run
your application directly or export it to some other process management your application directly or export it to some other process management
format. format.
@@ -18,7 +18,7 @@ format.
`foreman start` is used to run your application directly from the command line. `foreman start` is used to run your application directly from the command line.
If no additional parameters are passed, foreman will run one instance of each If no additional parameters are passed, foreman will run one instance of each
type of process defined in your Psfile. type of process defined in your Procfile.
If a parameter is passed, foreman will run one instance of the specified If a parameter is passed, foreman will run one instance of the specified
application type. application type.
@@ -66,8 +66,8 @@ The following options control how the application is run:
These options control all modes of foreman's operation. These options control all modes of foreman's operation.
* `-f`, `--psfile`: * `-f`, `--procfile`:
Specify an alternate location for the application's Psfile. This file's Specify an alternate location for the application's Procfile. This file's
containing directory will be assumed to be the root directory of the containing directory will be assumed to be the root directory of the
application. application.
@@ -99,9 +99,9 @@ will be structured to make the following commands valid:
`restart appname-processname-3` `restart appname-processname-3`
## PSFILE ## PROCFILE
A Psfile should contain both a name for the process and the command used A Procfile should contain both a name for the process and the command used
to run it. to run it.
web bundle exec thin start web bundle exec thin start
@@ -117,9 +117,9 @@ Export the application in upstart format:
$ foreman export upstart /etc/init $ foreman export upstart /etc/init
Run one process type from the application defined in a specific Psfile: Run one process type from the application defined in a specific Procfile:
$ foreman start alpha -p ~/myapp/Psfile $ foreman start alpha -p ~/app/Procfile
## COPYRIGHT ## COPYRIGHT
+3 -3
View File
@@ -31,9 +31,9 @@ describe "Foreman::Engine" do
it "handles concurrency" do it "handles concurrency" do
write_procfile write_procfile
mock(subject).fork_individual(subject.processes["alpha"], 1, 5000) mock(subject).fork_individual(subject.processes["alpha"], 5000)
mock(subject).fork_individual(subject.processes["alpha"], 2, 5001) mock(subject).fork_individual(subject.processes["alpha"], 5001)
mock(subject).fork_individual(subject.processes["bravo"], 1, 5100) mock(subject).fork_individual(subject.processes["bravo"], 5100)
mock(subject).watch_for_termination mock(subject).watch_for_termination
subject.start(:concurrency => "alpha=2") subject.start(:concurrency => "alpha=2")
end end