Compare commits

...
69 Commits
Author SHA1 Message Date
David Dollar a04032454a 0.37.0.pre4 2012-01-24 08:03:07 -08:00
David Dollar 29c94c785d Merge pull request #130 from clowder/foreman
---

Because `Your::Runit::Env != My::Runit::Env` I thought that it would be nice to be able to include your own export format as a another gem along side Foreman; similar to MultiJson’s engines but using constantize because we are specifying formats via the command line.

Cheers,
Chris
2012-01-24 08:00:12 -08:00
Chris Lowder a0a2dd9454 Don't expose the options hash. 2012-01-24 15:10:25 +00:00
Chris Lowder 1b701cddf3 Simplify subclassing by adding all arguments to the initializer. Also, clean up the method signatures for existing exporters. 2012-01-24 15:10:18 +00:00
Chris Lowder 4080b3f1f2 Add ZenTest as a development dependency, there is an autotest folder but the gem is missing. 2012-01-24 14:37:57 +00:00
Chris Lowder 84c49ae2b8 Attempt to require the custom export class. 2012-01-24 14:36:38 +00:00
Chris Lowder d54b46806c Catching more than we need to. 2012-01-24 14:36:38 +00:00
Chris Lowder bc1c5e4c74 Extract commonality into the base class, make life easy for our plugin writers. 2012-01-24 14:36:38 +00:00
Chris Lowder ed4a32518f Removing the hard coding of export formats allowing the user to 'plug-in' their own export format. 2012-01-24 14:31:45 +00:00
David Dollar c7167e1c83 Update README.markdown 2012-01-23 14:20:45 -08:00
David Dollar db93432118 Revert "try on more rubies"
This reverts commit 5eada6b7cc.
2012-01-23 00:45:25 -05:00
David Dollar 5eada6b7cc try on more rubies 2012-01-23 00:43:25 -05:00
David Dollar 5e46b1f43a fix webhook url 2012-01-23 00:41:10 -05:00
David Dollar ef723f5831 Update README.markdown 2012-01-23 00:37:58 -05:00
David Dollar 52e24ef64b Update README.markdown 2012-01-23 00:31:57 -05:00
David Dollar 0b1daf1927 ensure we have non-nil data, fixes #111 2012-01-22 22:01:03 -05:00
David Dollar e0d84a56d7 make sure error method exists. fixes #104 2012-01-22 21:55:55 -05:00
David Dollar 7ee2edcc60 Merge pull request #136 from fnichol/foreman
---

Simple enough, but this helps when re-exporting runit services. Cheers, and thanks!

Conflicts:
	spec/foreman/export/runit_spec.rb
2012-01-22 21:46:57 -05:00
David Dollar d428ac5356 remove other from install instructions 2012-01-22 21:42:51 -05:00
David Dollar 5351b49fee cleanup 2012-01-22 21:41:10 -05:00
David Dollar 6ebe76d8c1 Revert "tweak authors"
This reverts commit 7c43c672c9
2012-01-22 21:39:24 -05:00
David Dollar 7c43c672c9 tweak authors 2012-01-22 21:39:09 -05:00
David Dollar 41d9050ae3 fix authors 2012-01-22 21:38:17 -05:00
David Dollar 09e9cefa3a readme tweaks 2012-01-22 21:36:38 -05:00
David Dollar 85efe5c1ba readme tweaks 2012-01-22 21:36:24 -05:00
David Dollar c21634c04e fix up authors 2012-01-22 21:34:23 -05:00
David Dollar 6d4f3476f1 Update README.markdown 2012-01-22 21:32:33 -05:00
David Dollar 724812d6e3 fix up specs 2012-01-22 21:17:54 -05:00
David Dollar ce6ec4848d we're not chdiring any more 2012-01-22 21:17:38 -05:00
David Dollar a37a097f73 use strings rather than symbols to better emulate the real thing 2012-01-22 21:17:18 -05:00
David Dollar f28725bdac Merge pull request #139 from brainopia/foreman
---

If you remember Ive wanted to implement a prototype of process-tree monitor (and therefore restore support for complex commands), but decided to start with specing current behavior and marking desired behavior as pending specs.

This pull-request is a first pass. Its mainly Foreman::Process specs and a bit of refactoring. Specs for Foreman::Engine will be coming next (theyll cover a wide ground of possible uses). Afterwards I will replace machinery a bit to remove pending specs and ensure the rest is still passing on all available to me platforms.

If you have any notices, Ill gladly hear them.
2012-01-22 20:58:51 -05:00
David Dollar 51eee011ce 0.37.0.pre3 2012-01-22 20:40:50 -05:00
David Dollar 6c8c848f54 normalize platform names 2012-01-22 20:33:14 -05:00
David Dollar f60c4cb767 windows support 2012-01-22 20:33:14 -05:00
David Dollar 4ad49cb058 add windows support 2012-01-22 20:33:13 -05:00
David Dollar e993af2b20 dont need pty 2012-01-22 20:33:13 -05:00
David Dollar d7000bccfa fix specs 2012-01-22 19:14:24 -05:00
David Dollar 2995a605b4 0.37.0.pre2 2012-01-22 19:05:42 -05:00
David Dollar ef280e802d 0.37.0.pre1 2012-01-22 19:04:25 -05:00
David Dollar 8a9001842c remove unnecessary stdout/stderr flattening 2012-01-22 19:01:36 -05:00
David Dollar 8a8d31eb43 use PLATFORM=jruby instead of JRUBY=true 2012-01-22 18:55:47 -05:00
David Dollar 3e98170878 fix java build bug 2012-01-22 18:39:43 -05:00
David Dollar 3d84de3062 dont do rubygems/bundler in the Rakefile 2012-01-22 18:39:33 -05:00
David Dollar 9cc0afca49 switch to posix-spawn for jruby 2012-01-22 18:39:20 -05:00
David Dollar 7a25d3ac5a add jruby build 2012-01-22 17:38:02 -05:00
David Dollar db1a5df354 spork is in the gemspec now 2012-01-22 17:37:41 -05:00
David Dollar e137596ce0 remove debugging 2012-01-22 17:37:30 -05:00
David Dollar c9042c5aae move the spoon require into the jruby branch 2012-01-22 17:30:02 -05:00
David Dollar 550adc8070 pass basedir along to the runner script 2012-01-22 17:29:52 -05:00
David Dollar fbdde3e62a beef up the runner script to allow a working directory to be set 2012-01-22 17:29:15 -05:00
David Dollar e161ecb630 Merge pull request #140 from jc00ke/foreman
---

