Compare commits
68 Commits
v0.30.1
...
v0.37.0.pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2995a605b4 | ||
|
|
ef280e802d | ||
|
|
8a9001842c | ||
|
|
8a8d31eb43 | ||
|
|
3e98170878 | ||
|
|
3d84de3062 | ||
|
|
9cc0afca49 | ||
|
|
7a25d3ac5a | ||
|
|
db1a5df354 | ||
|
|
e137596ce0 | ||
|
|
c9042c5aae | ||
|
|
550adc8070 | ||
|
|
fbdde3e62a | ||
|
|
e161ecb630 | ||
|
|
853a88dfbf | ||
|
|
b4cab08327 | ||
|
|
a008886bd0 | ||
|
|
c62f892ff6 | ||
|
|
d885e019b3 | ||
|
|
cfd337b44d | ||
|
|
1485eeb859 | ||
|
|
e0b5928e88 | ||
|
|
a73dce5405 | ||
|
|
2abddb42b3 | ||
|
|
d961a32cfe | ||
|
|
2bfc065c1d | ||
|
|
fbe3d4ec69 | ||
|
|
631187e0d8 | ||
|
|
92d1a4d367 | ||
|
|
f4123f4ae1 | ||
|
|
d4c2332c59 | ||
|
|
e257fc89c1 | ||
|
|
a278755ae4 | ||
|
|
3367a060a7 | ||
|
|
ac7e0743ac | ||
|
|
e574880814 | ||
|
|
7132cacbf6 | ||
|
|
c1f279aa6f | ||
|
|
34cfe9ef9d | ||
|
|
79fc3b8029 | ||
|
|
91140638e1 | ||
|
|
48cc60c30f | ||
|
|
533139ea9f | ||
|
|
86e2056a24 | ||
|
|
ab29963ee4 | ||
|
|
cf269c39da | ||
|
|
76cd2e794b | ||
|
|
83748cb538 | ||
|
|
d2c9ce0f34 | ||
|
|
98337c92e1 | ||
|
|
33d738b3f8 | ||
|
|
9432989fbe | ||
|
|
66b1483a75 | ||
|
|
64bd4db128 | ||
|
|
b561555f3a | ||
|
|
baa7b7685c | ||
|
|
cfa6e6f259 | ||
|
|
a34bc59721 | ||
|
|
07e8ca4a4b | ||
|
|
342d30bbb8 | ||
|
|
268dd6240e | ||
|
|
9e60b3e1a4 | ||
|
|
1c6285f8af | ||
|
|
5de1bd18ac | ||
|
|
fff15bc627 | ||
|
|
a66157d611 | ||
|
|
8bc8cb4b2e | ||
|
|
33aa1efc90 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,4 +5,4 @@
|
||||
/man/*.markdown
|
||||
/pkg
|
||||
/tags
|
||||
|
||||
/vendor
|
||||
6
Gemfile
6
Gemfile
@@ -2,6 +2,10 @@ source "http://rubygems.org"
|
||||
|
||||
gemspec
|
||||
|
||||
platform :jruby do
|
||||
gem "posix-spawn", "~> 0.3.6"
|
||||
end
|
||||
|
||||
group :development do
|
||||
gem 'parka'
|
||||
gem 'rake'
|
||||
@@ -9,7 +13,7 @@ group :development do
|
||||
gem 'fakefs', '~> 0.3.2'
|
||||
gem 'rcov', '~> 0.9.8'
|
||||
gem 'rr', '~> 1.0.2'
|
||||
gem 'rspec', '~> 2.6.0'
|
||||
gem 'rspec', '~> 2.0'
|
||||
gem 'aws-s3'
|
||||
gem "rubyzip"
|
||||
end
|
||||
|
||||
29
Gemfile.lock
29
Gemfile.lock
@@ -1,8 +1,8 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
foreman (0.30.1)
|
||||
term-ansicolor (~> 1.0.5)
|
||||
foreman (0.37.0.pre2)
|
||||
term-ansicolor (~> 1.0.7)
|
||||
thor (>= 0.13.6)
|
||||
|
||||
GEM
|
||||
@@ -14,17 +14,20 @@ GEM
|
||||
xml-simple
|
||||
builder (3.0.0)
|
||||
crack (0.1.8)
|
||||
diff-lcs (1.1.2)
|
||||
diff-lcs (1.1.3)
|
||||
fakefs (0.3.2)
|
||||
hpricot (0.8.2)
|
||||
hpricot (0.8.2-java)
|
||||
mime-types (1.16)
|
||||
mustache (0.11.2)
|
||||
parka (0.6.2)
|
||||
crack
|
||||
rest-client
|
||||
thor
|
||||
rake (0.9.2)
|
||||
posix-spawn (0.3.6)
|
||||
rake (0.9.2.2)
|
||||
rcov (0.9.8)
|
||||
rcov (0.9.8-java)
|
||||
rdiscount (1.6.5)
|
||||
rest-client (1.6.1)
|
||||
mime-types (>= 1.16)
|
||||
@@ -33,20 +36,21 @@ GEM
|
||||
mustache (>= 0.7.0)
|
||||
rdiscount (>= 1.5.8)
|
||||
rr (1.0.2)
|
||||
rspec (2.6.0)
|
||||
rspec-core (~> 2.6.0)
|
||||
rspec-expectations (~> 2.6.0)
|
||||
rspec-mocks (~> 2.6.0)
|
||||
rspec-core (2.6.4)
|
||||
rspec-expectations (2.6.0)
|
||||
rspec (2.8.0)
|
||||
rspec-core (~> 2.8.0)
|
||||
rspec-expectations (~> 2.8.0)
|
||||
rspec-mocks (~> 2.8.0)
|
||||
rspec-core (2.8.0)
|
||||
rspec-expectations (2.8.0)
|
||||
diff-lcs (~> 1.1.2)
|
||||
rspec-mocks (2.6.0)
|
||||
rspec-mocks (2.8.0)
|
||||
rubyzip (0.9.4)
|
||||
term-ansicolor (1.0.7)
|
||||
thor (0.14.6)
|
||||
xml-simple (1.0.15)
|
||||
|
||||
PLATFORMS
|
||||
java
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
@@ -54,9 +58,10 @@ DEPENDENCIES
|
||||
fakefs (~> 0.3.2)
|
||||
foreman!
|
||||
parka
|
||||
posix-spawn (~> 0.3.6)
|
||||
rake
|
||||
rcov (~> 0.9.8)
|
||||
ronn
|
||||
rr (~> 1.0.2)
|
||||
rspec (~> 2.6.0)
|
||||
rspec (~> 2.0)
|
||||
rubyzip
|
||||
|
||||
@@ -20,7 +20,8 @@ http://blog.daviddollar.org/2011/05/06/introducing-foreman.html
|
||||
|
||||
## Manual
|
||||
|
||||
See the [man page](http://ddollar.github.com/foreman) for usage.
|
||||
* [man page](http://ddollar.github.com/foreman)
|
||||
* [wiki](http://github.com/ddollar/foreman/wiki)
|
||||
|
||||
## Authorship
|
||||
|
||||
|
||||
12
Rakefile
12
Rakefile
@@ -1,7 +1,3 @@
|
||||
require "rubygems"
|
||||
require "bundler"
|
||||
Bundler.setup
|
||||
|
||||
require "rake"
|
||||
require "rspec"
|
||||
require "rspec/core/rake_task"
|
||||
@@ -102,9 +98,13 @@ def clean(file)
|
||||
rm file if File.exists?(file)
|
||||
end
|
||||
|
||||
def distribution_files
|
||||
def distribution_files(type=nil)
|
||||
require "foreman/distribution"
|
||||
Foreman::Distribution.files
|
||||
base_files = Foreman::Distribution.files
|
||||
type_files = type ?
|
||||
Dir[File.expand_path("../dist/resources/#{type}/**/*", __FILE__)] :
|
||||
[]
|
||||
base_files.concat(type_files)
|
||||
end
|
||||
|
||||
def mkchdir(dir)
|
||||
|
||||
36
bin/runner
36
bin/runner
@@ -1,2 +1,36 @@
|
||||
#!/bin/sh
|
||||
exec $1 2>&1
|
||||
#
|
||||
#/ Usage: runner [-d <dir>] <command>
|
||||
#/
|
||||
#/ Run a command with exec, optionally changing directory first
|
||||
|
||||
set -e
|
||||
|
||||
error() {
|
||||
echo $@ >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat $0 | grep '^#/' | cut -c4-
|
||||
exit
|
||||
}
|
||||
|
||||
while getopts ":hd:" OPT; do
|
||||
case $OPT in
|
||||
d) cd $OPTARG ;;
|
||||
h) usage ;;
|
||||
\?) error "invalid option: -$OPTARG" ;;
|
||||
:) error "option -$OPTARG requires an argument" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
shift $((OPTIND-1))
|
||||
|
||||
command=$1
|
||||
|
||||
if [ "$1" == "" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
exec $1
|
||||
|
||||
48
dist/deb.rake
vendored
Normal file
48
dist/deb.rake
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
file pkg("/apt-#{version}/foreman-#{version}.deb") => distribution_files("deb") do |t|
|
||||
mkchdir(File.dirname(t.name)) do
|
||||
mkchdir("usr/local/foreman") do
|
||||
assemble_distribution
|
||||
assemble_gems
|
||||
assemble resource("deb/foreman"), "bin/foreman", 0755
|
||||
File.chmod 0755, "bin/runner"
|
||||
end
|
||||
|
||||
assemble resource("deb/control"), "control"
|
||||
assemble resource("deb/postinst"), "postinst"
|
||||
|
||||
sh "tar czvf data.tar.gz usr/local/foreman --owner=root --group=root"
|
||||
sh "tar czvf control.tar.gz control postinst"
|
||||
|
||||
File.open("debian-binary", "w") do |f|
|
||||
f.puts "2.0"
|
||||
end
|
||||
|
||||
deb = File.basename(t.name)
|
||||
|
||||
sh "ar -r #{t.name} debian-binary control.tar.gz data.tar.gz"
|
||||
|
||||
touch "Sources"
|
||||
sh "apt-ftparchive packages . > Packages"
|
||||
sh "gzip -c Packages > Packages.gz"
|
||||
sh "apt-ftparchive release . > Release"
|
||||
sh "gpg -abs -u 0F1B0520 -o Release.gpg Release"
|
||||
end
|
||||
end
|
||||
|
||||
desc "Build a .deb package"
|
||||
task "deb:build" => pkg("/apt-#{version}/foreman-#{version}.deb")
|
||||
|
||||
desc "Remove build artifacts for .deb"
|
||||
task "deb:clean" do
|
||||
clean pkg("foreman-#{version}.deb")
|
||||
FileUtils.rm_rf("pkg/apt-#{version}") if Dir.exists?("pkg/apt-#{version}")
|
||||
end
|
||||
|
||||
desc "Publish .deb to S3."
|
||||
task "deb:release" => "deb:build" do |t|
|
||||
Dir["pkg/apt-#{version}/*"].each do |file|
|
||||
unless File.directory?(file)
|
||||
store file, "apt/#{File.basename(file)}"
|
||||
end
|
||||
end
|
||||
end
|
||||
14
dist/jruby.rake
vendored
Normal file
14
dist/jruby.rake
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
file pkg("foreman-#{version}-jruby.gem") => distribution_files do |t|
|
||||
sh "env PLATFORM=jruby gem build foreman.gemspec"
|
||||
sh "mv foreman-#{version}-java.gem #{t.name}"
|
||||
end
|
||||
|
||||
task "jruby:build" => pkg("foreman-#{version}-jruby.gem")
|
||||
|
||||
task "jruby:clean" do
|
||||
clean pkg("foreman-#{version}-jruby.gem")
|
||||
end
|
||||
|
||||
task "jruby:release" => "jruby:build" do |t|
|
||||
sh "parka push -f #{pkg("foreman-#{version}-jruby.gem")}"
|
||||
end
|
||||
12
dist/resources/deb/control
vendored
Normal file
12
dist/resources/deb/control
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
Package: foreman
|
||||
Version: <%= version %>
|
||||
Section: main
|
||||
Priority: standard
|
||||
Architecture: all
|
||||
Depends: ruby1.9.1
|
||||
Maintainer: Heroku
|
||||
Description: Manage Procfile-based applications.
|
||||
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.
|
||||
18
dist/resources/deb/foreman
vendored
Normal file
18
dist/resources/deb/foreman
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env ruby1.9.1
|
||||
|
||||
# resolve bin path, ignoring symlinks
|
||||
require "pathname"
|
||||
bin_file = Pathname.new(__FILE__).realpath
|
||||
|
||||
# add locally vendored gems to libpath
|
||||
gem_dir = File.expand_path("../../vendor/gems", bin_file)
|
||||
Dir["#{gem_dir}/**/lib"].each do |libdir|
|
||||
$:.unshift libdir
|
||||
end
|
||||
|
||||
# add self to libpath
|
||||
$:.unshift File.expand_path("../../lib", bin_file)
|
||||
|
||||
require "foreman/cli"
|
||||
|
||||
Foreman::CLI.start
|
||||
30
dist/resources/deb/heroku-release-key.txt
vendored
Normal file
30
dist/resources/deb/heroku-release-key.txt
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1.4.11 (Darwin)
|
||||
|
||||
mQENBE5SfAEBCADLp056ZgfdtAMXLWpEuL9zY+dIHIY5qLQcDmUivjHLVE4l3Bi3
|
||||
Mn570K0W9rfk7fHBPEO2XJEDdjk8Bg6mWTAeGjdfZgZaL+qO9NjqQ5QmVR+vgp7s
|
||||
yxJYlfY+JYTZvl/JiDWGhuPHSPggXILCMf3SpqWMHGPqe/3RAK+CHCNv/94uaoS4
|
||||
vi4HQT+k4sRceiM8WqkSRYSoc7rzdDejZn+InCYFfR56VeSFF4G4I6neZs/q5T9d
|
||||
Ty2i5d0gZLaX/Iqc+3Dy0vDKClc0HUQJ6ajDPuUqKLHFUpqyuwfJij60+C3GMi8K
|
||||
ckRPti31EPFVzq3GPHU+GqA+e9j84WHr4uJ5ABEBAAG0L0hlcm9rdSBSZWxlYXNl
|
||||
IEVuZ2luZWVyaW5nIDxyZWxlYXNlQGhlcm9rdS5jb20+iQE4BBMBAgAiBQJOUnwB
|
||||
AhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDJJ+vgDxsFIChECAC9h4Ay
|
||||
Nx4AQFu85cjR9rijyBflPeVqi7Xhzd7IvLg2+kZSexlb2oidj7iVSMy+vy5tG9g9
|
||||
8Az/JqMCVjcZ7ltn60OGU8gIYpJqt6VmH3vfJBxXu/Sm9tym3UCYGVvMAN5Oq6yB
|
||||
HlQkQ8F3p0cW69PmF+fibkgo9RE0EYlBIt2rUHNilTGFS6vXGr5reFFp3/rRHq3k
|
||||
bixnUwFSqNujJgnBKDPwtSYKc4pMpnhuv88xEpLH7vU8NLXQZMitKQguV8XEmcsu
|
||||
43LXlsx5uVr239/XNW+h412gIHFDSzB/YuLWlVUXMfquC96z/wxMqWWZyskDNgr0
|
||||
WDdMgzK6CUfXSqQhuQENBE5SfAEBCADbnGKcXpdVauQpINQLtRnrT0BJIrIo1Yxv
|
||||
LQRb3G7RU+Eq6aHXwk9fSKa6nEv9RsmqiW874yODnr0d/DTUWMHT+jRvPHm1wlbE
|
||||
pGR1aPSo7GgkSUdaT6CVBN3JWZ2kVJGqohNoJMYbfVaWd/kpa/LiMFWzS8LfWT2K
|
||||
xiO2vIh4qBfeRCGR7s8rADCHuHJ0eibADrgqcRfdPrChB1JiYLeTdV4yRmSzJ7TM
|
||||
zWX7OVpGfIFLbCw9NeN65pI9ePs2mSPM7DYkhhKSXWMwJNXFzn1blOGiwAwKb48P
|
||||
a/QpE6TG3PQzbYyTTP0Td1XgKAHcprvbc89a/nAk3a+PJQ/MqvDzABEBAAGJAR8E
|
||||
GAECAAkFAk5SfAECGwwACgkQySfr4A8bBSD4mAgAnCT5WRiDl0259Px9Z9J9Wk8Z
|
||||
SxugDct2Yhzca4aw1Ou4cfaIFCDXzFlBzSJfqk0HoVhp9r2gzEPUCKnSjRDyxaMo
|
||||
wZCUtqigBua+z4NB4AWgeOl/2S06I2ki1K7pfl4piYcHtEThHamnhVPJ2Hi6HsHq
|
||||
mUU+8SxleHE4GCXmKkuvxelUq9jrhHikIkm1RoqFOPb9zV3WRy4YzVHQSYfHmfk0
|
||||
9kXlM/CS0sfNv2UKCX+5e6eFIZv0rdtpp6VEh0tsFmsIClY6Z9MX7bgp8MnUJpyk
|
||||
OeIzOzQgkb4aeT0Whl+EPcTeDZfqIhVBoNXupUanmWNppFcMngxfqG2NGi1vvQ==
|
||||
=aUAq
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
3
dist/resources/deb/postinst
vendored
Executable file
3
dist/resources/deb/postinst
vendored
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
ln -sf /usr/local/foreman/bin/foreman /usr/bin/foreman
|
||||
@@ -16,6 +16,11 @@ Gem::Specification.new do |gem|
|
||||
gem.files = Dir["**/*"].select { |d| d =~ %r{^(README|bin/|data/|ext/|lib/|spec/|test/)} }
|
||||
gem.files << "man/foreman.1"
|
||||
|
||||
gem.add_dependency 'term-ansicolor', '~> 1.0.5'
|
||||
gem.add_dependency 'term-ansicolor', '~> 1.0.7'
|
||||
gem.add_dependency 'thor', '>= 0.13.6'
|
||||
|
||||
if ENV["PLATFORM"] == "jruby"
|
||||
gem.add_dependency "posix-spawn", "~> 0.3.6"
|
||||
gem.platform = Gem::Platform.new("java")
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,14 +6,23 @@ require "yaml"
|
||||
|
||||
class Foreman::CLI < Thor
|
||||
|
||||
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
|
||||
|
||||
desc "start", "Start the application"
|
||||
|
||||
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
|
||||
class_option :app_root, :type => :string, :aliases => "-d", :desc => "Default: Procfile directory"
|
||||
|
||||
method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
|
||||
method_option :port, :type => :numeric, :aliases => "-p"
|
||||
method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"'
|
||||
|
||||
class << self
|
||||
# Hackery. Take the run method away from Thor so that we can redefine it.
|
||||
def is_thor_reserved_word?(word, type)
|
||||
return false if word == 'run'
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def start
|
||||
check_procfile!
|
||||
engine.start
|
||||
@@ -54,6 +63,19 @@ class Foreman::CLI < Thor
|
||||
display "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
|
||||
end
|
||||
|
||||
desc "run COMMAND", "Run a command using your application's environment"
|
||||
|
||||
def run(*args)
|
||||
engine.apply_environment!
|
||||
begin
|
||||
exec args.join(" ")
|
||||
rescue Errno::EACCES
|
||||
error "not executable: #{args.first}"
|
||||
rescue Errno::ENOENT
|
||||
error "command not found: #{args.first}"
|
||||
end
|
||||
end
|
||||
|
||||
private ######################################################################
|
||||
|
||||
def check_procfile!
|
||||
@@ -87,5 +109,4 @@ private ######################################################################
|
||||
defaults = YAML::load_file(".foreman") || {}
|
||||
Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -17,11 +17,13 @@ class Foreman::Engine
|
||||
|
||||
extend Term::ANSIColor
|
||||
|
||||
COLORS = [ cyan, yellow, green, magenta, red ]
|
||||
COLORS = [ cyan, yellow, green, magenta, red, blue,
|
||||
intense_cyan, intense_yellow, intense_green, intense_magenta,
|
||||
intense_red, intense_blue ]
|
||||
|
||||
def initialize(procfile, options={})
|
||||
@procfile = Foreman::Procfile.new(procfile)
|
||||
@directory = File.expand_path(File.dirname(procfile))
|
||||
@directory = options[:app_root] || File.expand_path(File.dirname(procfile))
|
||||
@options = options
|
||||
@environment = read_environment_files(options[:env])
|
||||
@output_mutex = Mutex.new
|
||||
@@ -58,7 +60,7 @@ private ######################################################################
|
||||
|
||||
procfile.entries.each do |entry|
|
||||
reader, writer = IO.pipe
|
||||
entry.spawn(concurrency[entry.name], writer, @directory, @environment, base_port).each do |process|
|
||||
entry.spawn(concurrency[entry.name], writer, @directory, @environment, port_for(entry, 1, base_port)).each do |process|
|
||||
running_processes[process.pid] = process
|
||||
readers[process] = reader
|
||||
end
|
||||
@@ -71,6 +73,7 @@ private ######################################################################
|
||||
|
||||
def kill_all(signal="SIGTERM")
|
||||
running_processes.each do |pid, process|
|
||||
info "sending #{signal} to pid #{pid}"
|
||||
Process.kill(signal, pid) rescue Errno::ESRCH
|
||||
end
|
||||
end
|
||||
@@ -181,7 +184,8 @@ private ######################################################################
|
||||
def next_color
|
||||
@current_color ||= -1
|
||||
@current_color += 1
|
||||
@current_color >= COLORS.length ? "" : COLORS[@current_color]
|
||||
@current_color = 0 if COLORS.length < @current_color
|
||||
COLORS[@current_color]
|
||||
end
|
||||
|
||||
module Env
|
||||
|
||||
@@ -26,7 +26,7 @@ private ######################################################################
|
||||
def export_template(exporter, file, template_root)
|
||||
if template_root && File.exist?(file_path = File.join(template_root, file))
|
||||
File.read(file_path)
|
||||
elsif File.exist?(file_path = File.join("~/.foreman/templates", file))
|
||||
elsif File.exist?(file_path = File.expand_path(File.join("~/.foreman/templates", file)))
|
||||
File.read(file_path)
|
||||
else
|
||||
File.read(File.expand_path("../../../../data/export/#{exporter}/#{file}", __FILE__))
|
||||
|
||||
@@ -29,6 +29,7 @@ class Foreman::Export::Runit < Foreman::Export::Base
|
||||
|
||||
run = ERB.new(run_template).result(binding)
|
||||
write_file "#{process_directory}/run", run
|
||||
FileUtils.chmod 0755, "#{process_directory}/run"
|
||||
|
||||
port = engine.port_for(process, num, options[:port])
|
||||
environment_variables = {'PORT' => port}.
|
||||
@@ -41,7 +42,7 @@ class Foreman::Export::Runit < Foreman::Export::Base
|
||||
|
||||
log_run = ERB.new(log_run_template).result(binding)
|
||||
write_file "#{process_log_directory}/run", log_run
|
||||
|
||||
FileUtils.chmod 0755, "#{process_log_directory}/run"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
require "foreman"
|
||||
require "rubygems"
|
||||
|
||||
class Foreman::Process
|
||||
|
||||
@@ -14,10 +15,8 @@ class Foreman::Process
|
||||
end
|
||||
|
||||
def run(pipe, basedir, environment)
|
||||
Dir.chdir(basedir) do
|
||||
with_environment(environment.merge("PORT" => port.to_s)) do
|
||||
run_process entry.command, pipe
|
||||
end
|
||||
with_environment(environment.merge("PORT" => port.to_s)) do
|
||||
run_process basedir, entry.command, pipe
|
||||
end
|
||||
end
|
||||
|
||||
@@ -27,22 +26,33 @@ class Foreman::Process
|
||||
|
||||
private
|
||||
|
||||
def fork_with_io(command)
|
||||
io = case RUBY_VERSION
|
||||
when /^1\.9\./
|
||||
IO.popen([Foreman.runner, replace_command_env(command)], "w+")
|
||||
when /^1\.8\./
|
||||
full_command = replace_command_env(command).gsub("'", "\\'")
|
||||
IO.popen("#{Foreman.runner} '#{full_command}'", "w+")
|
||||
else
|
||||
raise "Unknown Ruby version: #{RUBY_VERSION}"
|
||||
end
|
||||
[ io, io.pid ]
|
||||
def jruby?
|
||||
defined?(RUBY_PLATFORM) and RUBY_PLATFORM == "java"
|
||||
end
|
||||
|
||||
def run_process(command, pipe)
|
||||
io, @pid = fork_with_io(command)
|
||||
trap("SIGTERM") { "got sigterm for %d" % @pid }
|
||||
def fork_with_io(command, basedir)
|
||||
reader, writer = IO.pipe
|
||||
command = replace_command_env(command)
|
||||
pid = if jruby?
|
||||
require "posix/spawn"
|
||||
POSIX::Spawn.spawn(Foreman.runner, "-d", basedir, command, {
|
||||
:out => writer, :err => writer
|
||||
})
|
||||
else
|
||||
fork do
|
||||
trap("INT", "IGNORE")
|
||||
writer.sync = true
|
||||
$stdout.reopen writer
|
||||
$stderr.reopen writer
|
||||
reader.close
|
||||
exec Foreman.runner, "-d", basedir, command
|
||||
end
|
||||
end
|
||||
[ reader, pid ]
|
||||
end
|
||||
|
||||
def run_process(basedir, command, pipe)
|
||||
io, @pid = fork_with_io(command, basedir)
|
||||
output pipe, "started with pid %d" % @pid
|
||||
Thread.new do
|
||||
until io.eof?
|
||||
|
||||
@@ -5,7 +5,10 @@ class Foreman::Utils
|
||||
def self.parse_concurrency(concurrency)
|
||||
begin
|
||||
pairs = concurrency.to_s.gsub(/\s/, "").split(",")
|
||||
pairs.inject(Hash.new(1)) do |hash, pair|
|
||||
|
||||
default = concurrency.nil? ? 1 : 0
|
||||
|
||||
pairs.inject(Hash.new(default)) do |hash, pair|
|
||||
process, amount = pair.split("=")
|
||||
hash.update(process => amount.to_i)
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module Foreman
|
||||
|
||||
VERSION = "0.30.1"
|
||||
VERSION = "0.37.0.pre2"
|
||||
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.\" generated with Ronn/v0.7.3
|
||||
.\" http://github.com/rtomayko/ronn/tree/0.7.3
|
||||
.
|
||||
.TH "FOREMAN" "1" "November 2011" "Foreman 0.26.0" "Foreman Manual"
|
||||
.TH "FOREMAN" "1" "January 2012" "Foreman 0.33.1" "Foreman Manual"
|
||||
.
|
||||
.SH "NAME"
|
||||
\fBforeman\fR \- manage Procfile\-based applications
|
||||
@@ -68,6 +68,10 @@ Specify the user the application should be run as\. Defaults to the app name
|
||||
These options control all modes of foreman\'s operation\.
|
||||
.
|
||||
.TP
|
||||
\fB\-d\fR, \fB\-\-directory\fR
|
||||
Specify an alternate application root\. This defaults to the directory containing the Procfile\.
|
||||
.
|
||||
.TP
|
||||
\fB\-e\fR, \fB\-\-env\fR
|
||||
Specify an alternate environment file\. You can specify more than one file by using: \fB\-\-env file1,file2\fR\.
|
||||
.
|
||||
|
||||
@@ -66,6 +66,10 @@ The following options control how the application is run:
|
||||
|
||||
These options control all modes of foreman's operation.
|
||||
|
||||
* `-d`, `--directory`:
|
||||
Specify an alternate application root. This defaults to the directory
|
||||
containing the Procfile.
|
||||
|
||||
* `-e`, `--env`:
|
||||
Specify an alternate environment file. You can specify more than one
|
||||
file by using: `--env file1,file2`.
|
||||
|
||||
@@ -89,5 +89,54 @@ describe "Foreman::CLI" do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "run" do
|
||||
describe "with a valid Procfile" do
|
||||
before { write_procfile }
|
||||
|
||||
describe "and a command" do
|
||||
let(:command) { ["ls", "-l"] }
|
||||
|
||||
before(:each) do
|
||||
stub(subject).exec
|
||||
end
|
||||
|
||||
it "should load the environment file" do
|
||||
write_env
|
||||
preserving_env do
|
||||
subject.run *command
|
||||
ENV["FOO"].should == "bar"
|
||||
end
|
||||
|
||||
ENV["FOO"].should be_nil
|
||||
end
|
||||
|
||||
it "should runute the command as a string" do
|
||||
mock(subject).exec(command.join(" "))
|
||||
subject.run *command
|
||||
end
|
||||
end
|
||||
|
||||
describe "and a non-existent command" do
|
||||
let(:command) { "iuhtngrglhulhdfg" }
|
||||
|
||||
it "should print an error" do
|
||||
mock_error(subject, "command not found: #{command}") do
|
||||
subject.run command
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "and a non-executable command" do
|
||||
let(:command) { __FILE__ }
|
||||
|
||||
it "should print an error" do
|
||||
mock_error(subject, "not executable: #{command}") do
|
||||
subject.run command
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -35,7 +35,7 @@ describe "Foreman::Engine" do
|
||||
write_procfile
|
||||
engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2")
|
||||
mock.instance_of(Foreman::Process).run_process("./alpha", is_a(IO)).twice
|
||||
mock.instance_of(Foreman::Process).run_process("./bravo", is_a(IO))
|
||||
mock.instance_of(Foreman::Process).run_process("./bravo", is_a(IO)).never
|
||||
mock(engine).watch_for_output
|
||||
mock(engine).watch_for_termination
|
||||
engine.start
|
||||
|
||||
@@ -12,8 +12,13 @@ describe Foreman::Export::Bluepill do
|
||||
before(:each) { stub(bluepill).say }
|
||||
|
||||
it "exports to the filesystem" do
|
||||
bluepill.export("/tmp/init", :concurrency => "alpha=2")
|
||||
File.read("/tmp/init/app.pill").should == example_export_file("bluepill/app.pill")
|
||||
bluepill.export("/tmp/init")
|
||||
normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app.pill"))
|
||||
end
|
||||
|
||||
end
|
||||
it "exports to the filesystem with concurrency" do
|
||||
bluepill.export("/tmp/init", :concurrency => "alpha=2")
|
||||
|
||||
normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app-concurrency.pill"))
|
||||
end
|
||||
end
|
||||
@@ -10,10 +10,11 @@ describe Foreman::Export::Runit do
|
||||
|
||||
before(:each) { load_export_templates_into_fakefs("runit") }
|
||||
before(:each) { stub(runit).say }
|
||||
before(:each) { stub(FakeFS::FileUtils).chmod }
|
||||
|
||||
it "exports to the filesystem" do
|
||||
FileUtils.mkdir_p('/tmp/init')
|
||||
runit.export('/tmp/init', :concurrency => 'alpha=2')
|
||||
runit.export('/tmp/init', :concurrency => "alpha=2,bravo=1")
|
||||
|
||||
File.read("/tmp/init/app-alpha-1/run").should == example_export_file('runit/app-alpha-1-run')
|
||||
File.read("/tmp/init/app-alpha-1/log/run").should ==
|
||||
|
||||
@@ -12,14 +12,23 @@ describe Foreman::Export::Upstart do
|
||||
before(:each) { stub(upstart).say }
|
||||
|
||||
it "exports to the filesystem" do
|
||||
upstart.export("/tmp/init")
|
||||
|
||||
File.read("/tmp/init/app.conf").should == example_export_file("upstart/app.conf")
|
||||
File.read("/tmp/init/app-alpha.conf").should == example_export_file("upstart/app-alpha.conf")
|
||||
File.read("/tmp/init/app-alpha-1.conf").should == example_export_file("upstart/app-alpha-1.conf")
|
||||
File.read("/tmp/init/app-bravo.conf").should == example_export_file("upstart/app-bravo.conf")
|
||||
File.read("/tmp/init/app-bravo-1.conf").should == example_export_file("upstart/app-bravo-1.conf")
|
||||
end
|
||||
|
||||
it "exports to the filesystem with concurrency" do
|
||||
upstart.export("/tmp/init", :concurrency => "alpha=2")
|
||||
|
||||
File.read("/tmp/init/app.conf").should == example_export_file("upstart/app.conf")
|
||||
File.read("/tmp/init/app-alpha.conf").should == example_export_file("upstart/app-alpha.conf")
|
||||
File.read("/tmp/init/app-alpha-1.conf").should == example_export_file("upstart/app-alpha-1.conf")
|
||||
File.read("/tmp/init/app-alpha-2.conf").should == example_export_file("upstart/app-alpha-2.conf")
|
||||
File.read("/tmp/init/app-bravo.conf").should == example_export_file("upstart/app-bravo.conf")
|
||||
File.read("/tmp/init/app-bravo-1.conf").should == example_export_file("upstart/app-bravo-1.conf")
|
||||
File.exists?("/tmp/init/app-bravo-1.conf").should == false
|
||||
end
|
||||
|
||||
context "with alternate templates" do
|
||||
@@ -38,13 +47,19 @@ describe Foreman::Export::Upstart do
|
||||
end
|
||||
|
||||
context "with alternate templates from home dir" do
|
||||
let(:default_template_root) {File.expand_path("~/.foreman/templates")}
|
||||
let(:default_template_root) {File.expand_path("#{ENV['HOME']}/.foreman/templates")}
|
||||
|
||||
before do
|
||||
ENV['_FOREMAN_SPEC_HOME'] = ENV['HOME']
|
||||
ENV['HOME'] = "/home/appuser"
|
||||
FileUtils.mkdir_p default_template_root
|
||||
File.open("#{default_template_root}/master.conf.erb", "w") { |f| f.puts "default_alternate_template" }
|
||||
end
|
||||
|
||||
after do
|
||||
ENV['HOME'] = ENV.delete('_FOREMAN_SPEC_HOME')
|
||||
end
|
||||
|
||||
it "can export with alternate template files" do
|
||||
upstart.export("/tmp/init")
|
||||
|
||||
|
||||
18
spec/helper_spec.rb
Normal file
18
spec/helper_spec.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
require "spec_helper"
|
||||
|
||||
describe "spec helpers" do
|
||||
describe "#preserving_env" do
|
||||
after { ENV.delete "FOO" }
|
||||
|
||||
it "should remove added environment vars" do
|
||||
preserving_env { ENV["FOO"] = "baz" }
|
||||
ENV["FOO"].should == nil
|
||||
end
|
||||
|
||||
it "should reset modified environment vars" do
|
||||
ENV["FOO"] = "bar"
|
||||
preserving_env { ENV["FOO"] = "baz"}
|
||||
ENV["FOO"].should == "bar"
|
||||
end
|
||||
end
|
||||
end
|
||||
47
spec/resources/export/bluepill/app-concurrency.pill
Normal file
47
spec/resources/export/bluepill/app-concurrency.pill
Normal file
@@ -0,0 +1,47 @@
|
||||
Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepill.log") do |app|
|
||||
|
||||
app.uid = "app"
|
||||
app.gid = "app"
|
||||
|
||||
|
||||
|
||||
|
||||
app.process("alpha-1") do |process|
|
||||
process.start_command = "./alpha"
|
||||
|
||||
process.working_dir = "/tmp/app"
|
||||
process.daemonize = true
|
||||
process.environment = {"PORT" => "5000"}
|
||||
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
|
||||
|
||||
process.stdout = process.stderr = "/var/log/app/app-alpha-1.log"
|
||||
|
||||
process.monitor_children do |children|
|
||||
children.stop_command "kill -QUIT {{PID}}"
|
||||
end
|
||||
|
||||
process.group = "app-alpha"
|
||||
end
|
||||
|
||||
|
||||
app.process("alpha-2") do |process|
|
||||
process.start_command = "./alpha"
|
||||
|
||||
process.working_dir = "/tmp/app"
|
||||
process.daemonize = true
|
||||
process.environment = {"PORT" => "5001"}
|
||||
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
|
||||
|
||||
process.stdout = process.stderr = "/var/log/app/app-alpha-2.log"
|
||||
|
||||
process.monitor_children do |children|
|
||||
children.stop_command "kill -QUIT {{PID}}"
|
||||
end
|
||||
|
||||
process.group = "app-alpha"
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
@@ -23,27 +23,6 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
|
||||
process.group = "app-alpha"
|
||||
end
|
||||
|
||||
|
||||
app.process("alpha-2") do |process|
|
||||
process.start_command = "./alpha"
|
||||
|
||||
process.working_dir = "/tmp/app"
|
||||
process.daemonize = true
|
||||
process.environment = {"PORT" => "5001"}
|
||||
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
|
||||
|
||||
process.stdout = process.stderr = "/var/log/app/app-alpha-2.log"
|
||||
|
||||
process.monitor_children do |children|
|
||||
children.stop_command "kill -QUIT {{PID}}"
|
||||
end
|
||||
|
||||
process.group = "app-alpha"
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
app.process("bravo-1") do |process|
|
||||
process.start_command = "./bravo"
|
||||
|
||||
|
||||
@@ -63,8 +63,23 @@ def example_export_file(filename)
|
||||
data
|
||||
end
|
||||
|
||||
def preserving_env
|
||||
old_env = ENV.to_hash
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
ENV.clear
|
||||
ENV.update(old_env)
|
||||
end
|
||||
end
|
||||
|
||||
def normalize_space(s)
|
||||
s.gsub(/\n[\n\s]*/, "\n")
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.color_enabled = true
|
||||
config.order = 'rand'
|
||||
config.include FakeFS::SpecHelpers
|
||||
config.mock_with :rr
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user