Compare commits

...
92 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
David Dollar 2bfc065c1d update rake 2012-01-16 18:35:06 -05:00
David Dollar fbe3d4ec69 0.35.0 2012-01-16 18:34:36 -05:00
David Dollar 631187e0d8 Merge pull request #132 from Viximo/feature/concurrency
Change default concurrency to 0 when concurrency is provided
2012-01-16 15:13:27 -08:00
Matt Griffin 92d1a4d367 Fix export specs 2012-01-16 17:39:21 -05:00
Matt Griffin f4123f4ae1 Merge branch 'master' of https://github.com/michaeldwan/foreman into feature/concurrency
Conflicts:
	spec/foreman/engine_spec.rb
	spec/foreman/export/bluepill_spec.rb
	spec/resources/export/bluepill/app.pill
2012-01-16 17:18:14 -05:00
David Dollar d4c2332c59 0.34.1 2012-01-16 09:53:56 -05:00
David Dollar e257fc89c1 fix missing start desc 2012-01-16 09:53:43 -05:00
David Dollar a278755ae4 0.34.0 2012-01-16 09:42:07 -05:00
David Dollar 3367a060a7 update man page 2012-01-16 09:41:36 -05:00
David Dollar ac7e0743ac update docs for -d 2012-01-16 09:39:54 -05:00
David Dollar e574880814 Merge pull request #101 from ndbroadbent/foreman
---

I just discovered the LiveReload gem, and wanted to use foreman to help me set up my development environments.

I didnt want to check in my custom development Procfiles, so I needed to alter the behaviour of:

> [The Procfiles] containing directory will be assumed to be the root directory of the application.

Ive set up some shared `Procfiles` for development, such as `Rails3Dev`, `Rails31Dev`, `JekyllDev`, etc.

Then I set up a bash alias for each of these Procfiles, such as:

```bash
alias rd31="foreman start -d . -f ~/dev/procfiles/Rails31Dev"
```

The only thing missing was the `-d` flag.

My `Rails31Dev` file looks like this:

```yaml
compass: compass watch --sass-dir app/assets/stylesheets --css-dir public/assets
livereload: livereload
passenger: passenger start
```

Thanks!

Conflicts:
	lib/foreman/cli.rb