Fixes #2

This is my first patch for JRuby, so any feedback would be appreciated. The specs do not run (Ill file a separate issue) but I am able to successfully start up & run the contents of a `Procfile`.

I based this patch on [launchys JRuby support](https://github.com/copiousfreetime/launchy/pull/10) and I too confirmed these changes did not break 1.8.7, 1.9.2 or 1.9.3.
2012-01-22 16:58:30 -05:00
jc00ke 853a88dfbf Move spoon dep to Gemfile
By moving it to the Gemfile & using platform we're able avoid installing
spoon for other Ruby implementations.
2012-01-22 13:43:37 -08:00
jc00ke b4cab08327 Using spoon for JRuby support 2012-01-22 12:27:25 -08:00
brainopia ade0005a92 Add specs for Foreman::Process#run 2012-01-22 22:07:53 +04:00
brainopia 241b91a0d5 Implement Foreman::Process#kill,detach,alive?,dead? 2012-01-22 22:07:01 +04:00
brainopia 047f106d48 - Use explicit fakefs tag in specs
- Clean up trailing whitespace
2012-01-22 15:00:43 +04:00
brainopia df043e60d8 Simplify Foreman::Process#with_environment 2012-01-22 08:57:09 +04:00
brainopia 158c184f8c Add specs for options of Foreman::Process#run 2012-01-22 08:55:45 +04:00
brainopia 2ed1fe8d44 Add specs for initialization of Foreman::Process 2012-01-22 08:54:42 +04:00
David Dollar a008886bd0 use default bucket for storage 2012-01-20 18:21:55 -08:00
David Dollar c62f892ff6 Merge pull request #138 from technomancy/debian
Debian
2012-01-20 18:07:45 -08:00
Phil Hagelberg d885e019b3 Add Debian packaging. 2012-01-20 18:02:01 -08:00
Phil Hagelberg cfd337b44d Ignore vendor dir. 2012-01-20 18:01:46 -08:00
Fletcher Nichol e76f3533dc runit creates a full path to export directory. 2012-01-18 20:13:08 -07:00
David Dollar 1485eeb859 0.36.1 2012-01-18 11:18:39 -05:00
David Dollar e0b5928e88 bump term-ansicolor in gemspec 2012-01-18 11:18:33 -05:00
David Dollar a73dce5405 0.36.0 2012-01-17 22:21:36 -05:00
David Dollar 2abddb42b3 sync the writer stream 2012-01-17 22:21:16 -05:00
David Dollar d961a32cfe capture stderr as well 2012-01-17 22:20:25 -05:00
37 changed files with 621 additions and 190 deletions
-1
View File
@@ -1 +0,0 @@
FOO=bar
+1 -1
View File
@@ -5,4 +5,4 @@
/man/*.markdown /man/*.markdown
/pkg /pkg
/tags /tags
/vendor
+1 -1
View File
@@ -11,4 +11,4 @@ notifications:
on_success: always on_success: always
on_failure: always on_failure: always
urls: urls:
- https://dx-helper.herokuapp.com/travis - http://dx-helper.herokuapp.com/travis
+9
View File
@@ -2,6 +2,14 @@ source "http://rubygems.org"
gemspec gemspec
platform :mingw do
gem "win32console", "~> 1.3.0"
end
platform :jruby do
gem "posix-spawn", "~> 0.3.6"
end
group :development do group :development do
gem 'parka' gem 'parka'
gem 'rake' gem 'rake'
@@ -10,6 +18,7 @@ group :development do
gem 'rcov', '~> 0.9.8' gem 'rcov', '~> 0.9.8'
gem 'rr', '~> 1.0.2' gem 'rr', '~> 1.0.2'
gem 'rspec', '~> 2.0' gem 'rspec', '~> 2.0'
gem 'ZenTest'
gem 'aws-s3' gem 'aws-s3'
gem "rubyzip" gem "rubyzip"
end end
+12 -2
View File
@@ -1,13 +1,14 @@
PATH PATH
remote: . remote: .
specs: specs:
foreman (0.35.0) foreman (0.37.0.pre4)
term-ansicolor (~> 1.0.5) term-ansicolor (~> 1.0.7)
thor (>= 0.13.6) thor (>= 0.13.6)
GEM GEM
remote: http://rubygems.org/ remote: http://rubygems.org/
specs: specs:
ZenTest (4.6.2)
aws-s3 (0.6.2) aws-s3 (0.6.2)
builder builder
mime-types mime-types
@@ -17,14 +18,17 @@ GEM
diff-lcs (1.1.3) diff-lcs (1.1.3)
fakefs (0.3.2) fakefs (0.3.2)
hpricot (0.8.2) hpricot (0.8.2)
hpricot (0.8.2-java)
mime-types (1.16) mime-types (1.16)
mustache (0.11.2) mustache (0.11.2)
parka (0.6.2) parka (0.6.2)
crack crack
rest-client rest-client
thor thor
posix-spawn (0.3.6)
rake (0.9.2.2) rake (0.9.2.2)
rcov (0.9.8) rcov (0.9.8)
rcov (0.9.8-java)
rdiscount (1.6.5) rdiscount (1.6.5)
rest-client (1.6.1) rest-client (1.6.1)
mime-types (>= 1.16) mime-types (>= 1.16)
@@ -44,19 +48,25 @@ GEM
rubyzip (0.9.4) rubyzip (0.9.4)
term-ansicolor (1.0.7) term-ansicolor (1.0.7)
thor (0.14.6) thor (0.14.6)
win32console (1.3.0-x86-mingw32)
xml-simple (1.0.15) xml-simple (1.0.15)
PLATFORMS PLATFORMS
java
ruby ruby
x86-mingw32
DEPENDENCIES DEPENDENCIES
ZenTest
aws-s3 aws-s3
fakefs (~> 0.3.2) fakefs (~> 0.3.2)
foreman! foreman!
parka parka
posix-spawn (~> 0.3.6)
rake rake
rcov (~> 0.9.8) rcov (~> 0.9.8)
ronn ronn
rr (~> 1.0.2) rr (~> 1.0.2)
rspec (~> 2.0) rspec (~> 2.0)
rubyzip rubyzip
win32console (~> 1.3.0)
+23 -34
View File
@@ -1,49 +1,38 @@
# Foreman # Foreman
## Installation Manage Procfile-based applications
* Rubygems <table>
<tr>
<th>If you have...</th>
<th>Install with...</th>
</tr>
<tr>
<td>Ruby (MRI, JRuby, Windows)</td>
<td><pre>$ gem install foreman</pre></td>
</tr>
<tr>
<td>Mac OS X</td>
<td><a href="http://assets.foreman.io/foreman/foreman.pkg">foreman.pkg</a></td>
</tr>
</table>
gem install foreman ## Getting Started
* OSX * http://blog.daviddollar.org/2011/05/06/introducing-foreman.html
http://assets.foreman.io/foreman/foreman.pkg ## Documentation
* Standalone Tarball
http://assets.foreman.io/foreman/foreman.tgz
## Description
http://blog.daviddollar.org/2011/05/06/introducing-foreman.html
## Manual
* [man page](http://ddollar.github.com/foreman) * [man page](http://ddollar.github.com/foreman)
* [wiki](http://github.com/ddollar/foreman/wiki) * [wiki](http://github.com/ddollar/foreman/wiki)
## Authorship ## Authors
Created by David Dollar #### Created and maintained by
David Dollar
Patches contributed by: #### Patches contributed by
Adam Wiggins, Chris Continanza, Chris Lowder, Craig R Webster, Dan Farina, Dan Peterson, David Dollar, Fletcher Nichol, Gabriel Burt, Gamaliel Toro, Greg Reinacker, Hugues Le Gendre, Hunter Nield, Iain Hecker, Jay Zeschin, Keith Rarick, Khaja Minhajuddin, Lincoln Stoll, Marcos Muino Garcia, Mark McGranaghan, Matt Griffin, Matt Haynes, Matthijs Langenberg, Michael Dwan, Michael van Rooijen, Mike Javorski, Nathan Broadbent, Nathan L Smith, Nick Zadrozny, Phil Hagelberg, Ricardo Chimal, Jr, Thom May, Tom Ward, brainopia, clifff, jc00ke
* Adam Wiggins
* Dan Peterson
* Hunter Nield
* Jay Zeschin
* Keith Rarick
* Khaja Minhajuddin
* Matt Haynes
* Michael van Rooijen
* Mike Javorski
* Nathan L Smith
* Nick Zadrozny
* Ricardo Chimal, Jr
* Thom May
* clifff
* Greg Reinacker
## License ## License
+11 -6
View File
@@ -1,7 +1,3 @@
require "rubygems"
require "bundler"
Bundler.setup
require "rake" require "rake"
require "rspec" require "rspec"
require "rspec/core/rake_task" require "rspec/core/rake_task"
@@ -55,6 +51,11 @@ task :pages => "man:commit" do
} }
end end
task :authors do
authors = %x{ git log --pretty=format:"%an" | sort -u }.split("\n")
puts authors.join(", ")
end
## dist ## dist
require "erb" require "erb"
@@ -102,9 +103,13 @@ def clean(file)
rm file if File.exists?(file) rm file if File.exists?(file)
end end
def distribution_files def distribution_files(type=nil)
require "foreman/distribution" 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 end
def mkchdir(dir) def mkchdir(dir)
+35 -1
View File
@@ -1,2 +1,36 @@
#!/bin/sh #!/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
+1 -1
View File
@@ -5,7 +5,7 @@ Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/
<% engine.procfile.entries.each do |process| %> <% engine.procfile.entries.each do |process| %>
<% 1.upto(concurrency[process.name]) do |num| %> <% 1.upto(concurrency[process.name]) do |num| %>
<% port = engine.port_for(process, num, options[:port]) %> <% port = engine.port_for(process, num, self.port) %>
app.process("<%= process.name %>-<%=num%>") do |process| app.process("<%= process.name %>-<%=num%>") do |process|
process.start_command = "<%= process.command.gsub("$PORT", port.to_s) %>" process.start_command = "<%= process.command.gsub("$PORT", port.to_s) %>"
+48
View 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
View File
@@ -0,0 +1,14 @@
file pkg("foreman-#{version}-jruby.gem") => distribution_files do |t|
sh "env PLATFORM=java 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
+14
View File
@@ -0,0 +1,14 @@
file pkg("foreman-#{version}-mingw32.gem") => distribution_files do |t|
sh "env PLATFORM=mingw32 gem build foreman.gemspec"
sh "mv foreman-#{version}-mingw32.gem #{t.name}"
end
task "mingw32:build" => pkg("foreman-#{version}-mingw32.gem")
task "mingw32:clean" do
clean pkg("foreman-#{version}-mingw32.gem")
end
task "mingw32:release" => "mingw32:build" do |t|
sh "parka push -f #{pkg("foreman-#{version}-mingw32.gem")}"
end
+12
View 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
View 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
View 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-----
Vendored Executable
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
set -e
ln -sf /usr/local/foreman/bin/foreman /usr/bin/foreman
+11 -1
View File
@@ -16,6 +16,16 @@ Gem::Specification.new do |gem|
gem.files = Dir["**/*"].select { |d| d =~ %r{^(README|bin/|data/|ext/|lib/|spec/|test/)} } gem.files = Dir["**/*"].select { |d| d =~ %r{^(README|bin/|data/|ext/|lib/|spec/|test/)} }
gem.files << "man/foreman.1" 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' gem.add_dependency 'thor', '>= 0.13.6'
if ENV["PLATFORM"] == "java"
gem.add_dependency "posix-spawn", "~> 0.3.6"
gem.platform = Gem::Platform.new("java")
end
if ENV["PLATFORM"] == "mingw32"
gem.add_dependency "win32console", "~> 1.3.0"
gem.platform = Gem::Platform.new("mingw32")
end
end end
+8 -1
View File
@@ -14,5 +14,12 @@ module Foreman
File.expand_path("../../bin/runner", __FILE__) File.expand_path("../../bin/runner", __FILE__)
end end
end def self.jruby?
defined?(RUBY_PLATFORM) and RUBY_PLATFORM == "java"
end
def self.windows?
defined?(RUBY_PLATFORM) and RUBY_PLATFORM =~ /(win|w)32$/
end
end
+13 -8
View File
@@ -1,10 +1,14 @@
require "foreman" require "foreman"
require "foreman/helpers"
require "foreman/engine" require "foreman/engine"
require "foreman/export" require "foreman/export"
require "thor" require "thor"
require "yaml" require "yaml"
class Foreman::CLI < Thor class Foreman::CLI < Thor
include Foreman::Helpers
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
desc "start", "Start the application" desc "start", "Start the application"
@@ -42,16 +46,17 @@ class Foreman::CLI < Thor
def export(format, location=nil) def export(format, location=nil)
check_procfile! check_procfile!
formatter = case format begin
when "inittab" then Foreman::Export::Inittab require "foreman/export/#{ format.tr('-', '_') }"
when "upstart" then Foreman::Export::Upstart classy_format = classify(format)
when "bluepill" then Foreman::Export::Bluepill formatter = constantize("Foreman::Export::#{ classy_format }")
when "runit" then Foreman::Export::Runit rescue NameError => ex
else error "Unknown export format: #{format}." error "Unknown export format: #{format} (no class Foreman::Export::#{ classy_format })."
rescue LoadError => ex
error "Unknown export format: #{format} (unable to load file 'foreman/export/#{ format.tr('-', '_') }')."
end end
formatter.new(engine).export(location, options) formatter.new(location, engine, options).export
rescue Foreman::Export::Exception => ex rescue Foreman::Export::Exception => ex
error ex.message error ex.message
end end
+11 -9
View File
@@ -2,7 +2,6 @@ require "foreman"
require "foreman/process" require "foreman/process"
require "foreman/procfile" require "foreman/procfile"
require "foreman/utils" require "foreman/utils"
require "pty"
require "tempfile" require "tempfile"
require "timeout" require "timeout"
require "term/ansicolor" require "term/ansicolor"
@@ -74,7 +73,7 @@ private ######################################################################
def kill_all(signal="SIGTERM") def kill_all(signal="SIGTERM")
running_processes.each do |pid, process| running_processes.each do |pid, process|
info "sending #{signal} to pid #{pid}" info "sending #{signal} to pid #{pid}"
Process.kill(signal, pid) rescue Errno::ESRCH process.kill signal
end end
end end
@@ -89,11 +88,14 @@ private ######################################################################
def watch_for_output def watch_for_output
Thread.new do Thread.new do
require "win32console" if Foreman.windows?
begin begin
loop do loop do
rs, ws = IO.select(readers.values, [], [], 1) rs, ws = IO.select(readers.values, [], [], 1)
(rs || []).each do |r| (rs || []).each do |r|
ps, message = r.gets.split(",", 2) data = r.gets
next unless data
ps, message = data.split(",", 2)
color = colors[ps.split(".").first] color = colors[ps.split(".").first]
info message, ps, color info message, ps, color
end end
@@ -134,11 +136,6 @@ private ######################################################################
end end
end end
def error(message)
puts "ERROR: #{message}"
exit 1
end
def longest_process_name def longest_process_name
@longest_process_name ||= begin @longest_process_name ||= begin
longest = procfile.process_names.map { |name| name.length }.sort.last longest = procfile.process_names.map { |name| name.length }.sort.last
@@ -156,7 +153,7 @@ private ######################################################################
end end
def termtitle(title) def termtitle(title)
printf("\033]0;#{title}\007") printf("\033]0;#{title}\007") unless Foreman.windows?
end end
def running_processes def running_processes
@@ -217,6 +214,11 @@ private ######################################################################
def apply_environment! def apply_environment!
@environment.each { |k,v| ENV[k] = v } @environment.each { |k,v| ENV[k] = v }
end end
def error(message)
puts "ERROR: #{message}"
exit 1
end
end end
include Env include Env
+10 -3
View File
@@ -3,10 +3,17 @@ require "foreman/utils"
class Foreman::Export::Base class Foreman::Export::Base
attr_reader :engine attr_reader :location, :engine, :app, :log, :port, :user, :template, :concurrency
def initialize(engine) def initialize(location, engine, options={})
@engine = engine @location = location
@engine = engine
@app = options[:app]
@log = options[:log]
@port = options[:port]
@user = options[:user]
@template = options[:template]
@concurrency = Foreman::Utils.parse_concurrency(options[:concurrency])
end end
def export def export
+5 -7
View File
@@ -3,23 +3,21 @@ require "foreman/export"
class Foreman::Export::Bluepill < Foreman::Export::Base class Foreman::Export::Bluepill < Foreman::Export::Base
def export(location, options={}) def export
error("Must specify a location") unless location error("Must specify a location") unless location
FileUtils.mkdir_p location FileUtils.mkdir_p location
app = options[:app] || File.basename(engine.directory) app = self.app || File.basename(engine.directory)
user = options[:user] || app user = self.user || app
log_root = options[:log] || "/var/log/#{app}" log_root = self.log || "/var/log/#{app}"
template_root = options[:template] template_root = self.template
Dir["#{location}/#{app}.pill"].each do |file| Dir["#{location}/#{app}.pill"].each do |file|
say "cleaning up: #{file}" say "cleaning up: #{file}"
FileUtils.rm(file) FileUtils.rm(file)
end end
concurrency = Foreman::Utils.parse_concurrency(options[:concurrency])
master_template = export_template("bluepill", "master.pill.erb", template_root) master_template = export_template("bluepill", "master.pill.erb", template_root)
master_config = ERB.new(master_template).result(binding) master_config = ERB.new(master_template).result(binding)
write_file "#{location}/#{app}.pill", master_config write_file "#{location}/#{app}.pill", master_config
+6 -8
View File
@@ -2,20 +2,18 @@ require "foreman/export"
class Foreman::Export::Inittab < Foreman::Export::Base class Foreman::Export::Inittab < Foreman::Export::Base
def export(fname=nil, options={}) def export
app = options[:app] || File.basename(engine.directory) app = self.app || File.basename(engine.directory)
user = options[:user] || app user = self.user || app
log_root = options[:log] || "/var/log/#{app}" log_root = self.log || "/var/log/#{app}"
concurrency = Foreman::Utils.parse_concurrency(options[:concurrency])
inittab = [] inittab = []
inittab << "# ----- foreman #{app} processes -----" inittab << "# ----- foreman #{app} processes -----"
engine.procfile.entries.inject(1) do |index, process| engine.procfile.entries.inject(1) do |index, process|
1.upto(concurrency[process.name]) do |num| 1.upto(self.concurrency[process.name]) do |num|
id = app.slice(0, 2).upcase + sprintf("%02d", index) id = app.slice(0, 2).upcase + sprintf("%02d", index)
port = engine.port_for(process, num, options[:port]) port = engine.port_for(process, num, self.port)
inittab << "#{id}:4:respawn:/bin/su - #{user} -c 'PORT=#{port} #{process.command} >> #{log_root}/#{process.name}-#{num}.log 2>&1'" inittab << "#{id}:4:respawn:/bin/su - #{user} -c 'PORT=#{port} #{process.command} >> #{log_root}/#{process.name}-#{num}.log 2>&1'"
index += 1 index += 1
end end
+8 -10
View File
@@ -4,21 +4,19 @@ require "foreman/export"
class Foreman::Export::Runit < Foreman::Export::Base class Foreman::Export::Runit < Foreman::Export::Base
ENV_VARIABLE_REGEX = /([a-zA-Z_]+[a-zA-Z0-9_]*)=(\S+)/ ENV_VARIABLE_REGEX = /([a-zA-Z_]+[a-zA-Z0-9_]*)=(\S+)/
def export(location, options={}) def export
error("Must specify a location") unless location error("Must specify a location") unless location
app = options[:app] || File.basename(engine.directory) app = self.app || File.basename(engine.directory)
user = options[:user] || app user = self.user || app
log_root = options[:log] || "/var/log/#{app}" log_root = self.log || "/var/log/#{app}"
template_root = options[:template] template_root = self.template
concurrency = Foreman::Utils.parse_concurrency(options[:concurrency])
run_template = export_template('runit', 'run.erb', template_root) run_template = export_template('runit', 'run.erb', template_root)
log_run_template = export_template('runit', 'log_run.erb', template_root) log_run_template = export_template('runit', 'log_run.erb', template_root)
engine.procfile.entries.each do |process| engine.procfile.entries.each do |process|
1.upto(concurrency[process.name]) do |num| 1.upto(self.concurrency[process.name]) do |num|
process_directory = "#{location}/#{app}-#{process.name}-#{num}" process_directory = "#{location}/#{app}-#{process.name}-#{num}"
process_env_directory = "#{process_directory}/env" process_env_directory = "#{process_directory}/env"
process_log_directory = "#{process_directory}/log" process_log_directory = "#{process_directory}/log"
@@ -31,7 +29,7 @@ class Foreman::Export::Runit < Foreman::Export::Base
write_file "#{process_directory}/run", run write_file "#{process_directory}/run", run
FileUtils.chmod 0755, "#{process_directory}/run" FileUtils.chmod 0755, "#{process_directory}/run"
port = engine.port_for(process, num, options[:port]) port = engine.port_for(process, num, self.port)
environment_variables = {'PORT' => port}. environment_variables = {'PORT' => port}.
merge(engine.environment). merge(engine.environment).
merge(inline_variables(process.command)) merge(inline_variables(process.command))
@@ -51,7 +49,7 @@ class Foreman::Export::Runit < Foreman::Export::Base
private private
def create_directory(location) def create_directory(location)
say "creating: #{location}" say "creating: #{location}"
FileUtils.mkdir(location) FileUtils.mkdir_p(location)
end end
def inline_variables(command) def inline_variables(command)
+8 -10
View File
@@ -3,23 +3,21 @@ require "foreman/export"
class Foreman::Export::Upstart < Foreman::Export::Base class Foreman::Export::Upstart < Foreman::Export::Base
def export(location, options={}) def export
error("Must specify a location") unless location error("Must specify a location") unless location
FileUtils.mkdir_p location FileUtils.mkdir_p location
app = options[:app] || File.basename(engine.directory) app = self.app || File.basename(engine.directory)
user = options[:user] || app user = self.user || app
log_root = options[:log] || "/var/log/#{app}" log_root = self.log || "/var/log/#{app}"
template_root = options[:template] template_root = self.template
Dir["#{location}/#{app}*.conf"].each do |file| Dir["#{location}/#{app}*.conf"].each do |file|
say "cleaning up: #{file}" say "cleaning up: #{file}"
FileUtils.rm(file) FileUtils.rm(file)
end end
concurrency = Foreman::Utils.parse_concurrency(options[:concurrency])
master_template = export_template("upstart", "master.conf.erb", template_root) master_template = export_template("upstart", "master.conf.erb", template_root)
master_config = ERB.new(master_template).result(binding) master_config = ERB.new(master_template).result(binding)
write_file "#{location}/#{app}.conf", master_config write_file "#{location}/#{app}.conf", master_config
@@ -27,13 +25,13 @@ class Foreman::Export::Upstart < Foreman::Export::Base
process_template = export_template("upstart", "process.conf.erb", template_root) process_template = export_template("upstart", "process.conf.erb", template_root)
engine.procfile.entries.each do |process| engine.procfile.entries.each do |process|
next if (conc = concurrency[process.name]) < 1 next if (conc = self.concurrency[process.name]) < 1
process_master_template = export_template("upstart", "process_master.conf.erb", template_root) process_master_template = export_template("upstart", "process_master.conf.erb", template_root)
process_master_config = ERB.new(process_master_template).result(binding) process_master_config = ERB.new(process_master_template).result(binding)
write_file "#{location}/#{app}-#{process.name}.conf", process_master_config write_file "#{location}/#{app}-#{process.name}.conf", process_master_config
1.upto(concurrency[process.name]) do |num| 1.upto(self.concurrency[process.name]) do |num|
port = engine.port_for(process, num, options[:port]) port = engine.port_for(process, num, self.port)
process_config = ERB.new(process_template).result(binding) process_config = ERB.new(process_template).result(binding)
write_file "#{location}/#{app}-#{process.name}-#{num}.conf", process_config write_file "#{location}/#{app}-#{process.name}-#{num}.conf", process_config
end end
+50
View File
@@ -0,0 +1,50 @@
module Foreman::Helpers
# Copied whole sale from, https://github.com/defunkt/resque/
# Given a word with dashes, returns a camel cased version of it.
#
# classify('job-name') # => 'JobName'
def classify(dashed_word)
dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
end
# Tries to find a constant with the name specified in the argument string:
#
# constantize("Module") # => Module
# constantize("Test::Unit") # => Test::Unit
#
# The name is assumed to be the one of a top-level constant, no matter
# whether it starts with "::" or not. No lexical context is taken into
# account:
#
# C = 'outside'
# module M
# C = 'inside'
# C # => 'inside'
# constantize("C") # => 'outside', same as ::C
# end
#
# NameError is raised when the constant is unknown.
def constantize(camel_cased_word)
camel_cased_word = camel_cased_word.to_s
if camel_cased_word.include?('-')
camel_cased_word = classify(camel_cased_word)
end
names = camel_cased_word.split('::')
names.shift if names.empty? || names.first.empty?
constant = Object
names.each do |name|
args = Module.method(:const_get).arity != 1 ? [false] : []
if constant.const_defined?(name, *args)
constant = constant.const_get(name)
else
constant = constant.const_missing(name)
end
end
constant
end
end
+47 -19
View File
@@ -1,4 +1,5 @@
require "foreman" require "foreman"
require "rubygems"
class Foreman::Process class Foreman::Process
@@ -14,10 +15,8 @@ class Foreman::Process
end end
def run(pipe, basedir, environment) def run(pipe, basedir, environment)
Dir.chdir(basedir) do with_environment(environment.merge("PORT" => port.to_s)) do
with_environment(environment.merge("PORT" => port.to_s)) do run_process basedir, entry.command, pipe
run_process entry.command, pipe
end
end end
end end
@@ -25,21 +24,52 @@ class Foreman::Process
"%s.%s" % [ entry.name, num ] "%s.%s" % [ entry.name, num ]
end end
def kill(signal)
pid && Process.kill(signal, pid)
rescue Errno::ESRCH
false
end
def detach
pid && Process.detach(pid)
end
def alive?
kill(0)
end
def dead?
!alive?
end
private private
def fork_with_io(command) def fork_with_io(command, basedir)
reader, writer = IO.pipe reader, writer = IO.pipe
pid = fork do command = replace_command_env(command)
trap("INT", "IGNORE") pid = if Foreman.windows?
$stdout.reopen writer Dir.chdir(basedir) do
reader.close Process.spawn command, :out => writer, :err => writer
exec Foreman.runner, replace_command_env(command) end
elsif Foreman.jruby?
require "posix/spawn"
POSIX::Spawn.spawn(Foreman.runner, "-d", basedir, command, {
:out => writer, :err => writer
})
else
fork do
writer.sync = true
$stdout.reopen writer
$stderr.reopen writer
reader.close
exec Foreman.runner, "-d", basedir, command
end
end end
[ reader, pid ] [ reader, pid ]
end end
def run_process(command, pipe) def run_process(basedir, command, pipe)
io, @pid = fork_with_io(command) io, @pid = fork_with_io(command, basedir)
output pipe, "started with pid %d" % @pid output pipe, "started with pid %d" % @pid
Thread.new do Thread.new do
until io.eof? until io.eof?
@@ -57,12 +87,10 @@ private
end end
def with_environment(environment) def with_environment(environment)
old_env = ENV.each_pair.inject({}) { |h,(k,v)| h.update(k => v) } original = ENV.to_hash
environment.each { |k,v| ENV[k] = v } ENV.update environment
ret = yield yield
ENV.clear ensure
old_env.each { |k,v| ENV[k] = v} ENV.replace original
ret
end end
end end
+1 -1
View File
@@ -1,5 +1,5 @@
module Foreman module Foreman
VERSION = "0.35.0" VERSION = "0.37.0.pre4"
end end
+8 -4
View File
@@ -1,7 +1,7 @@
require "spec_helper" require "spec_helper"
require "foreman/cli" require "foreman/cli"
describe "Foreman::CLI" do describe "Foreman::CLI", :fakefs do
subject { Foreman::CLI.new } subject { Foreman::CLI.new }
describe "start" do describe "start" do
@@ -30,7 +30,9 @@ describe "Foreman::CLI" do
it "respects --env" do it "respects --env" do
write_procfile write_procfile
write_env("envfile") write_env("envfile")
mock.instance_of(Foreman::Export::Upstart).export("/upstart", { "env" => "envfile" }) mock_export = mock(Foreman::Export::Upstart)
mock(Foreman::Export::Upstart).new("/upstart", is_a(Foreman::Engine), { "env" => "envfile" }) { mock_export }
mock_export.export
foreman %{ export upstart /upstart --env envfile } foreman %{ export upstart /upstart --env envfile }
end end
end end
@@ -49,7 +51,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 (unable to load file 'foreman/export/invalidformatter').") do
subject.export("invalidformatter") subject.export("invalidformatter")
end end
end end
@@ -60,7 +62,9 @@ describe "Foreman::CLI" do
it "runs successfully" do it "runs successfully" do
dont_allow(subject).error dont_allow(subject).error
mock.instance_of(Foreman::Export::Upstart).export("/tmp/foo", {}) mock_export = mock(Foreman::Export::Upstart)
mock(Foreman::Export::Upstart).new("/tmp/foo", is_a(Foreman::Engine), {}) { mock_export }
mock_export.export
subject.export("upstart", "/tmp/foo") subject.export("upstart", "/tmp/foo")
end end
end end
+5 -5
View File
@@ -1,7 +1,7 @@
require "spec_helper" require "spec_helper"
require "foreman/engine" require "foreman/engine"
describe "Foreman::Engine" do describe "Foreman::Engine", :fakefs do
subject { Foreman::Engine.new("Procfile", {}) } subject { Foreman::Engine.new("Procfile", {}) }
describe "initialize" do describe "initialize" do
@@ -24,8 +24,8 @@ describe "Foreman::Engine" do
describe "start" do describe "start" do
it "forks the processes" do it "forks the processes" do
write_procfile write_procfile
mock.instance_of(Foreman::Process).run_process("./alpha", is_a(IO)) mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./alpha", is_a(IO))
mock.instance_of(Foreman::Process).run_process("./bravo", is_a(IO)) mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./bravo", is_a(IO))
mock(subject).watch_for_output mock(subject).watch_for_output
mock(subject).watch_for_termination mock(subject).watch_for_termination
subject.start subject.start
@@ -34,8 +34,8 @@ describe "Foreman::Engine" do
it "handles concurrency" do it "handles concurrency" do
write_procfile write_procfile
engine = Foreman::Engine.new("Procfile",:concurrency => "alpha=2") 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(Dir.pwd, "./alpha", is_a(IO)).twice
mock.instance_of(Foreman::Process).run_process("./bravo", is_a(IO)).never mock.instance_of(Foreman::Process).run_process(Dir.pwd, "./bravo", is_a(IO)).never
mock(engine).watch_for_output mock(engine).watch_for_output
mock(engine).watch_for_termination mock(engine).watch_for_termination
engine.start engine.start
+12 -7
View File
@@ -3,22 +3,27 @@ require "foreman/engine"
require "foreman/export/bluepill" require "foreman/export/bluepill"
require "tmpdir" require "tmpdir"
describe Foreman::Export::Bluepill do describe Foreman::Export::Bluepill, :fakefs do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") } let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:engine) { Foreman::Engine.new(procfile) } let(:engine) { Foreman::Engine.new(procfile) }
let(:bluepill) { Foreman::Export::Bluepill.new(engine) } let(:options) { Hash.new }
let(:bluepill) { Foreman::Export::Bluepill.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("bluepill") } before(:each) { load_export_templates_into_fakefs("bluepill") }
before(:each) { stub(bluepill).say } before(:each) { stub(bluepill).say }
it "exports to the filesystem" do it "exports to the filesystem" do
bluepill.export("/tmp/init") bluepill.export
normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app.pill")) 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 context "with concurrency" do
bluepill.export("/tmp/init", :concurrency => "alpha=2") let(:options) { Hash[:concurrency => "alpha=2"] }
normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app-concurrency.pill")) it "exports to the filesystem with concurrency" do
bluepill.export
normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app-concurrency.pill"))
end
end end
end end
+8 -3
View File
@@ -3,10 +3,10 @@ require "foreman/engine"
require "foreman/export/runit" require "foreman/export/runit"
require "tmpdir" require "tmpdir"
describe Foreman::Export::Runit do describe Foreman::Export::Runit, :fakefs do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", 'bar=baz') } let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", 'bar=baz') }
let(:engine) { Foreman::Engine.new(procfile) } let(:engine) { Foreman::Engine.new(procfile) }
let(:runit) { Foreman::Export::Runit.new(engine) } let(:runit) { Foreman::Export::Runit.new('/tmp/init', engine, :concurrency => 'alpha=2,bravo=1') }
before(:each) { load_export_templates_into_fakefs("runit") } before(:each) { load_export_templates_into_fakefs("runit") }
before(:each) { stub(runit).say } before(:each) { stub(runit).say }
@@ -14,7 +14,8 @@ describe Foreman::Export::Runit do
it "exports to the filesystem" do it "exports to the filesystem" do
FileUtils.mkdir_p('/tmp/init') FileUtils.mkdir_p('/tmp/init')
runit.export('/tmp/init', :concurrency => "alpha=2,bravo=1")
runit.export
File.read("/tmp/init/app-alpha-1/run").should == example_export_file('runit/app-alpha-1-run') 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 == File.read("/tmp/init/app-alpha-1/log/run").should ==
@@ -33,4 +34,8 @@ describe Foreman::Export::Runit do
example_export_file('runit/app-bravo-1-log-run') example_export_file('runit/app-bravo-1-log-run')
File.read("/tmp/init/app-bravo-1/env/PORT").should == "5100\n" File.read("/tmp/init/app-bravo-1/env/PORT").should == "5100\n"
end end
it "creates a full path to the export directory" do
expect { runit.export }.to_not raise_error(Errno::ENOENT)
end
end end
+19 -13
View File
@@ -3,16 +3,17 @@ require "foreman/engine"
require "foreman/export/upstart" require "foreman/export/upstart"
require "tmpdir" require "tmpdir"
describe Foreman::Export::Upstart do describe Foreman::Export::Upstart, :fakefs do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") } let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:engine) { Foreman::Engine.new(procfile) } let(:engine) { Foreman::Engine.new(procfile) }
let(:upstart) { Foreman::Export::Upstart.new(engine) } let(:options) { Hash.new }
let(:upstart) { Foreman::Export::Upstart.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("upstart") } before(:each) { load_export_templates_into_fakefs("upstart") }
before(:each) { stub(upstart).say } before(:each) { stub(upstart).say }
it "exports to the filesystem" do it "exports to the filesystem" do
upstart.export("/tmp/init") upstart.export
File.read("/tmp/init/app.conf").should == example_export_file("upstart/app.conf") 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.conf").should == example_export_file("upstart/app-alpha.conf")
@@ -21,18 +22,23 @@ describe Foreman::Export::Upstart do
File.read("/tmp/init/app-bravo-1.conf").should == example_export_file("upstart/app-bravo-1.conf") File.read("/tmp/init/app-bravo-1.conf").should == example_export_file("upstart/app-bravo-1.conf")
end end
it "exports to the filesystem with concurrency" do context "with concurrency" do
upstart.export("/tmp/init", :concurrency => "alpha=2") let(:options) { Hash[:concurrency => "alpha=2"] }
File.read("/tmp/init/app.conf").should == example_export_file("upstart/app.conf") it "exports to the filesystem with concurrency" do
File.read("/tmp/init/app-alpha.conf").should == example_export_file("upstart/app-alpha.conf") upstart.export
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.conf").should == example_export_file("upstart/app.conf")
File.exists?("/tmp/init/app-bravo-1.conf").should == false 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.exists?("/tmp/init/app-bravo-1.conf").should == false
end
end end
context "with alternate templates" do context "with alternate templates" do
let(:template_root) { "/tmp/alternate" } let(:template_root) { "/tmp/alternate" }
let(:upstart) { Foreman::Export::Upstart.new("/tmp/init", engine, :template => template_root) }
before do before do
FileUtils.mkdir_p template_root FileUtils.mkdir_p template_root
@@ -40,7 +46,7 @@ describe Foreman::Export::Upstart do
end end
it "can export with alternate template files" do it "can export with alternate template files" do
upstart.export("/tmp/init", :template => template_root) upstart.export
File.read("/tmp/init/app.conf").should == "alternate_template\n" File.read("/tmp/init/app.conf").should == "alternate_template\n"
end end
@@ -61,7 +67,7 @@ describe Foreman::Export::Upstart do
end end
it "can export with alternate template files" do it "can export with alternate template files" do
upstart.export("/tmp/init") upstart.export
File.read("/tmp/init/app.conf").should == "default_alternate_template\n" File.read("/tmp/init/app.conf").should == "default_alternate_template\n"
end end
+131 -2
View File
@@ -1,2 +1,131 @@
require "spec_helper" require 'spec_helper'
require "foreman/process" require 'foreman/process'
require 'ostruct'
require 'timeout'
require 'tmpdir'
describe Foreman::Process do
subject { described_class.new entry, number, port }
let(:number) { 1 }
let(:port) { 777 }
let(:command) { "script" }
let(:name) { "foobar" }
let(:entry) { OpenStruct.new :name => name, :command => command }
its(:entry) { entry }
its(:num) { number }
its(:port) { port }
its(:name) { "#{name}.#{port}" }
its(:pid) { nil }
describe '#run' do
let(:pipe) { :pipe }
let(:basedir) { Dir.mktmpdir }
let(:env) {{ 'foo' => 'bar' }}
let(:init_delta) { 0.1 }
after { FileUtils.remove_entry_secure basedir }
def run(cmd=command)
entry.command = cmd
subject.run pipe, basedir, env
subject.detach && sleep(init_delta)
end
def run_file(executable, code)
file = File.open("#{basedir}/script", 'w') {|it| it << code }
run "#{executable} #{file.path}"
end
context 'options' do
it 'should set PORT for environment' do
mock(subject).run_process(basedir, command, pipe) do
ENV['PORT'].should == port.to_s
end
run
end
it 'should set custom variables for environment' do
mock(subject).run_process(basedir, command, pipe) do
ENV['foo'].should == 'bar'
end
run
end
it 'should restore environment afterwards' do
mock(subject).run_process(basedir, command, pipe)
run
ENV.should_not include('PORT', 'foo')
end
end
context 'process' do
around do |spec|
IO.pipe do |reader, writer|
@reader, @writer = reader, writer
spec.run
end
end
let(:pipe) { @writer }
let(:output) { @reader.read_nonblock 1024 }
it 'should not block' do
expect {
Timeout.timeout(2*init_delta) { run 'sleep 2' }
}.should_not raise_exception
end
it 'should be alive' do
run 'sleep 1'
subject.should be_alive
end
it 'should be dead' do
run 'exit'
subject.should be_dead
end
it 'should be killable' do
run 'sleep 1'
subject.kill 'TERM'
subject.should be_dead
end
it 'should send different signals' do
run_file 'ruby', <<-CODE
trap "TERM", "IGNORE"
loop { sleep 1 }
CODE
sleep 1 # wait for ruby to start
subject.should be_alive
subject.kill 'TERM'
subject.should be_alive
subject.kill 'KILL'
subject.should be_dead
end
it 'should redirect stdout' do
run 'echo hey'
output.should include('hey')
end
it 'should redirect stderr' do
run 'echo hey >2'
output.should include('hey')
end
it 'should handle variables' do
run 'echo $PORT'
output.should include('777')
end
it 'should handle arguments' do
pending
run %{ sh -c "trap '' TERM; sleep 10" }
subject.should be_alive
end
end
end
end
+1 -6
View File
@@ -8,13 +8,8 @@ describe Foreman do
it { should be_a String } it { should be_a String }
end end
describe "::load_env!(env_file)" do describe "::load_env!(env_file)", :fakefs do
before do
FakeFS.activate!
end
after do after do
FakeFS.deactivate!
ENV['FOO'] = nil ENV['FOO'] = nil
end end
+2 -1
View File
@@ -78,8 +78,9 @@ def normalize_space(s)
end end
RSpec.configure do |config| RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
config.color_enabled = true config.color_enabled = true
config.order = 'rand' config.order = 'rand'
config.include FakeFS::SpecHelpers config.include FakeFS::SpecHelpers, :fakefs
config.mock_with :rr config.mock_with :rr
end end