foreman-0.85.0/ 0000755 0000041 0000041 00000000000 13312112240 013250 5 ustar www-data www-data foreman-0.85.0/README.md 0000644 0000041 0000041 00000003343 13312112240 014532 0 ustar www-data www-data # Foreman
[](https://travis-ci.org/ddollar/foreman)
[](https://codeclimate.com/github/ddollar/foreman)
[](http://inch-ci.org/github/ddollar/foreman)
Manage Procfile-based applications
## Installation
$ gem install foreman
Ruby users should take care *not* to install foreman in their project's `Gemfile`.
## Getting Started
* http://blog.daviddollar.org/2011/05/06/introducing-foreman.html
## Supported Ruby versions
See [.travis.yml](.travis.yml) for a list of Ruby versions against which Foreman is tested.
## Documentation
* [man page](http://ddollar.github.io/foreman/)
* [wiki](https://github.com/ddollar/foreman/wiki)
* [changelog](https://github.com/ddollar/foreman/blob/master/Changelog.md)
## Ports
* [forego](https://github.com/ddollar/forego) - Go
* [node-foreman](https://github.com/strongloop/node-foreman) - Node.js
* [gaffer](https://github.com/jingweno/gaffer) - Java/JVM
* [goreman](https://github.com/mattn/goreman) - Go
* [honcho](https://github.com/nickstenning/honcho) - python
* [proclet](https://github.com/kazeburo/Proclet) - Perl
* [shoreman](https://github.com/chrismytton/shoreman) - shell
* [crank](https://github.com/arktisklada/crank) - Crystal
* [houseman](https://github.com/fujimura/houseman) - Haskell
* [spm](https://github.com/bytegust/spm) - Go
## Authors
#### Created and maintained by
David Dollar
#### Patches contributed by
[Contributor List](https://github.com/ddollar/foreman/contributors)
## License
Foreman is licensed under the MIT license.
See LICENSE for the full license text.
foreman-0.85.0/bin/ 0000755 0000041 0000041 00000000000 13312112240 014020 5 ustar www-data www-data foreman-0.85.0/bin/foreman-runner 0000755 0000041 0000041 00000001161 13312112240 016703 0 ustar www-data www-data #!/bin/sh
#
#/ Usage: foreman-runner [-d
] [-p] [...]
#/
#/ Run a command with exec, optionally changing directory first
set -e
error() {
echo $@ >&2
exit 1
}
usage() {
cat $0 | grep '^#/' | cut -c4-
exit
}
read_profile=""
while getopts ":hd:p" OPT; do
case $OPT in
d) cd "$OPTARG" ;;
p) read_profile="1" ;;
h) usage ;;
\?) error "invalid option: -$OPTARG" ;;
:) error "option -$OPTARG requires an argument" ;;
esac
done
shift $((OPTIND-1))
[ -z "$1" ] && usage
if [ "$read_profile" = "1" ]; then
if [ -f .profile ]; then
. ./.profile
fi
fi
exec "$@"
foreman-0.85.0/bin/foreman 0000755 0000041 0000041 00000000163 13312112240 015375 0 ustar www-data www-data #!/usr/bin/env ruby
$:.unshift File.expand_path("../../lib", __FILE__)
require "foreman/cli"
Foreman::CLI.start
foreman-0.85.0/spec/ 0000755 0000041 0000041 00000000000 13312112240 014202 5 ustar www-data www-data foreman-0.85.0/spec/helper_spec.rb 0000644 0000041 0000041 00000000702 13312112240 017017 0 ustar www-data www-data require "spec_helper"
describe "spec helpers" do
describe "#preserving_env" do
after { ENV.delete "FOO" }
it "should remove added environment vars" do
old = ENV["FOO"]
preserving_env { ENV["FOO"] = "baz" }
expect(ENV["FOO"]).to eq(old)
end
it "should reset modified environment vars" do
ENV["FOO"] = "bar"
preserving_env { ENV["FOO"] = "baz"}
expect(ENV["FOO"]).to eq("bar")
end
end
end
foreman-0.85.0/spec/resources/ 0000755 0000041 0000041 00000000000 13312112240 016214 5 ustar www-data www-data foreman-0.85.0/spec/resources/Procfile.bad 0000644 0000041 0000041 00000000031 13312112240 020421 0 ustar www-data www-data good: sleep 1
bad: false
foreman-0.85.0/spec/resources/bin/ 0000755 0000041 0000041 00000000000 13312112240 016764 5 ustar www-data www-data foreman-0.85.0/spec/resources/bin/test 0000755 0000041 0000041 00000000031 13312112240 017663 0 ustar www-data www-data #!/bin/sh
echo "testing"
foreman-0.85.0/spec/resources/bin/echo 0000755 0000041 0000041 00000000022 13312112240 017622 0 ustar www-data www-data #!/bin/sh
echo $*
foreman-0.85.0/spec/resources/bin/utf8 0000755 0000041 0000041 00000000044 13312112240 017576 0 ustar www-data www-data #!/usr/bin/env ruby
puts "\xff\x03"
foreman-0.85.0/spec/resources/bin/env 0000755 0000041 0000041 00000000027 13312112240 017501 0 ustar www-data www-data #!/bin/bash
echo ${!1}
foreman-0.85.0/spec/resources/export/ 0000755 0000041 0000041 00000000000 13312112240 017535 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/inittab/ 0000755 0000041 0000041 00000000000 13312112240 021167 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/inittab/inittab.default 0000644 0000041 0000041 00000000764 13312112240 024176 0 ustar www-data www-data # ----- foreman app processes -----
AP01:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5000;./alpha >> /var/log/app/alpha-1.log 2>&1'
AP02:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5100;./bravo >> /var/log/app/bravo-1.log 2>&1'
AP03:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5200;./foo_bar >> /var/log/app/foo_bar-1.log 2>&1'
AP04:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5300;./foo-bar >> /var/log/app/foo-bar-1.log 2>&1'
# ----- end foreman app processes -----
foreman-0.85.0/spec/resources/export/inittab/inittab.concurrency 0000644 0000041 0000041 00000000434 13312112240 025076 0 ustar www-data www-data # ----- foreman app processes -----
AP01:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5000;./alpha >> /var/log/app/alpha-1.log 2>&1'
AP02:4:respawn:/bin/su - app -c 'cd /tmp/app;export PORT=5001;./alpha >> /var/log/app/alpha-2.log 2>&1'
# ----- end foreman app processes -----
foreman-0.85.0/spec/resources/export/systemd/ 0000755 0000041 0000041 00000000000 13312112240 021225 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/systemd/app-alpha.target 0000644 0000041 0000041 00000000031 13312112240 024272 0 ustar www-data www-data [Unit]
PartOf=app.target
foreman-0.85.0/spec/resources/export/systemd/app.target 0000644 0000041 0000041 00000000173 13312112240 023216 0 ustar www-data www-data [Unit]
Wants=app-alpha.target app-bravo.target app-foo_bar.target app-foo-bar.target
[Install]
WantedBy=multi-user.target
foreman-0.85.0/spec/resources/export/systemd/app-bravo@.service 0000644 0000041 0000041 00000000411 13312112240 024572 0 ustar www-data www-data [Unit]
PartOf=app-bravo.target
[Service]
User=app
WorkingDirectory=/tmp/app
Environment=PORT=%i
ExecStart=/bin/bash -lc 'exec ./bravo'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=mixed
TimeoutStopSec=5
foreman-0.85.0/spec/resources/export/systemd/app-alpha@.service 0000644 0000041 0000041 00000000411 13312112240 024546 0 ustar www-data www-data [Unit]
PartOf=app-alpha.target
[Service]
User=app
WorkingDirectory=/tmp/app
Environment=PORT=%i
ExecStart=/bin/bash -lc 'exec ./alpha'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=mixed
TimeoutStopSec=5
foreman-0.85.0/spec/resources/export/systemd/app-bravo.target 0000644 0000041 0000041 00000000031 13312112240 024316 0 ustar www-data www-data [Unit]
PartOf=app.target
foreman-0.85.0/spec/resources/export/supervisord/ 0000755 0000041 0000041 00000000000 13312112240 022122 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/supervisord/app-alpha-1.conf 0000644 0000041 0000041 00000002161 13312112240 024772 0 ustar www-data www-data [program:app-alpha-1]
command=./alpha
autostart=true
autorestart=true
stdout_logfile=/var/log/app/alpha-1.log
stderr_logfile=/var/log/app/alpha-1.error.log
user=app
directory=/tmp/app
environment=FOO="bar",URL="http://example.com/api?foo=bar&baz=1",PORT="5000"
[program:app-bravo-1]
command=./bravo
autostart=true
autorestart=true
stdout_logfile=/var/log/app/bravo-1.log
stderr_logfile=/var/log/app/bravo-1.error.log
user=app
directory=/tmp/app
environment=FOO="bar",URL="http://example.com/api?foo=bar&baz=1",PORT="5100"
[program:app-foo_bar-1]
command=./foo_bar
autostart=true
autorestart=true
stdout_logfile=/var/log/app/foo_bar-1.log
stderr_logfile=/var/log/app/foo_bar-1.error.log
user=app
directory=/tmp/app
environment=FOO="bar",URL="http://example.com/api?foo=bar&baz=1",PORT="5200"
[program:app-foo-bar-1]
command=./foo-bar
autostart=true
autorestart=true
stdout_logfile=/var/log/app/foo-bar-1.log
stderr_logfile=/var/log/app/foo-bar-1.error.log
user=app
directory=/tmp/app
environment=FOO="bar",URL="http://example.com/api?foo=bar&baz=1",PORT="5300"
[group:app]
programs=app-alpha-1,app-bravo-1,app-foo_bar-1,app-foo-bar-1
foreman-0.85.0/spec/resources/export/supervisord/app-alpha-2.conf 0000644 0000041 0000041 00000000717 13312112240 025000 0 ustar www-data www-data [program:app-alpha-1]
command=./alpha
autostart=true
autorestart=true
stdout_logfile=/var/log/app/alpha-1.log
stderr_logfile=/var/log/app/alpha-1.error.log
user=app
directory=/tmp/app
environment=PORT="5000"
[program:app-alpha-2]
command=./alpha
autostart=true
autorestart=true
stdout_logfile=/var/log/app/alpha-2.log
stderr_logfile=/var/log/app/alpha-2.error.log
user=app
directory=/tmp/app
environment=PORT="5001"
[group:app]
programs=app-alpha-1,app-alpha-2
foreman-0.85.0/spec/resources/export/runit/ 0000755 0000041 0000041 00000000000 13312112240 020676 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/runit/app-alpha-2/ 0000755 0000041 0000041 00000000000 13312112240 022700 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/runit/app-alpha-2/run 0000644 0000041 0000041 00000000137 13312112240 023430 0 ustar www-data www-data #!/bin/sh
cd /tmp/app
exec 2>&1
exec chpst -u app -e /tmp/init/app-alpha-2/env ./alpha bar=baz
foreman-0.85.0/spec/resources/export/runit/app-alpha-2/log/ 0000755 0000041 0000041 00000000000 13312112240 023461 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/runit/app-alpha-2/log/run 0000644 0000041 0000041 00000000212 13312112240 024203 0 ustar www-data www-data #!/bin/sh
set -e
LOG=/var/log/app/alpha-2
test -d "$LOG" || mkdir -p -m 2750 "$LOG" && chown app "$LOG"
exec chpst -u app svlogd "$LOG"
foreman-0.85.0/spec/resources/export/runit/app-alpha-1/ 0000755 0000041 0000041 00000000000 13312112240 022677 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/runit/app-alpha-1/run 0000644 0000041 0000041 00000000137 13312112240 023427 0 ustar www-data www-data #!/bin/sh
cd /tmp/app
exec 2>&1
exec chpst -u app -e /tmp/init/app-alpha-1/env ./alpha bar=baz
foreman-0.85.0/spec/resources/export/runit/app-alpha-1/log/ 0000755 0000041 0000041 00000000000 13312112240 023460 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/runit/app-alpha-1/log/run 0000644 0000041 0000041 00000000212 13312112240 024202 0 ustar www-data www-data #!/bin/sh
set -e
LOG=/var/log/app/alpha-1
test -d "$LOG" || mkdir -p -m 2750 "$LOG" && chown app "$LOG"
exec chpst -u app svlogd "$LOG"
foreman-0.85.0/spec/resources/export/runit/app-bravo-1/ 0000755 0000041 0000041 00000000000 13312112240 022723 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/runit/app-bravo-1/run 0000644 0000041 0000041 00000000127 13312112240 023452 0 ustar www-data www-data #!/bin/sh
cd /tmp/app
exec 2>&1
exec chpst -u app -e /tmp/init/app-bravo-1/env ./bravo
foreman-0.85.0/spec/resources/export/runit/app-bravo-1/log/ 0000755 0000041 0000041 00000000000 13312112240 023504 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/runit/app-bravo-1/log/run 0000644 0000041 0000041 00000000212 13312112240 024226 0 ustar www-data www-data #!/bin/sh
set -e
LOG=/var/log/app/bravo-1
test -d "$LOG" || mkdir -p -m 2750 "$LOG" && chown app "$LOG"
exec chpst -u app svlogd "$LOG"
foreman-0.85.0/spec/resources/export/upstart/ 0000755 0000041 0000041 00000000000 13312112240 021237 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/upstart/app-alpha-1.conf 0000644 0000041 0000041 00000000170 13312112240 024105 0 ustar www-data www-data start on starting app-alpha
stop on stopping app-alpha
respawn
env PORT=5000
setuid app
chdir /tmp/app
exec ./alpha
foreman-0.85.0/spec/resources/export/upstart/app.conf 0000644 0000041 0000041 00000000062 13312112240 022664 0 ustar www-data www-data start on runlevel [2345]
stop on runlevel [!2345]
foreman-0.85.0/spec/resources/export/upstart/app-alpha-2.conf 0000644 0000041 0000041 00000000170 13312112240 024106 0 ustar www-data www-data start on starting app-alpha
stop on stopping app-alpha
respawn
env PORT=5001
setuid app
chdir /tmp/app
exec ./alpha
foreman-0.85.0/spec/resources/export/upstart/app-bravo-1.conf 0000644 0000041 0000041 00000000170 13312112240 024131 0 ustar www-data www-data start on starting app-bravo
stop on stopping app-bravo
respawn
env PORT=5100
setuid app
chdir /tmp/app
exec ./bravo
foreman-0.85.0/spec/resources/export/upstart/app-alpha.conf 0000644 0000041 0000041 00000000053 13312112240 023747 0 ustar www-data www-data start on starting app
stop on stopping app
foreman-0.85.0/spec/resources/export/upstart/app-bravo.conf 0000644 0000041 0000041 00000000053 13312112240 023773 0 ustar www-data www-data start on starting app
stop on stopping app
foreman-0.85.0/spec/resources/export/launchd/ 0000755 0000041 0000041 00000000000 13312112240 021153 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/launchd/launchd-a.default 0000644 0000041 0000041 00000001432 13312112240 024355 0 ustar www-data www-data
Label
app-alpha-1
EnvironmentVariables
PORT
5000
ProgramArguments
./alpha
KeepAlive
RunAtLoad
StandardOutPath
/var/log/app/app-alpha-1.log
StandardErrorPath
/var/log/app/app-alpha-1.log
UserName
app
WorkingDirectory
/tmp/app
foreman-0.85.0/spec/resources/export/launchd/launchd-c.default 0000644 0000041 0000041 00000001473 13312112240 024364 0 ustar www-data www-data
Label
app-alpha-1
EnvironmentVariables
PORT
5000
ProgramArguments
./alpha
charlie
KeepAlive
RunAtLoad
StandardOutPath
/var/log/app/app-alpha-1.log
StandardErrorPath
/var/log/app/app-alpha-1.log
UserName
app
WorkingDirectory
/tmp/app
foreman-0.85.0/spec/resources/export/launchd/launchd-b.default 0000644 0000041 0000041 00000001432 13312112240 024356 0 ustar www-data www-data
Label
app-bravo-1
EnvironmentVariables
PORT
5100
ProgramArguments
./bravo
KeepAlive
RunAtLoad
StandardOutPath
/var/log/app/app-bravo-1.log
StandardErrorPath
/var/log/app/app-bravo-1.log
UserName
app
WorkingDirectory
/tmp/app
foreman-0.85.0/spec/resources/export/daemon/ 0000755 0000041 0000041 00000000000 13312112240 021000 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/daemon/app-alpha-1.conf 0000644 0000041 0000041 00000000365 13312112240 023654 0 ustar www-data www-data start on starting app-alpha
stop on stopping app-alpha
respawn
env PORT=5000
exec start-stop-daemon --start --chuid app --chdir /tmp/app --make-pidfile --pidfile /var/run/app/app-alpha-1.pid --exec ./alpha >> /var/log/app/app-alpha-1.log 2>&1
foreman-0.85.0/spec/resources/export/daemon/app.conf 0000644 0000041 0000041 00000000302 13312112240 022422 0 ustar www-data www-data pre-start script
bash << "EOF"
mkdir -p /var/log/app
chown -R app /var/log/app
mkdir -p /var/run/app
chown -R app /var/run/app
EOF
end script
start on runlevel [2345]
stop on runlevel [016]
foreman-0.85.0/spec/resources/export/daemon/app-alpha-2.conf 0000644 0000041 0000041 00000000365 13312112240 023655 0 ustar www-data www-data start on starting app-alpha
stop on stopping app-alpha
respawn
env PORT=5001
exec start-stop-daemon --start --chuid app --chdir /tmp/app --make-pidfile --pidfile /var/run/app/app-alpha-2.pid --exec ./alpha >> /var/log/app/app-alpha-2.log 2>&1
foreman-0.85.0/spec/resources/export/daemon/app-bravo-1.conf 0000644 0000041 0000041 00000000365 13312112240 023700 0 ustar www-data www-data start on starting app-bravo
stop on stopping app-bravo
respawn
env PORT=5100
exec start-stop-daemon --start --chuid app --chdir /tmp/app --make-pidfile --pidfile /var/run/app/app-bravo-1.pid --exec ./bravo >> /var/log/app/app-bravo-1.log 2>&1
foreman-0.85.0/spec/resources/export/daemon/app-alpha.conf 0000644 0000041 0000041 00000000053 13312112240 023510 0 ustar www-data www-data start on starting app
stop on stopping app
foreman-0.85.0/spec/resources/export/daemon/app-bravo.conf 0000644 0000041 0000041 00000000053 13312112240 023534 0 ustar www-data www-data start on starting app
stop on stopping app
foreman-0.85.0/spec/resources/export/bluepill/ 0000755 0000041 0000041 00000000000 13312112240 021345 5 ustar www-data www-data foreman-0.85.0/spec/resources/export/bluepill/app-concurrency.pill 0000644 0000041 0000041 00000002216 13312112240 025340 0 ustar www-data www-data 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 = %Q{./alpha}
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT"=>"5000"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stop_grace_time = 45.seconds
process.stdout = process.stderr = "/var/log/app/app-alpha-1.log"
process.monitor_children do |children|
children.stop_command "kill {{PID}}"
end
process.group = "app-alpha"
end
app.process("alpha-2") do |process|
process.start_command = %Q{./alpha}
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT"=>"5001"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stop_grace_time = 45.seconds
process.stdout = process.stderr = "/var/log/app/app-alpha-2.log"
process.monitor_children do |children|
children.stop_command "kill {{PID}}"
end
process.group = "app-alpha"
end
end
foreman-0.85.0/spec/resources/export/bluepill/app.pill 0000644 0000041 0000041 00000004204 13312112240 023007 0 ustar www-data www-data 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 = %Q{./alpha}
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT"=>"5000"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stop_grace_time = 45.seconds
process.stdout = process.stderr = "/var/log/app/app-alpha-1.log"
process.monitor_children do |children|
children.stop_command "kill {{PID}}"
end
process.group = "app-alpha"
end
app.process("bravo-1") do |process|
process.start_command = %Q{./bravo}
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT"=>"5100"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stop_grace_time = 45.seconds
process.stdout = process.stderr = "/var/log/app/app-bravo-1.log"
process.monitor_children do |children|
children.stop_command "kill {{PID}}"
end
process.group = "app-bravo"
end
app.process("foo_bar-1") do |process|
process.start_command = %Q{./foo_bar}
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT"=>"5200"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stop_grace_time = 45.seconds
process.stdout = process.stderr = "/var/log/app/app-foo_bar-1.log"
process.monitor_children do |children|
children.stop_command "kill {{PID}}"
end
process.group = "app-foo_bar"
end
app.process("foo-bar-1") do |process|
process.start_command = %Q{./foo-bar}
process.working_dir = "/tmp/app"
process.daemonize = true
process.environment = {"PORT"=>"5300"}
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stop_grace_time = 45.seconds
process.stdout = process.stderr = "/var/log/app/app-foo-bar-1.log"
process.monitor_children do |children|
children.stop_command "kill {{PID}}"
end
process.group = "app-foo-bar"
end
end
foreman-0.85.0/spec/resources/Procfile 0000644 0000041 0000041 00000000151 13312112240 017677 0 ustar www-data www-data echo: bin/echo echoing
env: bin/env FOO
test: bin/test
utf8: bin/utf8
ps: bin/echo PS env var is $PS
foreman-0.85.0/spec/foreman_spec.rb 0000644 0000041 0000041 00000000435 13312112240 017172 0 ustar www-data www-data require "spec_helper"
require "foreman"
describe Foreman do
describe "VERSION" do
subject { Foreman::VERSION }
it { is_expected.to be_a String }
end
describe "runner" do
it "should exist" do
expect(File.exists?(Foreman.runner)).to eq(true)
end
end
end
foreman-0.85.0/spec/foreman/ 0000755 0000041 0000041 00000000000 13312112240 015631 5 ustar www-data www-data foreman-0.85.0/spec/foreman/engine_spec.rb 0000644 0000041 0000041 00000006404 13312112240 020441 0 ustar www-data www-data require "spec_helper"
require "foreman/engine"
class Foreman::Engine::Tester < Foreman::Engine
attr_reader :buffer
def startup
@buffer = ""
end
def output(name, data)
@buffer += "#{name}: #{data}"
end
def shutdown
end
end
describe "Foreman::Engine", :fakefs do
subject do
write_procfile "Procfile"
Foreman::Engine::Tester.new.load_procfile("Procfile")
end
describe "initialize" do
describe "with a Procfile" do
before { write_procfile }
it "reads the processes" do
expect(subject.process("alpha").command).to eq("./alpha")
expect(subject.process("bravo").command).to eq("./bravo")
end
end
end
describe "start" do
it "forks the processes" do
expect(subject.process("alpha")).to receive(:run)
expect(subject.process("bravo")).to receive(:run)
expect(subject).to receive(:watch_for_output)
expect(subject).to receive(:wait_for_shutdown_or_child_termination)
subject.start
end
it "handles concurrency" do
subject.options[:formation] = "alpha=2"
expect(subject.process("alpha")).to receive(:run).twice
expect(subject.process("bravo")).to_not receive(:run)
expect(subject).to receive(:watch_for_output)
expect(subject).to receive(:wait_for_shutdown_or_child_termination)
subject.start
end
end
describe "directories" do
it "has the directory default relative to the Procfile" do
write_procfile "/some/app/Procfile"
engine = Foreman::Engine.new.load_procfile("/some/app/Procfile")
expect(engine.root).to eq("/some/app")
end
end
describe "environment" do
it "should read env files" do
write_file("/tmp/env") { |f| f.puts("FOO=baz") }
subject.load_env("/tmp/env")
expect(subject.env["FOO"]).to eq("baz")
end
it "should read more than one if specified" do
write_file("/tmp/env1") { |f| f.puts("FOO=bar") }
write_file("/tmp/env2") { |f| f.puts("BAZ=qux") }
subject.load_env "/tmp/env1"
subject.load_env "/tmp/env2"
expect(subject.env["FOO"]).to eq("bar")
expect(subject.env["BAZ"]).to eq("qux")
end
it "should handle quoted values" do
write_file("/tmp/env") do |f|
f.puts 'FOO=bar'
f.puts 'BAZ="qux"'
f.puts "FRED='barney'"
f.puts 'OTHER="escaped\"quote"'
f.puts 'URL="http://example.com/api?foo=bar&baz=1"'
end
subject.load_env "/tmp/env"
expect(subject.env["FOO"]).to eq("bar")
expect(subject.env["BAZ"]).to eq("qux")
expect(subject.env["FRED"]).to eq("barney")
expect(subject.env["OTHER"]).to eq('escaped"quote')
expect(subject.env["URL"]).to eq("http://example.com/api?foo=bar&baz=1")
end
it "should handle multiline strings" do
write_file("/tmp/env") do |f|
f.puts 'FOO="bar\nbaz"'
end
subject.load_env "/tmp/env"
expect(subject.env["FOO"]).to eq("bar\nbaz")
end
it "should fail if specified and doesnt exist" do
expect { subject.load_env "/tmp/env" }.to raise_error(Errno::ENOENT)
end
it "should set port from .env if specified" do
write_file("/tmp/env") { |f| f.puts("PORT=9000") }
subject.load_env "/tmp/env"
expect(subject.send(:base_port)).to eq(9000)
end
end
end
foreman-0.85.0/spec/foreman/helpers_spec.rb 0000644 0000041 0000041 00000001064 13312112240 020633 0 ustar www-data www-data require "spec_helper"
require "foreman/helpers"
describe "Foreman::Helpers" do
before do
module Foo
class Bar; end
end
end
after do
Object.send(:remove_const, :Foo)
end
subject { o = Object.new; o.extend(Foreman::Helpers); o }
it "should classify words" do
expect(subject.classify("foo")).to eq("Foo")
expect(subject.classify("foo-bar")).to eq("FooBar")
end
it "should constantize words" do
expect(subject.constantize("Object")).to eq(Object)
expect(subject.constantize("Foo::Bar")).to eq(Foo::Bar)
end
end
foreman-0.85.0/spec/foreman/export/ 0000755 0000041 0000041 00000000000 13312112240 017152 5 ustar www-data www-data foreman-0.85.0/spec/foreman/export/base_spec.rb 0000644 0000041 0000041 00000001252 13312112240 021423 0 ustar www-data www-data require "spec_helper"
require "foreman/engine"
require "foreman/export"
describe "Foreman::Export::Base", :fakefs do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:location) { "/tmp/init" }
let(:engine) { Foreman::Engine.new().load_procfile(procfile) }
let(:subject) { Foreman::Export::Base.new(location, engine) }
it "has a say method for displaying info" do
expect(subject).to receive(:puts).with("[foreman export] foo")
subject.send(:say, "foo")
end
it "raises errors as a Foreman::Export::Exception" do
expect { subject.send(:error, "foo") }.to raise_error(Foreman::Export::Exception, "foo")
end
end
foreman-0.85.0/spec/foreman/export/inittab_spec.rb 0000644 0000041 0000041 00000002331 13312112240 022142 0 ustar www-data www-data require "spec_helper"
require "foreman/engine"
require "foreman/export/inittab"
require "tmpdir"
describe Foreman::Export::Inittab, :fakefs do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:location) { "/tmp/inittab" }
let(:formation) { nil }
let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
let(:options) { Hash.new }
let(:inittab) { Foreman::Export::Inittab.new(location, engine, options) }
before(:each) { load_export_templates_into_fakefs("inittab") }
before(:each) { allow(inittab).to receive(:say) }
it "exports to the filesystem" do
inittab.export
expect(File.read("/tmp/inittab")).to eq(example_export_file("inittab/inittab.default"))
end
context "to stdout" do
let(:location) { "-" }
it "exports to stdout" do
expect(inittab).to receive(:puts).with(example_export_file("inittab/inittab.default"))
inittab.export
end
end
context "with concurrency" do
let(:formation) { "alpha=2" }
it "exports to the filesystem with concurrency" do
inittab.export
expect(File.read("/tmp/inittab")).to eq(example_export_file("inittab/inittab.concurrency"))
end
end
end
foreman-0.85.0/spec/foreman/export/supervisord_spec.rb 0000644 0000041 0000041 00000002502 13312112240 023075 0 ustar www-data www-data require "spec_helper"
require "foreman/engine"
require "foreman/export/supervisord"
require "tmpdir"
describe Foreman::Export::Supervisord, :fakefs do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:formation) { nil }
let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
let(:options) { Hash.new }
let(:supervisord) { Foreman::Export::Supervisord.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("supervisord") }
before(:each) { allow(supervisord).to receive(:say) }
it "exports to the filesystem" do
write_env(".env", "FOO"=>"bar", "URL"=>"http://example.com/api?foo=bar&baz=1")
supervisord.engine.load_env('.env')
supervisord.export
expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("supervisord/app-alpha-1.conf"))
end
it "cleans up if exporting into an existing dir" do
expect(FileUtils).to receive(:rm).with("/tmp/init/app.conf")
supervisord.export
supervisord.export
end
context "with concurrency" do
let(:formation) { "alpha=2" }
it "exports to the filesystem with concurrency" do
supervisord.export
expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("supervisord/app-alpha-2.conf"))
end
end
end
foreman-0.85.0/spec/foreman/export/runit_spec.rb 0000644 0000041 0000041 00000003464 13312112240 021661 0 ustar www-data www-data require "spec_helper"
require "foreman/engine"
require "foreman/export/runit"
require "tmpdir"
describe Foreman::Export::Runit, :fakefs do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", 'bar=baz') }
let(:engine) { Foreman::Engine.new(:formation => "alpha=2,bravo=1").load_procfile(procfile) }
let(:options) { Hash.new }
let(:runit) { Foreman::Export::Runit.new('/tmp/init', engine, options) }
before(:each) { load_export_templates_into_fakefs("runit") }
before(:each) { allow(runit).to receive(:say) }
before(:each) { allow(FakeFS::FileUtils).to receive(:chmod) }
it "exports to the filesystem" do
engine.env["BAR"] = "baz"
runit.export
expect(File.read("/tmp/init/app-alpha-1/run")).to eq(example_export_file('runit/app-alpha-1/run'))
expect(File.read("/tmp/init/app-alpha-1/log/run")).to eq(example_export_file('runit/app-alpha-1/log/run'))
expect(File.read("/tmp/init/app-alpha-1/env/PORT")).to eq("5000\n")
expect(File.read("/tmp/init/app-alpha-1/env/BAR")).to eq("baz\n")
expect(File.read("/tmp/init/app-alpha-2/run")).to eq(example_export_file('runit/app-alpha-2/run'))
expect(File.read("/tmp/init/app-alpha-2/log/run")).to eq(example_export_file('runit/app-alpha-2/log/run'))
expect(File.read("/tmp/init/app-alpha-2/env/PORT")).to eq("5001\n")
expect(File.read("/tmp/init/app-alpha-2/env/BAR")).to eq("baz\n")
expect(File.read("/tmp/init/app-bravo-1/run")).to eq(example_export_file('runit/app-bravo-1/run'))
expect(File.read("/tmp/init/app-bravo-1/log/run")).to eq(example_export_file('runit/app-bravo-1/log/run'))
expect(File.read("/tmp/init/app-bravo-1/env/PORT")).to eq("5100\n")
end
it "creates a full path to the export directory" do
expect { runit.export }.to_not raise_error
end
end
foreman-0.85.0/spec/foreman/export/upstart_spec.rb 0000644 0000041 0000041 00000010626 13312112240 022220 0 ustar www-data www-data require "spec_helper"
require "foreman/engine"
require "foreman/export/upstart"
require "tmpdir"
describe Foreman::Export::Upstart, :fakefs do
let(:procfile) { write_procfile("/tmp/app/Procfile") }
let(:formation) { nil }
let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
let(:options) { Hash.new }
let(:upstart) { Foreman::Export::Upstart.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("upstart") }
before(:each) { allow(upstart).to receive(:say) }
it "exports to the filesystem" do
upstart.export
expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("upstart/app.conf"))
expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("upstart/app-alpha.conf"))
expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("upstart/app-alpha-1.conf"))
expect(File.read("/tmp/init/app-bravo.conf")).to eq(example_export_file("upstart/app-bravo.conf"))
expect(File.read("/tmp/init/app-bravo-1.conf")).to eq(example_export_file("upstart/app-bravo-1.conf"))
end
it "cleans up if exporting into an existing dir" do
expect(FileUtils).to receive(:rm).with("/tmp/init/app.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha-1.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo-1.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar-1.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar-1.conf")
upstart.export
upstart.export
end
it "does not delete exported files for similarly named applications" do
FileUtils.mkdir_p "/tmp/init"
["app2", "app2-alpha", "app2-alpha-1"].each do |name|
path = "/tmp/init/#{name}.conf"
FileUtils.touch(path)
expect(FileUtils).to_not receive(:rm).with(path)
end
upstart.export
end
it 'does not delete exported files for app which share name prefix' do
FileUtils.mkdir_p "/tmp/init"
["app-worker", "app-worker-worker", "app-worker-worker-1"].each do |name|
path = "/tmp/init/#{name}.conf"
FileUtils.touch(path)
expect(FileUtils).to_not receive(:rm).with(path)
end
upstart.export
expect(File.exist?('/tmp/init/app.conf')).to be true
expect(File.exist?('/tmp/init/app-worker.conf')).to be true
end
it "quotes and escapes environment variables" do
engine.env['KEY'] = 'd"\|d'
upstart.export
expect("foobarfoo").to include "bar"
expect(File.read("/tmp/init/app-alpha-1.conf")).to match(/KEY='d"\\\|d'/)
end
context "with a formation" do
let(:formation) { "alpha=2" }
it "exports to the filesystem with concurrency" do
upstart.export
expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("upstart/app.conf"))
expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("upstart/app-alpha.conf"))
expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("upstart/app-alpha-1.conf"))
expect(File.read("/tmp/init/app-alpha-2.conf")).to eq(example_export_file("upstart/app-alpha-2.conf"))
expect(File.exists?("/tmp/init/app-bravo-1.conf")).to eq(false)
end
end
context "with alternate templates" do
let(:template) { "/tmp/alternate" }
let(:options) { { :app => "app", :template => template } }
before do
FileUtils.mkdir_p template
File.open("#{template}/master.conf.erb", "w") { |f| f.puts "alternate_template" }
end
it "can export with alternate template files" do
upstart.export
expect(File.read("/tmp/init/app.conf")).to eq("alternate_template\n")
end
end
context "with alternate templates from home dir" do
before do
FileUtils.mkdir_p File.expand_path("~/.foreman/templates/upstart")
File.open(File.expand_path("~/.foreman/templates/upstart/master.conf.erb"), "w") do |file|
file.puts "default_alternate_template"
end
end
it "can export with alternate template files" do
upstart.export
expect(File.read("/tmp/init/app.conf")).to eq("default_alternate_template\n")
end
end
end
foreman-0.85.0/spec/foreman/export/launchd_spec.rb 0000644 0000041 0000041 00000002176 13312112240 022135 0 ustar www-data www-data require "spec_helper"
require "foreman/engine"
require "foreman/export/launchd"
require "tmpdir"
describe Foreman::Export::Launchd, :fakefs do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:options) { Hash.new }
let(:engine) { Foreman::Engine.new().load_procfile(procfile) }
let(:launchd) { Foreman::Export::Launchd.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("launchd") }
before(:each) { allow(launchd).to receive(:say) }
it "exports to the filesystem" do
launchd.export
expect(File.read("/tmp/init/app-alpha-1.plist")).to eq(example_export_file("launchd/launchd-a.default"))
expect(File.read("/tmp/init/app-bravo-1.plist")).to eq(example_export_file("launchd/launchd-b.default"))
end
context "with multiple command arguments" do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile", "charlie") }
it "splits each command argument" do
launchd.export
expect(File.read("/tmp/init/app-alpha-1.plist")).to eq(example_export_file("launchd/launchd-c.default"))
end
end
end
foreman-0.85.0/spec/foreman/export/bluepill_spec.rb 0000644 0000041 0000041 00000002345 13312112240 022325 0 ustar www-data www-data require "spec_helper"
require "foreman/engine"
require "foreman/export/bluepill"
require "tmpdir"
describe Foreman::Export::Bluepill, :fakefs do
let(:procfile) { FileUtils.mkdir_p("/tmp/app"); write_procfile("/tmp/app/Procfile") }
let(:formation) { nil }
let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
let(:options) { Hash.new }
let(:bluepill) { Foreman::Export::Bluepill.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("bluepill") }
before(:each) { allow(bluepill).to receive(:say) }
it "exports to the filesystem" do
bluepill.export
expect(normalize_space(File.read("/tmp/init/app.pill"))).to eq(normalize_space(example_export_file("bluepill/app.pill")))
end
it "cleans up if exporting into an existing dir" do
expect(FileUtils).to receive(:rm).with("/tmp/init/app.pill")
bluepill.export
bluepill.export
end
context "with a process formation" do
let(:formation) { "alpha=2" }
it "exports to the filesystem with concurrency" do
bluepill.export
expect(normalize_space(File.read("/tmp/init/app.pill"))).to eq(normalize_space(example_export_file("bluepill/app-concurrency.pill")))
end
end
end
foreman-0.85.0/spec/foreman/export/systemd_spec.rb 0000644 0000041 0000041 00000011464 13312112240 022207 0 ustar www-data www-data require "spec_helper"
require "foreman/engine"
require "foreman/export/systemd"
require "tmpdir"
describe Foreman::Export::Systemd, :fakefs do
let(:procfile) { write_procfile("/tmp/app/Procfile") }
let(:formation) { nil }
let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
let(:options) { Hash.new }
let(:systemd) { Foreman::Export::Systemd.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("systemd") }
before(:each) { allow(systemd).to receive(:say) }
it "exports to the filesystem" do
systemd.export
expect(File.read("/tmp/init/app.target")).to eq(example_export_file("systemd/app.target"))
expect(File.read("/tmp/init/app-alpha.target")).to eq(example_export_file("systemd/app-alpha.target"))
expect(File.read("/tmp/init/app-alpha@.service")).to eq(example_export_file("systemd/app-alpha@.service"))
expect(File.read("/tmp/init/app-bravo.target")).to eq(example_export_file("systemd/app-bravo.target"))
expect(File.read("/tmp/init/app-bravo@.service")).to eq(example_export_file("systemd/app-bravo@.service"))
expect(File.directory?("/tmp/init/app-alpha.target.wants")).to be_truthy
expect(File.symlink?("/tmp/init/app-alpha.target.wants/app-alpha@5000.service")).to be_truthy
end
it "cleans up if exporting into an existing dir" do
expect(FileUtils).to receive(:rm).with("/tmp/init/app.target")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha@.service")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha.target")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha.target.wants/app-alpha@5000.service")
expect(FileUtils).to receive(:rm_r).with("/tmp/init/app-alpha.target.wants")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo.target")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo@.service")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo.target.wants/app-bravo@5100.service")
expect(FileUtils).to receive(:rm_r).with("/tmp/init/app-bravo.target.wants")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar.target")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar@.service")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar.target.wants/app-foo_bar@5200.service")
expect(FileUtils).to receive(:rm_r).with("/tmp/init/app-foo_bar.target.wants")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar.target")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar@.service")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar.target.wants/app-foo-bar@5300.service")
expect(FileUtils).to receive(:rm_r).with("/tmp/init/app-foo-bar.target.wants")
systemd.export
systemd.export
end
it "includes environment variables" do
engine.env['KEY'] = 'some "value"'
systemd.export
expect(File.read("/tmp/init/app-alpha@.service")).to match(/KEY=some "value"/)
end
it "includes ExecStart line" do
engine.env['KEY'] = 'some "value"'
systemd.export
expect(File.read("/tmp/init/app-alpha@.service")).to match(/^ExecStart=/)
end
context "with a formation" do
let(:formation) { "alpha=2" }
it "exports to the filesystem with concurrency" do
systemd.export
expect(File.read("/tmp/init/app.target")).to eq(example_export_file("systemd/app.target"))
expect(File.read("/tmp/init/app-alpha.target")).to eq(example_export_file("systemd/app-alpha.target"))
expect(File.read("/tmp/init/app-alpha@.service")).to eq(example_export_file("systemd/app-alpha@.service"))
expect(File.read("/tmp/init/app-bravo.target")).to eq(example_export_file("systemd/app-bravo.target"))
expect(File.read("/tmp/init/app-bravo@.service")).to eq(example_export_file("systemd/app-bravo@.service"))
end
end
context "with alternate templates" do
let(:template) { "/tmp/alternate" }
let(:options) { { :app => "app", :template => template } }
before do
FileUtils.mkdir_p template
File.open("#{template}/master.target.erb", "w") { |f| f.puts "alternate_template" }
end
it "can export with alternate template files" do
systemd.export
expect(File.read("/tmp/init/app.target")).to eq("alternate_template\n")
end
end
context "with alternate templates from home dir" do
before do
FileUtils.mkdir_p File.expand_path("~/.foreman/templates/systemd")
File.open(File.expand_path("~/.foreman/templates/systemd/master.target.erb"), "w") do |file|
file.puts "default_alternate_template"
end
end
it "can export with alternate template files" do
systemd.export
expect(File.read("/tmp/init/app.target")).to eq("default_alternate_template\n")
end
end
end
foreman-0.85.0/spec/foreman/export/daemon_spec.rb 0000644 0000041 0000041 00000007313 13312112240 021760 0 ustar www-data www-data require "spec_helper"
require "foreman/engine"
require "foreman/export/daemon"
require "tmpdir"
describe Foreman::Export::Daemon, :fakefs do
let(:procfile) { write_procfile("/tmp/app/Procfile") }
let(:formation) { nil }
let(:engine) { Foreman::Engine.new(:formation => formation).load_procfile(procfile) }
let(:options) { Hash.new }
let(:daemon) { Foreman::Export::Daemon.new("/tmp/init", engine, options) }
before(:each) { load_export_templates_into_fakefs("daemon") }
before(:each) { allow(daemon).to receive(:say) }
it "exports to the filesystem" do
daemon.export
expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("daemon/app.conf"))
expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("daemon/app-alpha.conf"))
expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("daemon/app-alpha-1.conf"))
expect(File.read("/tmp/init/app-bravo.conf")).to eq(example_export_file("daemon/app-bravo.conf"))
expect(File.read("/tmp/init/app-bravo-1.conf")).to eq(example_export_file("daemon/app-bravo-1.conf"))
end
it "cleans up if exporting into an existing dir" do
expect(FileUtils).to receive(:rm).with("/tmp/init/app.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-alpha-1.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-bravo-1.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo-bar-1.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar.conf")
expect(FileUtils).to receive(:rm).with("/tmp/init/app-foo_bar-1.conf")
daemon.export
daemon.export
end
it "does not delete exported files for similarly named applications" do
FileUtils.mkdir_p "/tmp/init"
["app2", "app2-alpha", "app2-alpha-1"].each do |name|
path = "/tmp/init/#{name}.conf"
FileUtils.touch(path)
expect(FileUtils).to_not receive(:rm).with(path)
end
daemon.export
end
context "with a formation" do
let(:formation) { "alpha=2" }
it "exports to the filesystem with concurrency" do
daemon.export
expect(File.read("/tmp/init/app.conf")).to eq(example_export_file("daemon/app.conf"))
expect(File.read("/tmp/init/app-alpha.conf")).to eq(example_export_file("daemon/app-alpha.conf"))
expect(File.read("/tmp/init/app-alpha-1.conf")).to eq(example_export_file("daemon/app-alpha-1.conf"))
expect(File.read("/tmp/init/app-alpha-2.conf")).to eq(example_export_file("daemon/app-alpha-2.conf"))
expect(File.exists?("/tmp/init/app-bravo-1.conf")).to eq(false)
end
end
context "with alternate templates" do
let(:template) { "/tmp/alternate" }
let(:options) { { :app => "app", :template => template } }
before do
FileUtils.mkdir_p template
File.open("#{template}/master.conf.erb", "w") { |f| f.puts "alternate_template" }
end
it "can export with alternate template files" do
daemon.export
expect(File.read("/tmp/init/app.conf")).to eq("alternate_template\n")
end
end
context "with alternate templates from home dir" do
before do
FileUtils.mkdir_p File.expand_path("~/.foreman/templates/daemon")
File.open(File.expand_path("~/.foreman/templates/daemon/master.conf.erb"), "w") do |file|
file.puts "default_alternate_template"
end
end
it "can export with alternate template files" do
daemon.export
expect(File.read("/tmp/init/app.conf")).to eq("default_alternate_template\n")
end
end
end
foreman-0.85.0/spec/foreman/cli_spec.rb 0000644 0000041 0000041 00000006560 13312112240 017746 0 ustar www-data www-data require "spec_helper"
require "foreman/cli"
describe "Foreman::CLI", :fakefs do
subject { Foreman::CLI.new }
describe ".foreman" do
before { File.open(".foreman", "w") { |f| f.puts "formation: alpha=2" } }
it "provides default options" do
expect(subject.send(:options)["formation"]).to eq("alpha=2")
end
it "is overridden by options at the cli" do
subject = Foreman::CLI.new([], :formation => "alpha=3")
expect(subject.send(:options)["formation"]).to eq("alpha=3")
end
end
describe "start" do
describe "when a Procfile doesnt exist", :fakefs do
it "displays an error" do
mock_error(subject, "Procfile does not exist.") do
expect_any_instance_of(Foreman::Engine).to_not receive(:start)
subject.start
end
end
end
describe "with a valid Procfile" do
it "can run a single command" do
without_fakefs do
output = foreman("start env -f #{resource_path("Procfile")}")
expect(output).to match(/env.1/)
expect(output).not_to match(/test.1/)
end
end
it "can run all commands" do
without_fakefs do
output = foreman("start -f #{resource_path("Procfile")} -e #{resource_path(".env")}")
expect(output).to match(/echo.1 \| echoing/)
expect(output).to match(/env.1 \| bar/)
expect(output).to match(/test.1 \| testing/)
end
end
it "sets PS variable with the process name" do
without_fakefs do
output = foreman("start -f #{resource_path("Procfile")}")
expect(output).to match(/ps.1 \| PS env var is ps.1/)
end
end
it "fails if process fails" do
output = `bundle exec foreman start -f #{resource_path "Procfile.bad"} && echo success`
expect(output).not_to include 'success'
end
end
end
describe "check" do
it "with a valid Procfile displays the jobs" do
write_procfile
expect(foreman("check")).to eq("valid procfile detected (alpha, bravo, foo_bar, foo-bar)\n")
end
it "with a blank Procfile displays an error" do
FileUtils.touch "Procfile"
expect(foreman("check")).to eq("ERROR: no processes defined\n")
end
it "without a Procfile displays an error" do
expect(foreman("check")).to eq("ERROR: Procfile does not exist.\n")
end
end
describe "run" do
it "can run a command" do
expect(forked_foreman("run echo 1")).to eq("1\n")
end
it "doesn't parse options for the command" do
expect(forked_foreman("run grep -e FOO #{resource_path(".env")}")).to eq("FOO=bar\n")
end
it "includes the environment" do
expect(forked_foreman("run -e #{resource_path(".env")} #{resource_path("bin/env FOO")}")).to eq("bar\n")
end
it "can run a command from the Procfile" do
expect(forked_foreman("run -f #{resource_path("Procfile")} test")).to eq("testing\n")
end
it "exits with the same exit code as the command" do
expect(fork_and_get_exitstatus("run echo 1")).to eq(0)
expect(fork_and_get_exitstatus("run date 'invalid_date'")).to eq(1)
end
end
describe "version" do
it "displays gem version" do
expect(foreman("version").chomp).to eq(Foreman::VERSION)
end
it "displays gem version on shortcut command" do
expect(foreman("-v").chomp).to eq(Foreman::VERSION)
end
end
end
foreman-0.85.0/spec/foreman/export_spec.rb 0000644 0000041 0000041 00000001364 13312112240 020515 0 ustar www-data www-data require "spec_helper"
require "foreman/export"
describe "Foreman::Export" do
subject { Foreman::Export }
describe "with a formatter that doesn't declare the appropriate class" do
it "prints an error" do
expect(subject).to receive(:require).with("foreman/export/invalidformatter")
mock_export_error("Unknown export format: invalidformatter (no class Foreman::Export::Invalidformatter).") do
subject.formatter("invalidformatter")
end
end
end
describe "with an invalid formatter" do
it "prints an error" do
mock_export_error("Unknown export format: invalidformatter (unable to load file 'foreman/export/invalidformatter').") do
subject.formatter("invalidformatter")
end
end
end
end
foreman-0.85.0/spec/foreman/process_spec.rb 0000644 0000041 0000041 00000004323 13312112240 020650 0 ustar www-data www-data require 'spec_helper'
require 'foreman/process'
require 'ostruct'
require 'timeout'
require 'tmpdir'
describe Foreman::Process do
def run(process, options={})
rd, wr = IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY")
process.run(options.merge(:output => wr))
rd.gets
end
describe "#run" do
it "runs the process" do
process = Foreman::Process.new(resource_path("bin/test"))
expect(run(process)).to eq("testing\n")
end
it "can set environment" do
process = Foreman::Process.new(resource_path("bin/env FOO"), :env => { "FOO" => "bar" })
expect(run(process)).to eq("bar\n")
end
it "can set per-run environment" do
process = Foreman::Process.new(resource_path("bin/env FOO"))
expect(run(process, :env => { "FOO" => "bar "})).to eq("bar\n")
end
it "can handle env vars in the command" do
process = Foreman::Process.new(resource_path("bin/echo $FOO"), :env => { "FOO" => "bar" })
expect(run(process)).to eq("bar\n")
end
it "can handle per-run env vars in the command" do
process = Foreman::Process.new(resource_path("bin/echo $FOO"))
expect(run(process, :env => { "FOO" => "bar" })).to eq("bar\n")
end
it "should output utf8 properly" do
process = Foreman::Process.new(resource_path("bin/utf8"))
expect(run(process)).to eq(Foreman.ruby_18? ? "\xFF\x03\n" : "\xFF\x03\n".force_encoding('binary'))
end
it "can expand env in the command" do
process = Foreman::Process.new("command $FOO $BAR", :env => { "FOO" => "bar" })
expect(process.expanded_command).to eq("command bar $BAR")
end
it "can expand extra env in the command" do
process = Foreman::Process.new("command $FOO $BAR", :env => { "FOO" => "bar" })
expect(process.expanded_command("BAR" => "qux")).to eq("command bar qux")
end
it "can execute" do
expect(Kernel).to receive(:exec).with("bin/command")
process = Foreman::Process.new("bin/command")
process.exec
end
it "can execute with env" do
expect(Kernel).to receive(:exec).with("bin/command bar")
process = Foreman::Process.new("bin/command $FOO")
process.exec(:env => { "FOO" => "bar" })
end
end
end
foreman-0.85.0/spec/foreman/procfile_spec.rb 0000644 0000041 0000041 00000003127 13312112240 020776 0 ustar www-data www-data require 'spec_helper'
require 'foreman/procfile'
require 'pathname'
require 'tmpdir'
describe Foreman::Procfile, :fakefs do
subject { Foreman::Procfile.new }
it "can load from a file" do
write_procfile
subject.load "Procfile"
expect(subject["alpha"]).to eq("./alpha")
expect(subject["bravo"]).to eq("./bravo")
end
it "loads a passed-in Procfile" do
write_procfile
procfile = Foreman::Procfile.new("Procfile")
expect(procfile["alpha"]).to eq("./alpha")
expect(procfile["bravo"]).to eq("./bravo")
expect(procfile["foo-bar"]).to eq("./foo-bar")
expect(procfile["foo_bar"]).to eq("./foo_bar")
end
it 'only creates Procfile entries for lines matching regex' do
write_procfile
procfile = Foreman::Procfile.new("Procfile")
keys = procfile.instance_variable_get(:@entries).map(&:first)
expect(keys).to match_array(%w[alpha bravo foo-bar foo_bar])
end
it "returns nil when attempting to retrieve an non-existing entry" do
write_procfile
procfile = Foreman::Procfile.new("Procfile")
expect(procfile["unicorn"]).to eq(nil)
end
it "can have a process appended to it" do
subject["charlie"] = "./charlie"
expect(subject["charlie"]).to eq("./charlie")
end
it "can write to a string" do
subject["foo"] = "./foo"
subject["bar"] = "./bar"
expect(subject.to_s).to eq("foo: ./foo\nbar: ./bar")
end
it "can write to a file" do
subject["foo"] = "./foo"
subject["bar"] = "./bar"
Dir.mkdir('/tmp')
subject.save "/tmp/proc"
expect(File.read("/tmp/proc")).to eq("foo: ./foo\nbar: ./bar\n")
end
end
foreman-0.85.0/spec/spec_helper.rb 0000644 0000041 0000041 00000007776 13312112240 017041 0 ustar www-data www-data # it throws following message:
# W, [2018-02-06T18:16:06.360071 #72025] WARN -- : This usage of the Code Climate Test Reporter is now deprecated. Since version
# 1.0, we now require you to run `SimpleCov` in your test/spec helper, and then
# run the provided `codeclimate-test-reporter` binary separately to report your
# results to Code Climate.
#
# More information here: https://github.com/codeclimate/ruby-test-reporter/blob/master/README.md
# require "codeclimate-test-reporter"
# CodeClimate::TestReporter.start
require "simplecov"
SimpleCov.start do
add_filter "/spec/"
end
require "rspec"
require "timecop"
require "pp"
require "fakefs/safe"
require "fakefs/spec_helpers"
$:.unshift File.expand_path("../../lib", __FILE__)
def mock_export_error(message)
expect { yield }.to raise_error(Foreman::Export::Exception, message)
end
def mock_error(subject, message)
mock_exit do
expect(subject).to receive(:puts).with("ERROR: #{message}")
yield
end
end
def make_pipe
IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY")
end
def foreman(args)
capture_stdout do
begin
Foreman::CLI.start(args.split(" "))
rescue SystemExit
end
end
end
def forked_foreman(args)
rd, wr = make_pipe
Process.spawn("bundle exec bin/foreman #{args}", :out => wr, :err => wr)
wr.close
rd.read
end
def fork_and_capture(&blk)
rd, wr = make_pipe
pid = fork do
rd.close
wr.sync = true
$stdout.reopen wr
$stderr.reopen wr
blk.call
$stdout.flush
$stdout.close
end
wr.close
Process.wait pid
buffer = ""
until rd.eof?
buffer += rd.gets
end
end
def fork_and_get_exitstatus(args)
pid = Process.spawn("bundle exec bin/foreman #{args}", :out => "/dev/null", :err => "/dev/null")
Process.wait(pid)
$?.exitstatus
end
def mock_exit(&block)
expect(block).to raise_error(SystemExit)
end
def write_foreman_config(app)
File.open("/etc/foreman/#{app}.conf", "w") do |file|
file.puts %{#{app}_processes="alpha bravo"}
file.puts %{#{app}_alpha="1"}
file.puts %{#{app}_bravo="2"}
end
end
def write_procfile(procfile="Procfile", alpha_env="")
FileUtils.mkdir_p(File.dirname(procfile))
File.open(procfile, "w") do |file|
file.puts "alpha: ./alpha" + " #{alpha_env}".rstrip
file.puts "\n"
file.puts "bravo:\t./bravo"
file.puts "foo_bar:\t./foo_bar"
file.puts "foo-bar:\t./foo-bar"
file.puts "# baz:\t./baz"
end
File.expand_path(procfile)
end
def write_file(file)
FileUtils.mkdir_p(File.dirname(file))
File.open(file, 'w') do |f|
yield(f)
end
end
def write_env(env=".env", options={"FOO"=>"bar"})
File.open(env, "w") do |file|
options.each do |key, val|
file.puts "#{key}=#{val}"
end
end
end
def without_fakefs
FakeFS.deactivate!
ret = yield
FakeFS.activate!
ret
end
def load_export_templates_into_fakefs(type)
without_fakefs do
Dir[File.expand_path("../../data/export/#{type}/**/*", __FILE__)].inject({}) do |hash, file|
next(hash) if File.directory?(file)
hash.update(file => File.read(file))
end
end.each do |filename, contents|
FileUtils.mkdir_p File.dirname(filename)
File.open(filename, "w") do |f|
f.puts contents
end
end
end
def resource_path(filename)
File.expand_path("../resources/#{filename}", __FILE__)
end
def example_export_file(filename)
FakeFS.deactivate!
data = File.read(File.expand_path(resource_path("export/#{filename}"), __FILE__))
FakeFS.activate!
data
end
def preserving_env
old_env = ENV.to_hash
begin
yield
ensure
ENV.clear
ENV.update(old_env)
end
end
def normalize_space(s)
s.gsub(/\n[\n\s]*/, "\n")
end
def capture_stdout
old_stdout = $stdout.dup
rd, wr = make_pipe
$stdout = wr
yield
wr.close
rd.read
ensure
$stdout = old_stdout
end
RSpec.configure do |config|
config.color = true
config.order = 'rand'
config.include FakeFS::SpecHelpers, :fakefs
config.before(:each) do
FileUtils.mkdir_p('/tmp')
end
config.after(:each) do
FileUtils.rm_rf('/tmp')
end
end
foreman-0.85.0/foreman.gemspec 0000644 0000041 0000041 00000013155 13312112240 016251 0 ustar www-data www-data #########################################################
# This file has been automatically generated by gem2tgz #
#########################################################
# -*- encoding: utf-8 -*-
# stub: foreman 0.85.0 ruby lib
Gem::Specification.new do |s|
s.name = "foreman".freeze
s.version = "0.85.0"
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
s.require_paths = ["lib".freeze]
s.authors = ["David Dollar".freeze]
s.date = "2018-06-18"
s.description = "Process manager for applications with multiple components".freeze
s.email = "ddollar@gmail.com".freeze
s.executables = ["foreman".freeze]
s.files = ["README.md".freeze, "bin/foreman".freeze, "bin/foreman-runner".freeze, "data/example/Procfile".freeze, "data/example/Procfile.without_colon".freeze, "data/example/error".freeze, "data/example/log/neverdie.log".freeze, "data/example/spawnee".freeze, "data/example/spawner".freeze, "data/example/ticker".freeze, "data/example/utf8".freeze, "data/export/bluepill/master.pill.erb".freeze, "data/export/daemon/master.conf.erb".freeze, "data/export/daemon/process.conf.erb".freeze, "data/export/daemon/process_master.conf.erb".freeze, "data/export/launchd/launchd.plist.erb".freeze, "data/export/runit/log/run.erb".freeze, "data/export/runit/run.erb".freeze, "data/export/supervisord/app.conf.erb".freeze, "data/export/systemd/master.target.erb".freeze, "data/export/systemd/process.service.erb".freeze, "data/export/systemd/process_master.target.erb".freeze, "data/export/upstart/master.conf.erb".freeze, "data/export/upstart/process.conf.erb".freeze, "data/export/upstart/process_master.conf.erb".freeze, "lib/foreman.rb".freeze, "lib/foreman/cli.rb".freeze, "lib/foreman/distribution.rb".freeze, "lib/foreman/engine.rb".freeze, "lib/foreman/engine/cli.rb".freeze, "lib/foreman/env.rb".freeze, "lib/foreman/export.rb".freeze, "lib/foreman/export/base.rb".freeze, "lib/foreman/export/bluepill.rb".freeze, "lib/foreman/export/daemon.rb".freeze, "lib/foreman/export/inittab.rb".freeze, "lib/foreman/export/launchd.rb".freeze, "lib/foreman/export/runit.rb".freeze, "lib/foreman/export/supervisord.rb".freeze, "lib/foreman/export/systemd.rb".freeze, "lib/foreman/export/upstart.rb".freeze, "lib/foreman/helpers.rb".freeze, "lib/foreman/process.rb".freeze, "lib/foreman/procfile.rb".freeze, "lib/foreman/version.rb".freeze, "man/foreman.1".freeze, "spec/foreman/cli_spec.rb".freeze, "spec/foreman/engine_spec.rb".freeze, "spec/foreman/export/base_spec.rb".freeze, "spec/foreman/export/bluepill_spec.rb".freeze, "spec/foreman/export/daemon_spec.rb".freeze, "spec/foreman/export/inittab_spec.rb".freeze, "spec/foreman/export/launchd_spec.rb".freeze, "spec/foreman/export/runit_spec.rb".freeze, "spec/foreman/export/supervisord_spec.rb".freeze, "spec/foreman/export/systemd_spec.rb".freeze, "spec/foreman/export/upstart_spec.rb".freeze, "spec/foreman/export_spec.rb".freeze, "spec/foreman/helpers_spec.rb".freeze, "spec/foreman/process_spec.rb".freeze, "spec/foreman/procfile_spec.rb".freeze, "spec/foreman_spec.rb".freeze, "spec/helper_spec.rb".freeze, "spec/resources/Procfile".freeze, "spec/resources/Procfile.bad".freeze, "spec/resources/bin/echo".freeze, "spec/resources/bin/env".freeze, "spec/resources/bin/test".freeze, "spec/resources/bin/utf8".freeze, "spec/resources/export/bluepill/app-concurrency.pill".freeze, "spec/resources/export/bluepill/app.pill".freeze, "spec/resources/export/daemon/app-alpha-1.conf".freeze, "spec/resources/export/daemon/app-alpha-2.conf".freeze, "spec/resources/export/daemon/app-alpha.conf".freeze, "spec/resources/export/daemon/app-bravo-1.conf".freeze, "spec/resources/export/daemon/app-bravo.conf".freeze, "spec/resources/export/daemon/app.conf".freeze, "spec/resources/export/inittab/inittab.concurrency".freeze, "spec/resources/export/inittab/inittab.default".freeze, "spec/resources/export/launchd/launchd-a.default".freeze, "spec/resources/export/launchd/launchd-b.default".freeze, "spec/resources/export/launchd/launchd-c.default".freeze, "spec/resources/export/runit/app-alpha-1/log/run".freeze, "spec/resources/export/runit/app-alpha-1/run".freeze, "spec/resources/export/runit/app-alpha-2/log/run".freeze, "spec/resources/export/runit/app-alpha-2/run".freeze, "spec/resources/export/runit/app-bravo-1/log/run".freeze, "spec/resources/export/runit/app-bravo-1/run".freeze, "spec/resources/export/supervisord/app-alpha-1.conf".freeze, "spec/resources/export/supervisord/app-alpha-2.conf".freeze, "spec/resources/export/systemd/app-alpha.target".freeze, "spec/resources/export/systemd/app-alpha@.service".freeze, "spec/resources/export/systemd/app-bravo.target".freeze, "spec/resources/export/systemd/app-bravo@.service".freeze, "spec/resources/export/systemd/app.target".freeze, "spec/resources/export/upstart/app-alpha-1.conf".freeze, "spec/resources/export/upstart/app-alpha-2.conf".freeze, "spec/resources/export/upstart/app-alpha.conf".freeze, "spec/resources/export/upstart/app-bravo-1.conf".freeze, "spec/resources/export/upstart/app-bravo.conf".freeze, "spec/resources/export/upstart/app.conf".freeze, "spec/spec_helper.rb".freeze]
s.homepage = "http://github.com/ddollar/foreman".freeze
s.licenses = ["MIT".freeze]
s.rubygems_version = "2.5.2.1".freeze
s.summary = "Process manager for applications with multiple components".freeze
if s.respond_to? :specification_version then
s.specification_version = 4
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q.freeze, ["~> 0.19.1"])
else
s.add_dependency(%q.freeze, ["~> 0.19.1"])
end
else
s.add_dependency(%q.freeze, ["~> 0.19.1"])
end
end
foreman-0.85.0/data/ 0000755 0000041 0000041 00000000000 13312112240 014161 5 ustar www-data www-data foreman-0.85.0/data/export/ 0000755 0000041 0000041 00000000000 13312112240 015502 5 ustar www-data www-data foreman-0.85.0/data/export/systemd/ 0000755 0000041 0000041 00000000000 13312112240 017172 5 ustar www-data www-data foreman-0.85.0/data/export/systemd/master.target.erb 0000644 0000041 0000041 00000000131 13312112240 022437 0 ustar www-data www-data [Unit]
Wants=<%= process_master_names.join(' ') %>
[Install]
WantedBy=multi-user.target
foreman-0.85.0/data/export/systemd/process.service.erb 0000644 0000041 0000041 00000000655 13312112240 023007 0 ustar www-data www-data [Unit]
PartOf=<%= app %>-<%= name %>.target
[Service]
User=<%= user %>
WorkingDirectory=<%= engine.root %>
Environment=PORT=%i
<% engine.env.each_pair do |var,env| -%>
Environment="<%= var %>=<%= env %>"
<% end -%>
ExecStart=/bin/bash -lc 'exec <%= process.command %>'
Restart=always
StandardInput=null
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=%n
KillMode=mixed
TimeoutStopSec=<%= engine.options[:timeout] %>
foreman-0.85.0/data/export/systemd/process_master.target.erb 0000644 0000041 0000041 00000000040 13312112240 024174 0 ustar www-data www-data [Unit]
PartOf=<%= app %>.target
foreman-0.85.0/data/export/supervisord/ 0000755 0000041 0000041 00000000000 13312112240 020067 5 ustar www-data www-data foreman-0.85.0/data/export/supervisord/app.conf.erb 0000644 0000041 0000041 00000001466 13312112240 022274 0 ustar www-data www-data <%
app_names = []
engine.each_process do |name, process|
1.upto(engine.formation[name]) do |num|
port = engine.port_for(process, num)
full_name = "#{app}-#{name}-#{num}"
environment = engine.env.merge("PORT" => port.to_s).map do |key, value|
value = shell_quote(value)
value = value.gsub('\=', '=')
value = value.gsub('\&', '&')
value = value.gsub('\?', '?')
"#{key}=\"#{value}\""
end
app_names << full_name
-%>
[program:<%= full_name %>]
command=<%= process.command %>
autostart=true
autorestart=true
stdout_logfile=<%= log %>/<%= name %>-<%= num %>.log
stderr_logfile=<%= log %>/<%= name %>-<%= num %>.error.log
user=<%= user %>
directory=<%= engine.root %>
environment=<%= environment.join(',') %>
<%
end
end
-%>
[group:<%= app %>]
programs=<%= app_names.join(',') %>
foreman-0.85.0/data/export/runit/ 0000755 0000041 0000041 00000000000 13312112240 016643 5 ustar www-data www-data foreman-0.85.0/data/export/runit/log/ 0000755 0000041 0000041 00000000000 13312112240 017424 5 ustar www-data www-data foreman-0.85.0/data/export/runit/log/run.erb 0000644 0000041 0000041 00000000247 13312112240 020725 0 ustar www-data www-data #!/bin/sh
set -e
LOG=<%= log %>/<%= name %>-<%= num %>
test -d "$LOG" || mkdir -p -m 2750 "$LOG" && chown <%= user %> "$LOG"
exec chpst -u <%= user %> svlogd "$LOG"
foreman-0.85.0/data/export/runit/run.erb 0000644 0000041 0000041 00000000226 13312112240 020141 0 ustar www-data www-data #!/bin/sh
cd <%= engine.root %>
exec 2>&1
exec chpst -u <%= user %> -e <%= File.join(location, "#{process_directory}/env") %> <%= process.command %>
foreman-0.85.0/data/export/upstart/ 0000755 0000041 0000041 00000000000 13312112240 017204 5 ustar www-data www-data foreman-0.85.0/data/export/upstart/process.conf.erb 0000644 0000041 0000041 00000000505 13312112240 022300 0 ustar www-data www-data start on starting <%= app %>-<%= name %>
stop on stopping <%= app %>-<%= name %>
respawn
env PORT=<%= port %>
<% engine.env.each do |name,value| -%>
<% next if name.upcase == "PORT" -%>
env <%= name %>='<%= value.gsub(/'/, "'\"'\"'") %>'
<% end -%>
setuid <%= user %>
chdir <%= engine.root %>
exec <%= process.command %>
foreman-0.85.0/data/export/upstart/process_master.conf.erb 0000644 0000041 0000041 00000000071 13312112240 023651 0 ustar www-data www-data start on starting <%= app %>
stop on stopping <%= app %>
foreman-0.85.0/data/export/upstart/master.conf.erb 0000644 0000041 0000041 00000000062 13312112240 022113 0 ustar www-data www-data start on runlevel [2345]
stop on runlevel [!2345]
foreman-0.85.0/data/export/launchd/ 0000755 0000041 0000041 00000000000 13312112240 017120 5 ustar www-data www-data foreman-0.85.0/data/export/launchd/launchd.plist.erb 0000644 0000041 0000041 00000002005 13312112240 022357 0 ustar www-data www-data
Label
<%= "#{app}-#{name}-#{num}" %>
EnvironmentVariables
<%- engine.env.merge("PORT" => port).each_pair do |var,env| -%>
<%= var %>
<%= env %>
<%- end -%>
ProgramArguments
<%- command_args.each do |command| -%>
<%= command %>
<%- end -%>
KeepAlive
RunAtLoad
StandardOutPath
<%= log %>/<%= app %>-<%= name %>-<%=num%>.log
StandardErrorPath
<%= log %>/<%= app %>-<%= name %>-<%=num%>.log
UserName
<%= user %>
WorkingDirectory
<%= engine.root %>
foreman-0.85.0/data/export/daemon/ 0000755 0000041 0000041 00000000000 13312112240 016745 5 ustar www-data www-data foreman-0.85.0/data/export/daemon/process.conf.erb 0000644 0000041 0000041 00000000723 13312112240 022043 0 ustar www-data www-data start on starting <%= app %>-<%= name.gsub('_', '-') %>
stop on stopping <%= app %>-<%= name.gsub('_', '-') %>
respawn
env PORT=<%= port %><% engine.env.each_pair do |var, env| %>
env <%= var %>=<%= env %><% end %>
exec start-stop-daemon --start --chuid <%= user %> --chdir <%= engine.root %> --make-pidfile --pidfile <%= run %>/<%= app %>-<%= name %>-<%= num %>.pid --exec <%= executable %><%= arguments %> >> <%= log %>/<%= app %>-<%= name %>-<%= num %>.log 2>&1
foreman-0.85.0/data/export/daemon/process_master.conf.erb 0000644 0000041 0000041 00000000071 13312112240 023412 0 ustar www-data www-data start on starting <%= app %>
stop on stopping <%= app %>
foreman-0.85.0/data/export/daemon/master.conf.erb 0000644 0000041 0000041 00000000312 13312112240 021652 0 ustar www-data www-data pre-start script
bash << "EOF"
mkdir -p <%= log %>
chown -R <%= user %> <%= log %>
mkdir -p <%= run %>
chown -R <%= user %> <%= run %>
EOF
end script
start on runlevel [2345]
stop on runlevel [016]
foreman-0.85.0/data/export/bluepill/ 0000755 0000041 0000041 00000000000 13312112240 017312 5 ustar www-data www-data foreman-0.85.0/data/export/bluepill/master.pill.erb 0000644 0000041 0000041 00000001644 13312112240 022243 0 ustar www-data www-data Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/bluepill.log") do |app|
app.uid = "<%= user %>"
app.gid = "<%= user %>"
<% engine.each_process do |name, process| %>
<% 1.upto(engine.formation[name]) do |num| %>
<% port = engine.port_for(process, num) %>
app.process("<%= name %>-<%= num %>") do |process|
process.start_command = %Q{<%= process.command %>}
process.working_dir = "<%= engine.root %>"
process.daemonize = true
process.environment = <%= engine.env.merge("PORT" => port.to_s).inspect %>
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
process.stop_grace_time = 45.seconds
process.stdout = process.stderr = "<%= log %>/<%= app %>-<%= name %>-<%= num %>.log"
process.monitor_children do |children|
children.stop_command "kill {{PID}}"
end
process.group = "<%= app %>-<%= name %>"
end
<% end %>
<% end %>
end
foreman-0.85.0/data/example/ 0000755 0000041 0000041 00000000000 13312112240 015614 5 ustar www-data www-data foreman-0.85.0/data/example/ticker 0000755 0000041 0000041 00000000355 13312112240 017026 0 ustar www-data www-data #!/usr/bin/env ruby
$stdout.sync = true
%w( SIGINT SIGTERM ).each do |signal|
trap(signal) do
puts "received #{signal} but i'm ignoring it!"
end
end
while true
puts "tick: #{ARGV.inspect} -- FOO:#{ENV["FOO"]}"
sleep 1
end
foreman-0.85.0/data/example/Procfile 0000644 0000041 0000041 00000000133 13312112240 017277 0 ustar www-data www-data ticker: ruby ./ticker $PORT
error: ruby ./error
utf8: ruby ./utf8
spawner: ./spawner
foreman-0.85.0/data/example/log/ 0000755 0000041 0000041 00000000000 13312112240 016375 5 ustar www-data www-data foreman-0.85.0/data/example/log/neverdie.log 0000644 0000041 0000041 00000000102 13312112240 020672 0 ustar www-data www-data tick
tick
./never_die:6:in `sleep': Interrupt
from ./never_die:6
foreman-0.85.0/data/example/utf8 0000755 0000041 0000041 00000000364 13312112240 016433 0 ustar www-data www-data #!/usr/bin/env ruby
# encoding: BINARY
$stdout.sync = true
while true
puts "\u65e5\u672c\u8a9e\u6587\u5b57\u5217"
puts "\u0915\u0932\u094d\u0907\u0928\u0643\u0637\u0628\u041a\u0430\u043b\u0438\u043d\u0430"
puts "\xff\x03"
sleep 1
end
foreman-0.85.0/data/example/spawnee 0000755 0000041 0000041 00000000216 13312112240 017203 0 ustar www-data www-data #!/bin/sh
NAME="$1"
sigterm() {
echo "$NAME: got sigterm"
}
#trap sigterm SIGTERM
while true; do
echo "$NAME: ping $$"
sleep 1
done
foreman-0.85.0/data/example/Procfile.without_colon 0000644 0000041 0000041 00000000044 13312112240 022174 0 ustar www-data www-data ticker ./ticker $PORT
error ./error foreman-0.85.0/data/example/error 0000755 0000041 0000041 00000000131 13312112240 016666 0 ustar www-data www-data #!/usr/bin/env ruby
$stdout.sync = true
puts "will error in 10s"
sleep 5
raise "Dying"
foreman-0.85.0/data/example/spawner 0000755 0000041 0000041 00000000073 13312112240 017221 0 ustar www-data www-data #!/bin/sh
./spawnee A &
./spawnee B &
./spawnee C &
wait
foreman-0.85.0/man/ 0000755 0000041 0000041 00000000000 13312112240 014023 5 ustar www-data www-data foreman-0.85.0/man/foreman.1 0000644 0000041 0000041 00000014777 13312112240 015554 0 ustar www-data www-data .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "FOREMAN" "1" "March 2017" "Foreman 0.85.0" "Foreman Manual"
.
.SH "NAME"
\fBforeman\fR \- manage Procfile\-based applications
.
.SH "SYNOPSIS"
\fBforeman start [process]\fR
.
.br
\fBforeman run \fR
.
.br
\fBforeman export [location]\fR
.
.SH "DESCRIPTION"
Foreman is a manager for Procfile\-based applications\. Its aim is to abstract away the details of the Procfile format, and allow you to either run your application directly or export it to some other process management format\.
.
.SH "RUNNING"
\fBforeman start\fR is used to run your application directly from the command line\.
.
.P
If no additional parameters are passed, foreman will run one instance of each type of process defined in your Procfile\.
.
.P
If a parameter is passed, foreman will run one instance of the specified application type\.
.
.P
The following options control how the application is run:
.
.TP
\fB\-m\fR, \fB\-\-formation\fR
Specify the number of each process type to run\. The value passed in should be in the format \fBprocess=num,process=num\fR
.
.TP
\fB\-e\fR, \fB\-\-env\fR
Specify one or more \.env files to load
.
.TP
\fB\-f\fR, \fB\-\-procfile\fR
Specify an alternate Procfile to load, implies \fB\-d\fR at the Procfile root\.
.
.TP
\fB\-p\fR, \fB\-\-port\fR
Specify which port to use as the base for this application\. Should be a multiple of 1000\.
.
.TP
\fB\-t\fR, \fB\-\-timeout\fR
Specify the amount of time (in seconds) processes have to shutdown gracefully before receiving a SIGKILL, defaults to 5\.
.
.P
\fBforeman run\fR is used to run one\-off commands using the same environment as your defined processes\.
.
.SH "EXPORTING"
\fBforeman export\fR is used to export your application to another process management format\.
.
.P
A location to export can be passed as an argument\. This argument may be either required or optional depending on the export format\.
.
.P
The following options control how the application is run:
.
.TP
\fB\-a\fR, \fB\-\-app\fR
Use this name rather than the application\'s root directory name as the name of the application when exporting\.
.
.TP
\fB\-m\fR, \fB\-\-formation\fR
Specify the number of each process type to run\. The value passed in should be in the format \fBprocess=num,process=num\fR
.
.TP
\fB\-l\fR, \fB\-\-log\fR
Specify the directory to place process logs in\.
.
.TP
\fB\-p\fR, \fB\-\-port\fR
Specify which port to use as the base for this application\. Should be a multiple of 1000\.
.
.TP
\fB\-t\fR, \fB\-\-template\fR
Specify an alternate template to use for creating export files\. See \fIhttps://github\.com/ddollar/foreman/tree/master/data/export\fR for examples\.
.
.TP
\fB\-u\fR, \fB\-\-user\fR
Specify the user the application should be run as\. Defaults to the app name
.
.SH "GLOBAL OPTIONS"
These options control all modes of foreman\'s operation\.
.
.TP
\fB\-d\fR, \fB\-\-root\fR
Specify an alternate application root\. This defaults to the directory containing the Procfile\.
.
.TP
\fB\-e\fR, \fB\-\-env\fR
Specify an alternate environment file\. You can specify more than one file by using: \fB\-\-env file1,file2\fR\.
.
.TP
\fB\-f\fR, \fB\-\-procfile\fR
Specify an alternate location for the application\'s Procfile\. This file\'s containing directory will be assumed to be the root directory of the application\.
.
.SH "EXPORT FORMATS"
foreman currently supports the following output formats:
.
.IP "\(bu" 4
bluepill
.
.IP "\(bu" 4
inittab
.
.IP "\(bu" 4
launchd
.
.IP "\(bu" 4
runit
.
.IP "\(bu" 4
supervisord
.
.IP "\(bu" 4
systemd
.
.IP "\(bu" 4
upstart
.
.IP "" 0
.
.SH "INITTAB EXPORT"
Will export a chunk of inittab\-compatible configuration:
.
.IP "" 4
.
.nf
# \-\-\-\-\- foreman example processes \-\-\-\-\-
EX01:4:respawn:/bin/su \- example \-c \'PORT=5000 bundle exec thin start >> /var/log/web\-1\.log 2>&1\'
EX02:4:respawn:/bin/su \- example \-c \'PORT=5100 bundle exec rake jobs:work >> /var/log/job\-1\.log 2>&1\'
# \-\-\-\-\- end foreman example processes \-\-\-\-\-
.
.fi
.
.IP "" 0
.
.SH "SYSTEMD EXPORT"
Will create a series of systemd scripts in the location you specify\. Scripts will be structured to make the following commands valid:
.
.P
\fBsystemctl start appname\.target\fR
.
.P
\fBsystemctl stop appname\-processname\.target\fR
.
.P
\fBsystemctl restart appname\-processname\-3\.service\fR
.
.SH "UPSTART EXPORT"
Will create a series of upstart scripts in the location you specify\. Scripts will be structured to make the following commands valid:
.
.P
\fBstart appname\fR
.
.P
\fBstop appname\-processname\fR
.
.P
\fBrestart appname\-processname\-3\fR
.
.SH "PROCFILE"
A Procfile should contain both a name for the process and the command used to run it\.
.
.IP "" 4
.
.nf
web: bundle exec thin start
job: bundle exec rake jobs:work
.
.fi
.
.IP "" 0
.
.P
A process name may contain letters, numbers and the underscore character\. You can validate your Procfile format using the \fBcheck\fR command:
.
.IP "" 4
.
.nf
$ foreman check
.
.fi
.
.IP "" 0
.
.P
The special environment variables \fB$PORT\fR and \fB$PS\fR are available within the Procfile\. \fB$PORT\fR is the port selected for that process\. \fB$PS\fR is the name of the process for the line\.
.
.P
The \fB$PORT\fR value starts as the base port as specified by \fB\-p\fR, then increments by 100 for each new process line\. Multiple instances of the same process are assigned \fB$PORT\fR values that increment by 1\.
.
.SH "ENVIRONMENT"
If a \fB\.env\fR file exists in the current directory, the default environment will be read from it\. This file should contain key/value pairs, separated by \fB=\fR, with one key/value pair per line\.
.
.IP "" 4
.
.nf
FOO=bar
BAZ=qux
.
.fi
.
.IP "" 0
.
.SH "DEFAULT OPTIONS"
If a \fB\.foreman\fR file exists in the current directory, default options will be read from it\. This file should be in YAML format with the long option name as keys\. Example:
.
.IP "" 4
.
.nf
formation: alpha=0,bravo=1
port: 15000
.
.fi
.
.IP "" 0
.
.SH "EXAMPLES"
Start one instance of each process type, interleave the output on stdout:
.
.IP "" 4
.
.nf
$ foreman start
.
.fi
.
.IP "" 0
.
.P
Export the application in upstart format:
.
.IP "" 4
.
.nf
$ foreman export upstart /etc/init
.
.fi
.
.IP "" 0
.
.P
Run one process type from the application defined in a specific Procfile:
.
.IP "" 4
.
.nf
$ foreman start alpha \-f ~/myapp/Procfile
.
.fi
.
.IP "" 0
.
.P
Start all processes except the one named worker:
.
.IP "" 4
.
.nf
$ foreman start \-m all=1,worker=0
.
.fi
.
.IP "" 0
.
.SH "COPYRIGHT"
Foreman is Copyright (C) 2010 David Dollar \fIhttp://daviddollar\.org\fR
foreman-0.85.0/lib/ 0000755 0000041 0000041 00000000000 13312112240 014016 5 ustar www-data www-data foreman-0.85.0/lib/foreman.rb 0000644 0000041 0000041 00000000463 13312112240 015775 0 ustar www-data www-data require "foreman/version"
module Foreman
def self.runner
File.expand_path("../../bin/foreman-runner", __FILE__)
end
def self.ruby_18?
defined?(RUBY_VERSION) and RUBY_VERSION =~ /^1\.8\.\d+/
end
def self.windows?
defined?(RUBY_PLATFORM) and RUBY_PLATFORM =~ /(win|w)32$/
end
end
foreman-0.85.0/lib/foreman/ 0000755 0000041 0000041 00000000000 13312112240 015445 5 ustar www-data www-data foreman-0.85.0/lib/foreman/version.rb 0000644 0000041 0000041 00000000052 13312112240 017454 0 ustar www-data www-data module Foreman
VERSION = "0.85.0"
end
foreman-0.85.0/lib/foreman/export/ 0000755 0000041 0000041 00000000000 13312112240 016766 5 ustar www-data www-data foreman-0.85.0/lib/foreman/export/runit.rb 0000644 0000041 0000041 00000001656 13312112240 020464 0 ustar www-data www-data require "erb"
require "foreman/export"
class Foreman::Export::Runit < Foreman::Export::Base
ENV_VARIABLE_REGEX = /([a-zA-Z_]+[a-zA-Z0-9_]*)=(\S+)/
def export
super
engine.each_process do |name, process|
1.upto(engine.formation[name]) do |num|
process_directory = "#{app}-#{name}-#{num}"
create_directory process_directory
create_directory "#{process_directory}/env"
create_directory "#{process_directory}/log"
write_template "runit/run.erb", "#{process_directory}/run", binding
chmod 0755, "#{process_directory}/run"
port = engine.port_for(process, num)
engine.env.merge("PORT" => port.to_s).each do |key, value|
write_file "#{process_directory}/env/#{key}", value
end
write_template "runit/log/run.erb", "#{process_directory}/log/run", binding
chmod 0755, "#{process_directory}/log/run"
end
end
end
end
foreman-0.85.0/lib/foreman/export/systemd.rb 0000644 0000041 0000041 00000002372 13312112240 021007 0 ustar www-data www-data require "erb"
require "foreman/export"
class Foreman::Export::Systemd < Foreman::Export::Base
def export
super
Dir["#{location}/#{app}*.target"]
.concat(Dir["#{location}/#{app}*.service"])
.concat(Dir["#{location}/#{app}*.target.wants/#{app}*.service"])
.each do |file|
clean file
end
Dir["#{location}/#{app}*.target.wants"].each do |file|
clean_dir file
end
process_master_names = []
engine.each_process do |name, process|
service_fn = "#{app}-#{name}@.service"
write_template "systemd/process.service.erb", service_fn, binding
create_directory("#{app}-#{name}.target.wants")
1.upto(engine.formation[name])
.collect { |num| engine.port_for(process, num) }
.collect { |port| "#{app}-#{name}@#{port}.service" }
.each do |process_name|
create_symlink("#{app}-#{name}.target.wants/#{process_name}", "../#{service_fn}") rescue Errno::EEXIST # This is needed because rr-mocks do not call the origial cleanup
end
write_template "systemd/process_master.target.erb", "#{app}-#{name}.target", binding
process_master_names << "#{app}-#{name}.target"
end
write_template "systemd/master.target.erb", "#{app}.target", binding
end
end
foreman-0.85.0/lib/foreman/export/bluepill.rb 0000644 0000041 0000041 00000000355 13312112240 021126 0 ustar www-data www-data require "erb"
require "foreman/export"
class Foreman::Export::Bluepill < Foreman::Export::Base
def export
super
clean "#{location}/#{app}.pill"
write_template "bluepill/master.pill.erb", "#{app}.pill", binding
end
end
foreman-0.85.0/lib/foreman/export/inittab.rb 0000644 0000041 0000041 00000002136 13312112240 020747 0 ustar www-data www-data require "foreman/export"
class Foreman::Export::Inittab < Foreman::Export::Base
def export
error("Must specify a location") unless location
inittab = []
inittab << "# ----- foreman #{app} processes -----"
index = 1
engine.each_process do |name, process|
1.upto(engine.formation[name]) do |num|
id = app.slice(0, 2).upcase + sprintf("%02d", index)
port = engine.port_for(process, num)
commands = []
commands << "cd #{engine.root}"
commands << "export PORT=#{port}"
engine.env.each_pair do |var, env|
commands << "export #{var.upcase}=#{shell_quote(env)}"
end
commands << "#{process.command} >> #{log}/#{name}-#{num}.log 2>&1"
inittab << "#{id}:4:respawn:/bin/su - #{user} -c '#{commands.join(";")}'"
index += 1
end
end
inittab << "# ----- end foreman #{app} processes -----"
inittab = inittab.join("\n") + "\n"
if location == "-"
puts inittab
else
say "writing: #{location}"
File.open(location, "w") { |file| file.puts inittab }
end
end
end
foreman-0.85.0/lib/foreman/export/base.rb 0000644 0000041 0000041 00000010466 13312112240 020234 0 ustar www-data www-data require "foreman/export"
require "ostruct"
require "pathname"
require "shellwords"
class Foreman::Export::Base
attr_reader :location
attr_reader :engine
attr_reader :options
attr_reader :formation
# deprecated
attr_reader :port
def initialize(location, engine, options={})
@location = location
@engine = engine
@options = options.dup
@formation = engine.formation
# deprecated
def port
Foreman::Export::Base.warn_deprecation!
engine.base_port
end
# deprecated
def template
Foreman::Export::Base.warn_deprecation!
options[:template]
end
# deprecated
def @engine.procfile
Foreman::Export::Base.warn_deprecation!
@processes.map do |process|
OpenStruct.new(
:name => @names[process],
:process => process
)
end
end
end
def export
error("Must specify a location") unless location
FileUtils.mkdir_p(location) rescue error("Could not create: #{location}")
chown user, log
chown user, run
end
def app
options[:app] || "app"
end
def log
options[:log] || "/var/log/#{app}"
end
def run
options[:run] || "/var/run/#{app}"
end
def user
options[:user] || app
end
private ######################################################################
def self.warn_deprecation!
@@deprecation_warned ||= false
return if @@deprecation_warned
puts "WARNING: Using deprecated exporter interface. Please update your exporter"
puts "the interface shown in the upstart exporter:"
puts
puts "https://github.com/ddollar/foreman/blob/master/lib/foreman/export/upstart.rb"
puts "https://github.com/ddollar/foreman/blob/master/data/export/upstart/process.conf.erb"
puts
@@deprecation_warned = true
end
def chown user, dir
FileUtils.chown user, nil, dir
rescue
error("Could not chown #{dir} to #{user}") unless File.writable?(dir) || ! File.exists?(dir)
end
def error(message)
raise Foreman::Export::Exception.new(message)
end
def say(message)
puts "[foreman export] %s" % message
end
def clean(filename)
return unless File.exists?(filename)
say "cleaning up: #{filename}"
FileUtils.rm(filename)
end
def clean_dir(dirname)
return unless File.exists?(dirname)
say "cleaning up directory: #{dirname}"
FileUtils.rm_r(dirname)
end
def shell_quote(value)
Shellwords.escape(value)
end
# deprecated
def old_export_template(exporter, file, template_root)
if template_root && File.exist?(file_path = File.join(template_root, file))
File.read(file_path)
elsif File.exist?(file_path = File.expand_path(File.join("~/.foreman/templates", file)))
File.read(file_path)
else
File.read(File.expand_path("../../../../data/export/#{exporter}/#{file}", __FILE__))
end
end
def export_template(name, file=nil, template_root=nil)
if file && template_root
old_export_template name, file, template_root
else
name_without_first = name.split("/")[1..-1].join("/")
matchers = []
matchers << File.join(options[:template], name_without_first) if options[:template]
matchers << File.expand_path("~/.foreman/templates/#{name}")
matchers << File.expand_path("../../../../data/export/#{name}", __FILE__)
File.read(matchers.detect { |m| File.exists?(m) })
end
end
def write_template(name, target, binding)
compiled = if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
ERB.new(export_template(name), trim_mode: '-').result(binding)
else
ERB.new(export_template(name), nil, '-').result(binding)
end
write_file target, compiled
end
def chmod(mode, file)
say "setting #{file} to mode #{mode}"
FileUtils.chmod mode, File.join(location, file)
end
def create_directory(dir)
say "creating: #{dir}"
FileUtils.mkdir_p(File.join(location, dir))
end
def create_symlink(link, target)
say "symlinking: #{link} -> #{target}"
FileUtils.symlink(target, File.join(location, link))
end
def write_file(filename, contents)
say "writing: #{filename}"
filename = File.join(location, filename) unless Pathname.new(filename).absolute?
File.open(filename, "w") do |file|
file.puts contents
end
end
end
foreman-0.85.0/lib/foreman/export/upstart.rb 0000644 0000041 0000041 00000002025 13312112240 021014 0 ustar www-data www-data require "erb"
require "foreman/export"
class Foreman::Export::Upstart < Foreman::Export::Base
def export
super
master_file = "#{app}.conf"
clean File.join(location, master_file)
write_template master_template, master_file, binding
engine.each_process do |name, process|
process_master_file = "#{app}-#{name}.conf"
process_file = "#{app}-#{name}-%s.conf"
Dir[
File.join(location, process_master_file),
File.join(location, process_file % "*")
].each { |f| clean(f) }
next if engine.formation[name] < 1
write_template process_master_template, process_master_file, binding
1.upto(engine.formation[name]) do |num|
port = engine.port_for(process, num)
write_template process_template, process_file % num, binding
end
end
end
private
def master_template
"upstart/master.conf.erb"
end
def process_master_template
"upstart/process_master.conf.erb"
end
def process_template
"upstart/process.conf.erb"
end
end
foreman-0.85.0/lib/foreman/export/supervisord.rb 0000644 0000041 0000041 00000000431 13312112240 021676 0 ustar www-data www-data require "erb"
require "foreman/export"
class Foreman::Export::Supervisord < Foreman::Export::Base
def export
super
Dir["#{location}/#{app}.conf"].each do |file|
clean file
end
write_template "supervisord/app.conf.erb", "#{app}.conf", binding
end
end
foreman-0.85.0/lib/foreman/export/daemon.rb 0000644 0000041 0000041 00000001506 13312112240 020560 0 ustar www-data www-data require "erb"
require "foreman/export"
class Foreman::Export::Daemon < Foreman::Export::Base
def export
super
(Dir["#{location}/#{app}-*.conf"] << "#{location}/#{app}.conf").each do |file|
clean file
end
write_template "daemon/master.conf.erb", "#{app}.conf", binding
engine.each_process do |name, process|
next if engine.formation[name] < 1
write_template "daemon/process_master.conf.erb", "#{app}-#{name}.conf", binding
1.upto(engine.formation[name]) do |num|
port = engine.port_for(process, num)
arguments = process.command.split(" ")
executable = arguments.slice!(0)
arguments = arguments.size > 0 ? " -- #{arguments.join(' ')}" : ""
write_template "daemon/process.conf.erb", "#{app}-#{name}-#{num}.conf", binding
end
end
end
end
foreman-0.85.0/lib/foreman/export/launchd.rb 0000644 0000041 0000041 00000001022 13312112240 020724 0 ustar www-data www-data require "erb"
require "foreman/export"
class Foreman::Export::Launchd < Foreman::Export::Base
def export
super
engine.each_process do |name, process|
1.upto(engine.formation[name]) do |num|
port = engine.port_for(process, num)
command_args = process.command.split(/\s+/).map{|arg|
case arg
when "$PORT" then port
else arg
end
}
write_template "launchd/launchd.plist.erb", "#{app}-#{name}-#{num}.plist", binding
end
end
end
end
foreman-0.85.0/lib/foreman/export.rb 0000644 0000041 0000041 00000001773 13312112240 017323 0 ustar www-data www-data require "foreman"
require "foreman/helpers"
require "pathname"
module Foreman::Export
extend Foreman::Helpers
class Exception < ::Exception; end
def self.formatter(format)
begin
require "foreman/export/#{ format.tr('-', '_') }"
classy_format = classify(format)
formatter = constantize("Foreman::Export::#{ classy_format }")
rescue NameError => ex
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
def self.error(message)
raise Foreman::Export::Exception.new(message)
end
end
require "foreman/export/base"
require "foreman/export/inittab"
require "foreman/export/upstart"
require "foreman/export/daemon"
require "foreman/export/bluepill"
require "foreman/export/runit"
require "foreman/export/supervisord"
require "foreman/export/launchd"
require "foreman/export/systemd"
foreman-0.85.0/lib/foreman/helpers.rb 0000644 0000041 0000041 00000002440 13312112240 017434 0 ustar www-data www-data 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
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
foreman-0.85.0/lib/foreman/procfile.rb 0000644 0000041 0000041 00000003562 13312112240 017603 0 ustar www-data www-data require "foreman"
# Reads and writes Procfiles
#
# A valid Procfile entry is captured by this regex:
#
# /^([A-Za-z0-9_]+):\s*(.+)$/
#
# All other lines are ignored.
#
class Foreman::Procfile
# Initialize a Procfile
#
# @param [String] filename (nil) An optional filename to read from
#
def initialize(filename=nil)
@entries = []
load(filename) if filename
end
# Yield each +Procfile+ entry in order
#
def entries
@entries.each do |(name, command)|
yield name, command
end
end
# Retrieve a +Procfile+ command by name
#
# @param [String] name The name of the Procfile entry to retrieve
#
def [](name)
if entry = @entries.detect { |n,c| name == n }
entry.last
end
end
# Create a +Procfile+ entry
#
# @param [String] name The name of the +Procfile+ entry to create
# @param [String] command The command of the +Procfile+ entry to create
#
def []=(name, command)
delete name
@entries << [name, command]
end
# Remove a +Procfile+ entry
#
# @param [String] name The name of the +Procfile+ entry to remove
#
def delete(name)
@entries.reject! { |n,c| name == n }
end
# Load a Procfile from a file
#
# @param [String] filename The filename of the +Procfile+ to load
#
def load(filename)
@entries.replace parse(filename)
end
# Save a Procfile to a file
#
# @param [String] filename Save the +Procfile+ to this file
#
def save(filename)
File.open(filename, 'w') do |file|
file.puts self.to_s
end
end
# Get the +Procfile+ as a +String+
#
def to_s
@entries.map do |name, command|
[ name, command ].join(": ")
end.join("\n")
end
private
def parse(filename)
File.read(filename).gsub("\r\n","\n").split("\n").map do |line|
if line =~ /^([A-Za-z0-9_-]+):\s*(.+)$/
[$1, $2]
end
end.compact
end
end
foreman-0.85.0/lib/foreman/engine.rb 0000644 0000041 0000041 00000027730 13312112240 017250 0 ustar www-data www-data require "foreman"
require "foreman/env"
require "foreman/process"
require "foreman/procfile"
require "tempfile"
require "fileutils"
require "thread"
class Foreman::Engine
# The signals that the engine cares about.
#
HANDLED_SIGNALS = [ :TERM, :INT, :HUP, :USR1, :USR2 ]
attr_reader :env
attr_reader :options
attr_reader :processes
# Create an +Engine+ for running processes
#
# @param [Hash] options
#
# @option options [String] :formation (all=1) The process formation to use
# @option options [Fixnum] :port (5000) The base port to assign to processes
# @option options [String] :root (Dir.pwd) The root directory from which to run processes
#
def initialize(options={})
@options = options.dup
@options[:formation] ||= "all=1"
@options[:timeout] ||= 5
@env = {}
@mutex = Mutex.new
@names = {}
@processes = []
@running = {}
@readers = {}
@shutdown = false
# Self-pipe for deferred signal-handling (ala djb: http://cr.yp.to/docs/selfpipe.html)
reader, writer = create_pipe
reader.close_on_exec = true if reader.respond_to?(:close_on_exec)
writer.close_on_exec = true if writer.respond_to?(:close_on_exec)
@selfpipe = { :reader => reader, :writer => writer }
# Set up a global signal queue
# http://blog.rubybestpractices.com/posts/ewong/016-Implementing-Signal-Handlers.html
Thread.main[:signal_queue] = []
end
# Start the processes registered to this +Engine+
#
def start
register_signal_handlers
startup
spawn_processes
watch_for_output
sleep 0.1
wait_for_shutdown_or_child_termination
shutdown
exit(@exitstatus) if @exitstatus
end
# Set up deferred signal handlers
#
def register_signal_handlers
HANDLED_SIGNALS.each do |sig|
if ::Signal.list.include? sig.to_s
trap(sig) { Thread.main[:signal_queue] << sig ; notice_signal }
end
end
end
# Unregister deferred signal handlers
#
def restore_default_signal_handlers
HANDLED_SIGNALS.each do |sig|
trap(sig, :DEFAULT) if ::Signal.list.include? sig.to_s
end
end
# Wake the main thread up via the selfpipe when there's a signal
#
def notice_signal
@selfpipe[:writer].write_nonblock( '.' )
rescue Errno::EAGAIN
# Ignore writes that would block
rescue Errno::EINTR
# Retry if another signal arrived while writing
retry
end
# Invoke the real handler for signal +sig+. This shouldn't be called directly
# by signal handlers, as it might invoke code which isn't re-entrant.
#
# @param [Symbol] sig the name of the signal to be handled
#
def handle_signal(sig)
case sig
when :TERM
handle_term_signal
when :INT
handle_interrupt
when :HUP
handle_hangup
when *HANDLED_SIGNALS
handle_signal_forward(sig)
else
system "unhandled signal #{sig}"
end
end
# Handle a TERM signal
#
def handle_term_signal
system "SIGTERM received, starting shutdown"
@shutdown = true
end
# Handle an INT signal
#
def handle_interrupt
system "SIGINT received, starting shutdown"
@shutdown = true
end
# Handle a HUP signal
#
def handle_hangup
system "SIGHUP received, starting shutdown"
@shutdown = true
end
def handle_signal_forward(signal)
system "#{signal} received, forwarding it to children"
kill_children signal
end
# Register a process to be run by this +Engine+
#
# @param [String] name A name for this process
# @param [String] command The command to run
# @param [Hash] options
#
# @option options [Hash] :env A custom environment for this process
#
def register(name, command, options={})
options[:env] ||= env
options[:cwd] ||= File.dirname(command.split(" ").first)
process = Foreman::Process.new(command, options)
@names[process] = name
@processes << process
end
# Clear the processes registered to this +Engine+
#
def clear
@names = {}
@processes = []
end
# Register processes by reading a Procfile
#
# @param [String] filename A Procfile from which to read processes to register
#
def load_procfile(filename)
options[:root] ||= File.dirname(filename)
Foreman::Procfile.new(filename).entries do |name, command|
register name, command, :cwd => options[:root]
end
self
end
# Load a .env file into the +env+ for this +Engine+
#
# @param [String] filename A .env file to load into the environment
#
def load_env(filename)
Foreman::Env.new(filename).entries do |name, value|
@env[name] = value
end
end
# Send a signal to all processes started by this +Engine+
#
# @param [String] signal The signal to send to each process
#
def kill_children(signal="SIGTERM")
if Foreman.windows?
@running.each do |pid, (process, index)|
system "sending #{signal} to #{name_for(pid)} at pid #{pid}"
begin
Process.kill(signal, pid)
rescue Errno::ESRCH, Errno::EPERM
end
end
else
begin
pids = @running.keys.compact
Process.kill signal, *pids unless pids.empty?
rescue Errno::ESRCH, Errno::EPERM
end
end
end
# Send a signal to the whole process group.
#
# @param [String] signal The signal to send
#
def killall(signal="SIGTERM")
if Foreman.windows?
kill_children(signal)
else
begin
Process.kill "-#{signal}", Process.pid
rescue Errno::ESRCH, Errno::EPERM
end
end
end
# Get the process formation
#
# @returns [Fixnum] The formation count for the specified process
#
def formation
@formation ||= parse_formation(options[:formation])
end
# List the available process names
#
# @returns [Array] A list of process names
#
def process_names
@processes.map { |p| @names[p] }
end
# Get the +Process+ for a specifid name
#
# @param [String] name The process name
#
# @returns [Foreman::Process] The +Process+ for the specified name
#
def process(name)
@names.invert[name]
end
# Yield each +Process+ in order
#
def each_process
process_names.each do |name|
yield name, process(name)
end
end
# Get the root directory for this +Engine+
#
# @returns [String] The root directory
#
def root
File.expand_path(options[:root] || Dir.pwd)
end
# Get the port for a given process and offset
#
# @param [Foreman::Process] process A +Process+ associated with this engine
# @param [Fixnum] instance The instance of the process
#
# @returns [Fixnum] port The port to use for this instance of this process
#
def port_for(process, instance, base=nil)
if base
base + (@processes.index(process.process) * 100) + (instance - 1)
else
base_port + (@processes.index(process) * 100) + (instance - 1)
end
end
# Get the base port for this foreman instance
#
# @returns [Fixnum] port The base port
#
def base_port
(options[:port] || env["PORT"] || ENV["PORT"] || 5000).to_i
end
# deprecated
def environment
env
end
private
### Engine API ######################################################
def startup
raise TypeError, "must use a subclass of Foreman::Engine"
end
def output(name, data)
raise TypeError, "must use a subclass of Foreman::Engine"
end
def shutdown
raise TypeError, "must use a subclass of Foreman::Engine"
end
## Helpers ##########################################################
def create_pipe
IO.method(:pipe).arity.zero? ? IO.pipe : IO.pipe("BINARY")
end
def name_for(pid)
process, index = @running[pid]
name_for_index(process, index)
end
def name_for_index(process, index)
[ @names[process], index.to_s ].compact.join(".")
end
def parse_formation(formation)
pairs = formation.to_s.gsub(/\s/, "").split(",")
pairs.inject(Hash.new(0)) do |ax, pair|
process, amount = pair.split("=")
process == "all" ? ax.default = amount.to_i : ax[process] = amount.to_i
ax
end
end
def output_with_mutex(name, message)
@mutex.synchronize do
output name, message
end
end
def system(message)
output_with_mutex "system", message
end
def termination_message_for(status)
if status.exited?
"exited with code #{status.exitstatus}"
elsif status.signaled?
"terminated by SIG#{Signal.list.invert[status.termsig]}"
else
"died a mysterious death"
end
end
def flush_reader(reader)
until reader.eof?
data = reader.gets
output_with_mutex name_for(@readers.key(reader)), data
end
end
## Engine ###########################################################
def spawn_processes
@processes.each do |process|
1.upto(formation[@names[process]]) do |n|
reader, writer = create_pipe
begin
pid = process.run(:output => writer, :env => {
"PORT" => port_for(process, n).to_s,
"PS" => name_for_index(process, n)
})
writer.puts "started with pid #{pid}"
rescue Errno::ENOENT
writer.puts "unknown command: #{process.command}"
end
@running[pid] = [process, n]
@readers[pid] = reader
end
end
end
def read_self_pipe
@selfpipe[:reader].read_nonblock(11)
rescue Errno::EAGAIN, Errno::EINTR, Errno::EBADF, Errno::EWOULDBLOCK
# ignore
end
def handle_signals
while sig = Thread.main[:signal_queue].shift
self.handle_signal(sig)
end
end
def handle_io(readers)
readers.each do |reader|
next if reader == @selfpipe[:reader]
if reader.eof?
@readers.delete_if { |key, value| value == reader }
else
data = reader.gets
output_with_mutex name_for(@readers.invert[reader]), data
end
end
end
def watch_for_output
Thread.new do
begin
loop do
io = IO.select([@selfpipe[:reader]] + @readers.values, nil, nil, 30)
read_self_pipe
handle_signals
handle_io(io ? io.first : [])
end
rescue Exception => ex
puts ex.message
puts ex.backtrace
end
end
end
def wait_for_shutdown_or_child_termination
loop do
# Stop if it is time to shut down (asked via a signal)
break if @shutdown
# Stop if any of the children died
break if check_for_termination
# Sleep for a moment and do not blow up if any signals are coming our way
begin
sleep(1)
rescue Exception
# noop
end
end
# Ok, we have exited from the main loop, time to shut down gracefully
terminate_gracefully
end
def check_for_termination
# Check if any of the children have died off
pid, status = begin
Process.wait2(-1, Process::WNOHANG)
rescue Errno::ECHILD
return nil
end
# record the exit status
@exitstatus ||= status.exitstatus if status
# If no childred have died, nothing to do here
return nil unless pid
# Log the information about the process that exited
output_with_mutex name_for(pid), termination_message_for(status)
# Delete it from the list of running processes and return its pid
@running.delete(pid)
return pid
end
def terminate_gracefully
restore_default_signal_handlers
# Tell all children to stop gracefully
if Foreman.windows?
system "sending SIGKILL to all processes"
kill_children "SIGKILL"
else
system "sending SIGTERM to all processes"
kill_children "SIGTERM"
end
# Wait for all children to stop or until the time comes to kill them all
start_time = Time.now
while Time.now - start_time <= options[:timeout]
return if @running.empty?
check_for_termination
# Sleep for a moment and do not blow up if more signals are coming our way
begin
sleep(0.1)
rescue Exception
# noop
end
end
# Ok, we have no other option than to kill all of our children
system "sending SIGKILL to all processes"
kill_children "SIGKILL"
end
end
foreman-0.85.0/lib/foreman/env.rb 0000644 0000041 0000041 00000001240 13312112240 016557 0 ustar www-data www-data require "foreman"
class Foreman::Env
attr_reader :entries
def initialize(filename)
@entries = File.read(filename).gsub("\r\n","\n").split("\n").inject({}) do |ax, line|
if line =~ /\A([A-Za-z_0-9]+)=(.*)\z/
key = $1
case val = $2
# Remove single quotes
when /\A'(.*)'\z/ then ax[key] = $1
# Remove double quotes and unescape string preserving newline characters
when /\A"(.*)"\z/ then ax[key] = $1.gsub('\n', "\n").gsub(/\\(.)/, '\1')
else ax[key] = val
end
end
ax
end
end
def entries
@entries.each do |key, value|
yield key, value
end
end
end
foreman-0.85.0/lib/foreman/cli.rb 0000644 0000041 0000041 00000012542 13312112240 016545 0 ustar www-data www-data require "foreman"
require "foreman/helpers"
require "foreman/engine"
require "foreman/engine/cli"
require "foreman/export"
require "foreman/version"
require "shellwords"
require "yaml"
require "thor"
class Foreman::CLI < Thor
include Foreman::Helpers
map ["-v", "--version"] => :version
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
class_option :root, :type => :string, :aliases => "-d", :desc => "Default: Procfile directory"
desc "start [PROCESS]", "Start the application (or a specific PROCESS)"
method_option :color, :type => :boolean, :aliases => "-c", :desc => "Force color to be enabled"
method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
method_option :formation, :type => :string, :aliases => "-m", :banner => '"alpha=5,bar=3"', :desc => 'Specify what processes will run and how many. Default: "all=1"'
method_option :port, :type => :numeric, :aliases => "-p"
method_option :timeout, :type => :numeric, :aliases => "-t", :desc => "Specify the amount of time (in seconds) processes have to shutdown gracefully before receiving a SIGKILL, defaults to 5."
method_option :timestamp, :type => :boolean, :default => true, :desc => "Include timestamp in output"
class << self
# Hackery. Take the run method away from Thor so that we can redefine it.
def is_thor_reserved_word?(word, type)
return false if word == "run"
super
end
end
def start(process=nil)
check_procfile!
load_environment!
engine.load_procfile(procfile)
engine.options[:formation] = "#{process}=1" if process
engine.start
end
desc "export FORMAT LOCATION", "Export the application to another process management format"
method_option :app, :type => :string, :aliases => "-a"
method_option :log, :type => :string, :aliases => "-l"
method_option :run, :type => :string, :aliases => "-r", :desc => "Specify the pid file directory, defaults to /var/run/"
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 :user, :type => :string, :aliases => "-u"
method_option :template, :type => :string, :aliases => "-t"
method_option :formation, :type => :string, :aliases => "-m", :banner => '"alpha=5,bar=3"', :desc => 'Specify what processes will run and how many. Default: "all=1"'
method_option :timeout, :type => :numeric, :aliases => "-t", :desc => "Specify the amount of time (in seconds) processes have to shutdown gracefully before receiving a SIGKILL, defaults to 5."
def export(format, location=nil)
check_procfile!
load_environment!
engine.load_procfile(procfile)
formatter = Foreman::Export.formatter(format)
formatter.new(location, engine, options).export
rescue Foreman::Export::Exception => ex
error ex.message
end
desc "check", "Validate your application's Procfile"
def check
check_procfile!
engine.load_procfile(procfile)
error "no processes defined" unless engine.processes.length > 0
puts "valid procfile detected (#{engine.process_names.join(', ')})"
end
desc "run COMMAND [ARGS...]", "Run a command using your application's environment"
method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
stop_on_unknown_option! :run
def run(*args)
load_environment!
if File.file?(procfile)
engine.load_procfile(procfile)
end
pid = fork do
begin
engine.env.each { |k,v| ENV[k] = v }
if args.size == 1 && process = engine.process(args.first)
process.exec(:env => engine.env)
else
exec args.shelljoin
end
rescue Errno::EACCES
error "not executable: #{args.first}"
rescue Errno::ENOENT
error "command not found: #{args.first}"
end
end
trap("INT") do
Process.kill(:INT, pid)
end
Process.wait(pid)
exit $?.exitstatus || 0
rescue Interrupt
end
desc "version", "Display Foreman gem version"
def version
puts Foreman::VERSION
end
no_tasks do
def engine
@engine ||= begin
engine_class = Foreman::Engine::CLI
engine = engine_class.new(options)
engine
end
end
end
private ######################################################################
def error(message)
puts "ERROR: #{message}"
exit 1
end
def check_procfile!
error("#{procfile} does not exist.") unless File.file?(procfile)
end
def load_environment!
if options[:env]
options[:env].split(",").each do |file|
engine.load_env file
end
else
default_env = File.join(engine.root, ".env")
engine.load_env default_env if File.file?(default_env)
end
end
def procfile
case
when options[:procfile] then options[:procfile]
when options[:root] then File.expand_path(File.join(options[:root], "Procfile"))
else "Procfile"
end
end
def options
original_options = super
return original_options unless File.file?(".foreman")
defaults = ::YAML::load_file(".foreman") || {}
Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options))
end
end
foreman-0.85.0/lib/foreman/process.rb 0000644 0000041 0000041 00000003656 13312112240 017462 0 ustar www-data www-data require "foreman"
require "shellwords"
class Foreman::Process
attr_reader :command
attr_reader :env
# Create a Process
#
# @param [String] command The command to run
# @param [Hash] options
#
# @option options [String] :cwd (./) Change to this working directory before executing the process
# @option options [Hash] :env ({}) Environment variables to set for this process
#
def initialize(command, options={})
@command = command
@options = options.dup
@options[:env] ||= {}
end
# Get environment-expanded command for a +Process+
#
# @param [Hash] custom_env ({}) Environment variables to merge with defaults
#
# @return [String] The expanded command
#
def expanded_command(custom_env={})
env = @options[:env].merge(custom_env)
expanded_command = command.dup
env.each do |key, val|
expanded_command.gsub!("$#{key}", val)
end
expanded_command
end
# Run a +Process+
#
# @param [Hash] options
#
# @option options :env ({}) Environment variables to set for this execution
# @option options :output ($stdout) The output stream
#
# @returns [Fixnum] pid The +pid+ of the process
#
def run(options={})
env = @options[:env].merge(options[:env] || {})
output = options[:output] || $stdout
runner = "#{Foreman.runner}".shellescape
Dir.chdir(cwd) do
Process.spawn env, expanded_command(env), :out => output, :err => output
end
end
# Exec a +Process+
#
# @param [Hash] options
#
# @option options :env ({}) Environment variables to set for this execution
#
# @return Does not return
def exec(options={})
env = @options[:env].merge(options[:env] || {})
env.each { |k, v| ENV[k] = v }
Dir.chdir(cwd)
Kernel.exec expanded_command(env)
end
# Returns the working directory for this +Process+
#
# @returns [String]
#
def cwd
File.expand_path(@options[:cwd] || ".")
end
end
foreman-0.85.0/lib/foreman/engine/ 0000755 0000041 0000041 00000000000 13312112240 016712 5 ustar www-data www-data foreman-0.85.0/lib/foreman/engine/cli.rb 0000644 0000041 0000041 00000004703 13312112240 020012 0 ustar www-data www-data require "foreman/engine"
class Foreman::Engine::CLI < Foreman::Engine
module Color
ANSI = {
:reset => 0,
:black => 30,
:red => 31,
:green => 32,
:yellow => 33,
:blue => 34,
:magenta => 35,
:cyan => 36,
:white => 37,
:bright_black => 30,
:bright_red => 31,
:bright_green => 32,
:bright_yellow => 33,
:bright_blue => 34,
:bright_magenta => 35,
:bright_cyan => 36,
:bright_white => 37,
}
def self.enable(io, force=false)
io.extend(self)
@@color_force = force
end
def color?
return true if @@color_force
return false if Foreman.windows?
return false unless self.respond_to?(:isatty)
self.isatty && ENV["TERM"]
end
def color(name)
return "" unless color?
return "" unless ansi = ANSI[name.to_sym]
"\e[#{ansi}m"
end
end
FOREMAN_COLORS = %w( cyan yellow green magenta red blue bright_cyan bright_yellow
bright_green bright_magenta bright_red bright_blue )
def startup
@colors = map_colors
proctitle "foreman: master" unless Foreman.windows?
Color.enable($stdout, options[:color])
end
def output(name, data)
data.to_s.lines.map(&:chomp).each do |message|
output = ""
output += $stdout.color(@colors[name.split(".").first].to_sym)
output += "#{Time.now.strftime("%H:%M:%S")} " if options[:timestamp]
output += "#{pad_process_name(name)} | "
output += $stdout.color(:reset)
output += message
$stdout.puts output
$stdout.flush
end
rescue Errno::EPIPE
terminate_gracefully
end
def shutdown
end
private
def name_padding
@name_padding ||= begin
index_padding = @names.values.map { |n| formation[n] }.max.to_s.length + 1
name_padding = @names.values.map { |n| n.length + index_padding }.sort.last
[ 6, name_padding ].max
end
end
def pad_process_name(name)
name.ljust(name_padding, " ")
end
def map_colors
colors = Hash.new("white")
@names.values.each_with_index do |name, index|
colors[name] = FOREMAN_COLORS[index % FOREMAN_COLORS.length]
end
colors["system"] = "bright_white"
colors
end
def proctitle(title)
$0 = title
end
def termtitle(title)
printf("\033]0;#{title}\007") unless Foreman.windows?
end
end
foreman-0.85.0/lib/foreman/distribution.rb 0000644 0000041 0000041 00000000304 13312112240 020506 0 ustar www-data www-data module Foreman
module Distribution
def self.files
Dir[File.expand_path("../../../{bin,data,lib}/**/*", __FILE__)].select do |file|
File.file?(file)
end
end
end
end