Compare commits

...
13 Commits
Author SHA1 Message Date
David Dollar be6d1b805c Regenerated gemspec for version 0.4.2 2010-06-23 18:54:31 -04:00
David Dollar 58e936a7e2 0.4.2 2010-06-23 18:54:29 -04:00
David Dollar d4f29d6909 back to master after done 2010-06-23 18:54:17 -04:00
David Dollar 571163795f task to build pages 2010-06-23 18:53:20 -04:00
David Dollar 845ee9ef38 dont store man in repo 2010-06-23 18:50:36 -04:00
David Dollar d5d774c9c2 Regenerated gemspec for version 0.4.1 2010-06-23 18:20:00 -04:00
David Dollar b77952ff7f updating man pages 2010-06-23 18:19:59 -04:00
David Dollar 3495fa2fea 0.4.1 2010-06-23 18:19:57 -04:00
David Dollar 4741dceeb0 build man on release 2010-06-23 18:19:50 -04:00
David Dollar dc1cb08d27 updating man pages 2010-06-23 18:19:38 -04:00
David Dollar b51e8046ce 0.4.0 2010-06-23 18:19:23 -04:00
David Dollar 922eb7438e add manpage 2010-06-23 18:17:55 -04:00
David Dollar 6811a8d96a massive reworking of command line interface 2010-06-23 17:51:12 -04:00
13 changed files with 243 additions and 124 deletions
+3
View File
@@ -1,3 +1,6 @@
coverage coverage
example/log/* example/log/*
man/*.?
man/*.html
man/*.markdown
pkg pkg
+21
View File
@@ -6,6 +6,7 @@ $:.unshift File.expand_path("../lib", __FILE__)
require "foreman" require "foreman"
task :default => :spec task :default => :spec
task :release => :man
desc "Run all specs" desc "Run all specs"
Rspec::Core::RakeTask.new(:spec) do |t| Rspec::Core::RakeTask.new(:spec) do |t|
@@ -23,6 +24,26 @@ Rspec::Core::RakeTask.new("rcov:build") do |t|
t.rcov_opts = [ "--exclude", Gem.default_dir , "--exclude", "spec" ] t.rcov_opts = [ "--exclude", Gem.default_dir , "--exclude", "spec" ]
end end
desc 'Build the manual'
task :man do
ENV['RONN_MANUAL'] = "Foreman Manual"
ENV['RONN_ORGANIZATION'] = "Foreman #{Foreman::VERSION}"
sh "ronn -w -s toc -r5 --markdown man/*.ronn"
end
task :pages => :man do
sh %{
cp man/foreman.1.html /tmp/foreman.1.html
git checkout gh-pages
rm ./index.html
cp /tmp/foreman.1.html ./index.html
git add -u index.html
git commit -m "rebuilding man page"
git push origin -f gh-pages
git checkout master
}
end
###################################################### ######################################################
begin begin
+13
View File
@@ -0,0 +1,13 @@
pre-start script
bash << "EOF"
mkdir -p /var/log/<%= app %>
<% engine.processes.keys.sort.each do |process| %>
<% 1.upto(concurrency[process]).each do |num| %>
start <%=app%>-<%=process%>-<%=num%>
<% end %>
<% end %>
EOF
end script
+5
View File
@@ -0,0 +1,5 @@
stop on stopping <%= app %>
respawn
chdir <%= engine.directory %>
exec <%= process.command %> >> /var/log/<%=app%>/<%=process.name%>-<%=num%>.log 2>&1
+3 -2
View File
@@ -5,11 +5,11 @@
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = %q{foreman} s.name = %q{foreman}
s.version = "0.3.2" s.version = "0.4.2"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["David Dollar"] s.authors = ["David Dollar"]
s.date = %q{2010-06-22} s.date = %q{2010-06-23}
s.default_executable = %q{foreman} s.default_executable = %q{foreman}
s.description = %q{Process manager for applications with multiple components} s.description = %q{Process manager for applications with multiple components}
s.email = %q{ddollar@gmail.com} s.email = %q{ddollar@gmail.com}
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
"lib/foreman/configuration.rb", "lib/foreman/configuration.rb",
"lib/foreman/engine.rb", "lib/foreman/engine.rb",
"lib/foreman/export.rb", "lib/foreman/export.rb",
"lib/foreman/export/base.rb",
"lib/foreman/export/upstart.rb", "lib/foreman/export/upstart.rb",
"lib/foreman/process.rb", "lib/foreman/process.rb",
"spec/foreman/cli_spec.rb", "spec/foreman/cli_spec.rb",
+1 -1
View File
@@ -1,6 +1,6 @@
module Foreman module Foreman
VERSION = "0.3.2" VERSION = "0.4.2"
class AppDoesNotExist < Exception; end class AppDoesNotExist < Exception; end
+38 -26
View File
@@ -6,46 +6,58 @@ require "thor"
class Foreman::CLI < Thor class Foreman::CLI < Thor
desc "start [PROCFILE]", "Run the app described in PROCFILE" class_option :procfile, :type => :string, :aliases => "-p", :desc => "Default: ./Procfile"
def start(procfile="Procfile") desc "start [PROCESS]", "Start the application, or a specific process"
error "#{procfile} does not exist." unless procfile_exists?(procfile)
Foreman::Engine.new(procfile).start method_option :screen, :type => :boolean, :aliases => "-s"
def start(process=nil)
check_procfile!
if process
engine.execute(process)
elsif options[:screen]
engine.screen
else
engine.start
end
end end
desc "execute PROCESS [PROCFILE]", "Run an instance of the specified process from PROCFILE" desc "export FORMAT LOCATION", "Export the application to another process management format"
def execute(process, procfile="Procfile") method_option :app, :type => :string, :aliases => "-a"
error "#{procfile} does not exist." unless procfile_exists?(procfile) method_option :concurrency, :type => :string, :aliases => "-c",
Foreman::Engine.new(procfile).execute(process) :banner => '"alpha=5,bar=3"'
end
desc "screen [PROCFILE]", "Run the app described in PROCFILE as screen windows" def export(format, location=nil)
check_procfile!
def screen(procfile="Procfile")
error "#{procfile} does not exist." unless procfile_exists?(procfile)
Foreman::Engine.new(procfile).screen
end
desc "export APP [PROCFILE] [FORMAT]", "Export the app described in PROCFILE as APP to another FORMAT"
def export(app, procfile="Procfile", format="upstart")
error "#{procfile} does not exist." unless procfile_exists?(procfile)
formatter = case format formatter = case format
when "upstart" then Foreman::Export::Upstart when "upstart" then Foreman::Export::Upstart
else error "Unknown export format: #{format}." else error "Unknown export format: #{format}."
end end
formatter.new(Foreman::Engine.new(procfile)).export(app) formatter.new(engine).export(location,
:name => options[:app],
:concurrency => options[:concurrency]
)
rescue Foreman::Export::Exception => ex
error ex.message
end end
desc "scale APP PROCESS AMOUNT", "Change the concurrency of a given process type" private ######################################################################
def scale(app, process, amount) def check_procfile!
config = Foreman::Configuration.new(app) error("Procfile does not exist.") unless File.exist?(procfile)
error "No such process: #{process}." unless config.processes[process] end
config.scale(process, amount)
def engine
@engine ||= Foreman::Engine.new(procfile)
end
def procfile
options[:procfile] || "./Procfile"
end end
private ###################################################################### private ######################################################################
+2 -2
View File
@@ -83,8 +83,8 @@ private ######################################################################
info stdin.gets, process info stdin.gets, process
end end
end end
rescue PTY::ChildExited rescue PTY::ChildExited, Interrupt
# exited info "process exiting", process
end end
end end
end end
+1
View File
@@ -1,6 +1,7 @@
require "foreman" require "foreman"
module Foreman::Export module Foreman::Export
class Exception < ::Exception; end
end end
require "foreman/export/upstart" require "foreman/export/upstart"
+48
View File
@@ -0,0 +1,48 @@
require "foreman/configuration"
require "foreman/export"
class Foreman::Export::Base
attr_reader :engine
def initialize(engine)
@engine = engine
end
def export
raise "export method must be overridden"
end
private ######################################################################
def error(message)
raise Foreman::Export::Exception.new(message)
end
def say(message)
puts "[foreman export] %s" % message
end
def export_template(name)
File.read(File.expand_path("../../../../export/#{name}", __FILE__))
end
def parse_concurrency(concurrency)
@concurrency ||= begin
pairs = concurrency.to_s.gsub(/\s/, "").split(",")
pairs.inject(Hash.new(1)) do |hash, pair|
process, amount = pair.split("=")
hash.update(process => amount.to_i)
end
end
end
def write_file(filename, contents)
say "writing: #{filename}"
File.open(filename, "w") do |file|
file.puts contents
end
end
end
+28 -45
View File
@@ -1,51 +1,42 @@
require "erb"
require "foreman/configuration" require "foreman/configuration"
require "foreman/export" require "foreman/export/base"
class Foreman::Export::Upstart class Foreman::Export::Upstart < Foreman::Export::Base
attr_reader :engine def export(location, options={})
error("Must specify a location") unless location
def initialize(engine) FileUtils.mkdir_p location
@engine = engine
app = options[:app] || File.basename(engine.directory)
Dir["#{location}/#{app}*.conf"].each do |file|
say "cleaning up: #{file}"
FileUtils.rm(file)
end end
def export(app) concurrency = parse_concurrency(options[:concurrency])
FileUtils.mkdir_p "/etc/foreman"
FileUtils.mkdir_p "/etc/init"
config = Foreman::Configuration.new(app) master_template = export_template("upstart/master.conf.erb")
master_config = ERB.new(master_template).result(binding)
write_file "#{location}/#{app}.conf", master_config
write_file "/etc/init/#{app}.conf", <<-UPSTART_MASTER process_template = export_template("upstart/process.conf.erb")
pre-start script
bash << "EOF"
mkdir -p /var/log/#{app}
if [ -f /etc/foreman/#{app}.conf ]; then
source /etc/foreman/#{app}.conf
fi
for process in $( echo "$#{app}_processes" ); do
process_count_config="#{app}_$process"
process_count=${!process_count_config}
for ((i=1; i<=${process_count:=1}; i+=1)); do
start #{app}-$process NUM=$i
done
done
EOF
end script
UPSTART_MASTER
engine.processes.values.each do |process| engine.processes.values.each do |process|
write_file "/etc/init/#{app}-#{process.name}.conf", <<-UPSTART_CHILD 1.upto(concurrency[process.name]) do |num|
instance $NUM process_config = ERB.new(process_template).result(binding)
stop on stopping #{app} write_file "#{location}/#{app}-#{process.name}-#{num}.conf", process_config
respawn end
end
chdir #{engine.directory} return
exec #{process.command} >>/var/log/#{app}/#{process.name}.log 2>&1 write_file "#{location}/#{app}.conf", <<-UPSTART_MASTER
UPSTART_MASTER
engine.processes.each do |process|
write_file process_conf, <<-UPSTART_CHILD
UPSTART_CHILD UPSTART_CHILD
end end
@@ -55,12 +46,4 @@ exec #{process.command} >>/var/log/#{app}/#{process.name}.log 2>&1
config.write config.write
end end
private ######################################################################
def write_file(filename, contents)
File.open(filename, "w") do |file|
file.puts contents
end
end
end end
+75
View File
@@ -0,0 +1,75 @@
foreman(1) -- manage Procfile-based applications
================================================
## SYNOPSIS
`foreman` start [process]<br>
`foreman` export <format> [location]
## DESCRIPTION
**Foreman** is a manager for Procfile-based applications. Its aim is to
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
format.
## RUNNING
`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
type of process defined in your Procfile.
If a parameter is passed, foreman will run one instance of the specified
application type.
The following options control how the application is run:
* `-s`, `--screen`:
Run the application as a series of screen windows rather than interleaved
in stdout.
## EXPORTING
`foreman export` is used to export your application to another process
management format.
An location to export can be passed as an argument. This argument may be
either required or optional depending on the export format.
The following options control how the application is run:
* `-a`, `--app`:
Use this name rather than the application's root directory name as the
name of the application when exporting.
* `-c`, `--concurrency`:
Specify the number of each process type to run. The value passed in
should be in the format `process=num,process=num`.
## OPTIONS
These options control all modes of foreman's operation.
* `-p`, `--procfile`
Specify an alternate location for the application's Procfile. This file's
containing directory will be assumed to be the root directory of the
application.
## EXAMPLES
Start one instance of each process type, interleave the output on stdout:
$ foreman start
Export the application in upstart format:
$ foreman export upstart /etc/init
Run one process type from the application defined in a specific Procfile:
$ foreman start alpha -p ~/app/Procfile
## COPYRIGHT
Foreman is Copyright (C) 2010 David Dollar <http://daviddollar.org>
+6 -49
View File
@@ -25,27 +25,6 @@ describe "Foreman::CLI" do
end end
end end
describe "execute" do
describe "with a non-existent Procfile" do
it "prints an error" do
mock_error(subject, "Procfile does not exist.") do
dont_allow.instance_of(Foreman::Engine).start
subject.execute("alpha")
end
end
end
describe "with a Procfile" do
before(:each) { write_procfile }
it "runs successfully" do
dont_allow(subject).error
mock.instance_of(Foreman::Engine).execute("alpha")
subject.execute("alpha")
end
end
end
describe "export" do describe "export" do
describe "with a non-existent Procfile" do describe "with a non-existent Procfile" do
it "prints an error" do it "prints an error" do
@@ -62,7 +41,7 @@ describe "Foreman::CLI" do
describe "with an invalid formatter" do describe "with an invalid formatter" do
it "prints an error" do it "prints an error" do
mock_error(subject, "Unknown export format: invalidformatter.") do mock_error(subject, "Unknown export format: invalidformatter.") do
subject.export("testapp", "Procfile", "invalidformatter") subject.export("invalidformatter")
end end
end end
end end
@@ -72,33 +51,11 @@ describe "Foreman::CLI" do
it "runs successfully" do it "runs successfully" do
dont_allow(subject).error dont_allow(subject).error
subject.export("testapp") mock.instance_of(Foreman::Export::Upstart).export("/tmp/foo", {
end :concurrency => nil,
end :name => nil
end })
end subject.export("upstart", "/tmp/foo")
describe "scale" do
describe "without an existing configuration" do
it "displays an error" do
mock_error(subject, "No such process: alpha.") do
subject.scale("testapp", "alpha", "2")
end
end
end
describe "with an existing configuration" do
before(:each) { write_foreman_config("testapp") }
it "scales a process that exists" do
mock.instance_of(Foreman::Configuration).scale("alpha", "2")
subject.scale("testapp", "alpha", "2")
end
it "errors if a process that does not exist is specified" do
mock_error(subject, "No such process: invalidprocess.") do
dont_allow.instance_of(Foreman::Configuration).scale
subject.scale("testapp", "invalidprocess", "2")
end end
end end
end end