2012-01-16 09:38:25 -05:00
Craig R Webster 7132cacbf6 Wrap around to the first colour when all the colours are used 2012-01-16 09:35:51 -05:00
David Dollar c1f279aa6f run specs in random order 2012-01-16 09:33:34 -05:00
David Dollar 34cfe9ef9d update rspec 2012-01-16 09:33:34 -05:00
David Dollar 79fc3b8029 pedantry 2012-01-16 09:33:34 -05:00
Matthijs Langenberg 91140638e1 Set executable bit on runit run scripts. 2012-01-16 09:33:34 -05:00
David Dollar 48cc60c30f Merge pull request #114 from gburt/master
add more colors
2012-01-16 06:21:28 -08:00
David Dollar 533139ea9f 0.33.1 2012-01-16 09:18:48 -05:00
David Dollar 86e2056a24 Merge pull request #129 from fnichol/resolve-home-template
Expand template path under user's home directory (foreman export).
2012-01-16 06:17:43 -08:00
Fletcher Nichol ab29963ee4 Expand template path under user's home directory.
* File.join won't expand `~` into `ENV['HOME']`
  (http://ruby-doc.org/core-1.9.3/File.html#method-c-expand_path)
* The FakeFS File.exists? implementation calls FileSystem#find
  (https://github.com/defunkt/fakefs/blob/master/lib/fakefs/file_system.rb#L22-33)
  containing a call to FileSystem#normalize_path which expands the
  path variable passed in
  (https://github.com/defunkt/fakefs/blob/master/lib/fakefs/file_system.rb#L91-98)
* The file system mocking library sets up a false expectation that `~`
  will be expanded in the #export_template method and consequently the
  production code can't use the template directory
* To guard against future regressions such as fixes/updates to FakeFS or
  using an alternate file system mocking library, the specs were updated
  to explicitly set `ENV['HOME']`
2012-01-15 19:09:52 -07:00
Gabriel Burt 5de1bd18ac add more colors 2011-12-30 13:55:46 -06:00
Nathan Broadbent 8bc8cb4b2e Added option to specify app_root, if executing a Procfile from a shared location 2011-12-03 15:16:06 +08:00
Michael Dwan 33aa1efc90 default process concurrency is 0 when concurrency options specified, otherwise default concurrency is 1 2011-11-07 13:10:18 -07:00
42 changed files with 723 additions and 224 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
+10 -1
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'
@@ -9,7 +17,8 @@ group :development do
gem 'fakefs', '~> 0.3.2' gem 'fakefs', '~> 0.3.2'
gem 'rcov', '~> 0.9.8' gem 'rcov', '~> 0.9.8'
gem 'rr', '~> 1.0.2' gem 'rr', '~> 1.0.2'
gem 'rspec', '~> 2.6.0' gem 'rspec', '~> 2.0'
gem 'ZenTest'
gem 'aws-s3' gem 'aws-s3'
gem "rubyzip" gem "rubyzip"
end end
+22 -12
View File
@@ -1,30 +1,34 @@
PATH PATH
remote: . remote: .
specs: specs:
foreman (0.33.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
xml-simple xml-simple
builder (3.0.0) builder (3.0.0)
crack (0.1.8) crack (0.1.8)
diff-lcs (1.1.2) 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
rake (0.9.2) posix-spawn (0.3.6)
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)
@@ -33,30 +37,36 @@ GEM
mustache (>= 0.7.0) mustache (>= 0.7.0)
rdiscount (>= 1.5.8) rdiscount (>= 1.5.8)
rr (1.0.2) rr (1.0.2)
rspec (2.6.0) rspec (2.8.0)
rspec-core (~> 2.6.0) rspec-core (~> 2.8.0)
rspec-expectations (~> 2.6.0) rspec-expectations (~> 2.8.0)
rspec-mocks (~> 2.6.0) rspec-mocks (~> 2.8.0)
rspec-core (2.6.4) rspec-core (2.8.0)
rspec-expectations (2.6.0) rspec-expectations (2.8.0)
diff-lcs (~> 1.1.2) diff-lcs (~> 1.1.2)
rspec-mocks (2.6.0) rspec-mocks (2.8.0)
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.6.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
+19 -13
View File
@@ -1,15 +1,20 @@
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" class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
desc "start", "Start the application" 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 :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
method_option :port, :type => :numeric, :aliases => "-p" method_option :port, :type => :numeric, :aliases => "-p"
method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"' method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"'
@@ -21,7 +26,7 @@ class Foreman::CLI < Thor
super super
end end
end end
def start def start
check_procfile! check_procfile!
engine.start engine.start
@@ -41,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
@@ -61,7 +67,7 @@ class Foreman::CLI < Thor
error "no processes defined" unless engine.procfile.entries.length > 0 error "no processes defined" unless engine.procfile.entries.length > 0
display "valid procfile detected (#{engine.procfile.process_names.join(', ')})" display "valid procfile detected (#{engine.procfile.process_names.join(', ')})"
end end
desc "run COMMAND", "Run a command using your application's environment" desc "run COMMAND", "Run a command using your application's environment"
def run(*args) def run(*args)
@@ -74,7 +80,7 @@ class Foreman::CLI < Thor
error "command not found: #{args.first}" error "command not found: #{args.first}"
end end
end end
private ###################################################################### private ######################################################################
def check_procfile! def check_procfile!
+17 -12
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"
@@ -17,11 +16,13 @@ class Foreman::Engine
extend Term::ANSIColor 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={}) def initialize(procfile, options={})
@procfile = Foreman::Procfile.new(procfile) @procfile = Foreman::Procfile.new(procfile)
@directory = File.expand_path(File.dirname(procfile)) @directory = options[:app_root] || File.expand_path(File.dirname(procfile))
@options = options @options = options
@environment = read_environment_files(options[:env]) @environment = read_environment_files(options[:env])
@output_mutex = Mutex.new @output_mutex = Mutex.new
@@ -72,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
@@ -87,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
@@ -132,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
@@ -154,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
@@ -182,7 +181,8 @@ private ######################################################################
def next_color def next_color
@current_color ||= -1 @current_color ||= -1
@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 end
module Env module Env
@@ -214,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
+11 -4
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
@@ -26,7 +33,7 @@ private ######################################################################
def export_template(exporter, file, template_root) def export_template(exporter, file, template_root)
if template_root && File.exist?(file_path = File.join(template_root, file)) if template_root && File.exist?(file_path = File.join(template_root, file))
File.read(file_path) 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) File.read(file_path)
else else
File.read(File.expand_path("../../../../data/export/#{exporter}/#{file}", __FILE__)) File.read(File.expand_path("../../../../data/export/#{exporter}/#{file}", __FILE__))
+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
+10 -11
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"
@@ -29,8 +27,9 @@ class Foreman::Export::Runit < Foreman::Export::Base
run = ERB.new(run_template).result(binding) run = ERB.new(run_template).result(binding)
write_file "#{process_directory}/run", run write_file "#{process_directory}/run", 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))
@@ -41,7 +40,7 @@ class Foreman::Export::Runit < Foreman::Export::Base
log_run = ERB.new(log_run_template).result(binding) log_run = ERB.new(log_run_template).result(binding)
write_file "#{process_log_directory}/run", log_run write_file "#{process_log_directory}/run", log_run
FileUtils.chmod 0755, "#{process_log_directory}/run"
end end
end end
@@ -50,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
+4 -1
View File
@@ -5,7 +5,10 @@ class Foreman::Utils
def self.parse_concurrency(concurrency) def self.parse_concurrency(concurrency)
begin begin
pairs = concurrency.to_s.gsub(/\s/, "").split(",") 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("=") process, amount = pair.split("=")
hash.update(process => amount.to_i) hash.update(process => amount.to_i)
end end
+1 -1
View File
@@ -1,5 +1,5 @@
module Foreman module Foreman
VERSION = "0.33.0" VERSION = "0.37.0.pre4"
end end
+5 -1
View File
@@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.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" .SH "NAME"
\fBforeman\fR \- manage Procfile\-based applications \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\. These options control all modes of foreman\'s operation\.
. .
.TP .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 \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\. Specify an alternate environment file\. You can specify more than one file by using: \fB\-\-env file1,file2\fR\.
. .
+4
View File
@@ -66,6 +66,10 @@ The following options control how the application is run:
These options control all modes of foreman's operation. These options control all modes of foreman's operation.
* `-d`, `--directory`:
Specify an alternate application root. This defaults to the directory
containing the Procfile.
* `-e`, `--env`: * `-e`, `--env`:
Specify an alternate environment file. You can specify more than one Specify an alternate environment file. You can specify more than one
file by using: `--env file1,file2`. file by using: `--env file1,file2`.
+17 -13
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
@@ -89,47 +93,47 @@ describe "Foreman::CLI" do
end end
end end
end end
describe "run" do describe "run" do
describe "with a valid Procfile" do describe "with a valid Procfile" do
before { write_procfile } before { write_procfile }
describe "and a command" do describe "and a command" do
let(:command) { ["ls", "-l"] } let(:command) { ["ls", "-l"] }
before(:each) do before(:each) do
stub(subject).exec stub(subject).exec
end end
it "should load the environment file" do it "should load the environment file" do
write_env write_env
preserving_env do preserving_env do
subject.run *command subject.run *command
ENV["FOO"].should == "bar" ENV["FOO"].should == "bar"
end end
ENV["FOO"].should be_nil ENV["FOO"].should be_nil
end end
it "should runute the command as a string" do it "should runute the command as a string" do
mock(subject).exec(command.join(" ")) mock(subject).exec(command.join(" "))
subject.run *command subject.run *command
end end
end end
describe "and a non-existent command" do describe "and a non-existent command" do
let(:command) { "iuhtngrglhulhdfg" } let(:command) { "iuhtngrglhulhdfg" }
it "should print an error" do it "should print an error" do
mock_error(subject, "command not found: #{command}") do mock_error(subject, "command not found: #{command}") do
subject.run command subject.run command
end end
end end
end end
describe "and a non-executable command" do describe "and a non-executable command" do
let(:command) { __FILE__ } let(:command) { __FILE__ }
it "should print an error" do it "should print an error" do
mock_error(subject, "not executable: #{command}") do mock_error(subject, "not executable: #{command}") do
subject.run command subject.run command
+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)) 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
+15 -5
View File
@@ -3,17 +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", :concurrency => "alpha=2") bluepill.export
File.read("/tmp/init/app.pill").should == example_export_file("bluepill/app.pill") normalize_space(File.read("/tmp/init/app.pill")).should == normalize_space(example_export_file("bluepill/app.pill"))
end
context "with concurrency" do
let(:options) { Hash[:concurrency => "alpha=2"] }
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
+18 -12
View File
@@ -3,33 +3,39 @@ 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 }
before(:each) { stub(FakeFS::FileUtils).chmod }
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')
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 ==
example_export_file('runit/app-alpha-1-log-run') example_export_file('runit/app-alpha-1-log-run')
File.read("/tmp/init/app-alpha-1/env/PORT").should == "5000\n" File.read("/tmp/init/app-alpha-1/env/PORT").should == "5000\n"
File.read("/tmp/init/app-alpha-1/env/BAR").should == "baz\n" File.read("/tmp/init/app-alpha-1/env/BAR").should == "baz\n"
File.read("/tmp/init/app-alpha-2/run").should == example_export_file('runit/app-alpha-2-run') File.read("/tmp/init/app-alpha-2/run").should == example_export_file('runit/app-alpha-2-run')
File.read("/tmp/init/app-alpha-2/log/run").should == File.read("/tmp/init/app-alpha-2/log/run").should ==
example_export_file('runit/app-alpha-2-log-run') example_export_file('runit/app-alpha-2-log-run')
File.read("/tmp/init/app-alpha-2/env/PORT").should == "5001\n" File.read("/tmp/init/app-alpha-2/env/PORT").should == "5001\n"
File.read("/tmp/init/app-alpha-2/env/BAR").should == "baz\n" File.read("/tmp/init/app-alpha-2/env/BAR").should == "baz\n"
File.read("/tmp/init/app-bravo-1/run").should == example_export_file('runit/app-bravo-1-run') File.read("/tmp/init/app-bravo-1/run").should == example_export_file('runit/app-bravo-1-run')
File.read("/tmp/init/app-bravo-1/log/run").should == File.read("/tmp/init/app-bravo-1/log/run").should ==
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
end
it "creates a full path to the export directory" do
expect { runit.export }.to_not raise_error(Errno::ENOENT)
end
end
+29 -8
View File
@@ -3,27 +3,42 @@ 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", :concurrency => "alpha=2") 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")
File.read("/tmp/init/app-alpha-1.conf").should == example_export_file("upstart/app-alpha-1.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.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.read("/tmp/init/app-bravo-1.conf").should == example_export_file("upstart/app-bravo-1.conf")
end end
context "with concurrency" do
let(:options) { Hash[:concurrency => "alpha=2"] }
it "exports to the filesystem with concurrency" do
upstart.export
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.exists?("/tmp/init/app-bravo-1.conf").should == false
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
@@ -31,22 +46,28 @@ 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
end end
context "with alternate templates from home dir" do 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 before do
ENV['_FOREMAN_SPEC_HOME'] = ENV['HOME']
ENV['HOME'] = "/home/appuser"
FileUtils.mkdir_p default_template_root FileUtils.mkdir_p default_template_root
File.open("#{default_template_root}/master.conf.erb", "w") { |f| f.puts "default_alternate_template" } File.open("#{default_template_root}/master.conf.erb", "w") { |f| f.puts "default_alternate_template" }
end end
after do
ENV['HOME'] = ENV.delete('_FOREMAN_SPEC_HOME')
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
+2 -7
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
@@ -22,7 +17,7 @@ describe Foreman do
File.open("/tmp/env1", "w") { |f| f.puts("FOO=bar") } File.open("/tmp/env1", "w") { |f| f.puts("FOO=bar") }
Foreman.load_env!("/tmp/env1") Foreman.load_env!("/tmp/env1")
ENV['FOO'].should == 'bar' ENV['FOO'].should == 'bar'
end end
it "should assume env_file in ./.env" do it "should assume env_file in ./.env" do
File.open("./.env", "w") { |f| f.puts("FOO=bar") } File.open("./.env", "w") { |f| f.puts("FOO=bar") }
+3 -3
View File
@@ -3,16 +3,16 @@ require "spec_helper"
describe "spec helpers" do describe "spec helpers" do
describe "#preserving_env" do describe "#preserving_env" do
after { ENV.delete "FOO" } after { ENV.delete "FOO" }
it "should remove added environment vars" do it "should remove added environment vars" do
preserving_env { ENV["FOO"] = "baz" } preserving_env { ENV["FOO"] = "baz" }
ENV["FOO"].should == nil ENV["FOO"].should == nil
end end
it "should reset modified environment vars" do it "should reset modified environment vars" do
ENV["FOO"] = "bar" ENV["FOO"] = "bar"
preserving_env { ENV["FOO"] = "baz"} preserving_env { ENV["FOO"] = "baz"}
ENV["FOO"].should == "bar" ENV["FOO"].should == "bar"
end end
end end
end end
@@ -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
-21
View File
@@ -23,27 +23,6 @@ Bluepill.application("app", :foreground => false, :log_file => "/var/log/bluepil
process.group = "app-alpha" process.group = "app-alpha"
end 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| app.process("bravo-1") do |process|
process.start_command = "./bravo" process.start_command = "./bravo"
+7 -1
View File
@@ -73,8 +73,14 @@ def preserving_env
end end
end end
def normalize_space(s)
s.gsub(/\n[\n\s]*/, "\n")
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.include FakeFS::SpecHelpers config.order = 'rand'
config.include FakeFS::SpecHelpers, :fakefs
config.mock_with :rr config.mock_with :rr
end end