fiveman 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +11 -0
- data/bin/fiveman +7 -0
- data/bin/fiveman-runner +41 -0
- data/data/example/Procfile +4 -0
- data/data/example/Procfile.without_colon +2 -0
- data/data/example/error +7 -0
- data/data/example/log/neverdie.log +4 -0
- data/data/example/spawnee +14 -0
- data/data/example/spawner +7 -0
- data/data/example/ticker +14 -0
- data/data/example/utf8 +11 -0
- data/data/export/bluepill/master.pill.erb +28 -0
- data/data/export/daemon/master.conf.erb +14 -0
- data/data/export/daemon/process.conf.erb +8 -0
- data/data/export/daemon/process_master.conf.erb +2 -0
- data/data/export/launchd/launchd.plist.erb +33 -0
- data/data/export/runit/log/run.erb +7 -0
- data/data/export/runit/run.erb +4 -0
- data/data/export/supervisord/app.conf.erb +31 -0
- data/data/export/systemd/master.target.erb +5 -0
- data/data/export/systemd/process.service.erb +21 -0
- data/data/export/upstart/master.conf.erb +2 -0
- data/data/export/upstart/process.conf.erb +15 -0
- data/data/export/upstart/process_master.conf.erb +2 -0
- data/lib/fiveman/cli.rb +162 -0
- data/lib/fiveman/distribution.rb +9 -0
- data/lib/fiveman/engine/cli.rb +101 -0
- data/lib/fiveman/engine.rb +494 -0
- data/lib/fiveman/env.rb +29 -0
- data/lib/fiveman/export/base.rb +171 -0
- data/lib/fiveman/export/bluepill.rb +12 -0
- data/lib/fiveman/export/daemon.rb +28 -0
- data/lib/fiveman/export/inittab.rb +42 -0
- data/lib/fiveman/export/launchd.rb +22 -0
- data/lib/fiveman/export/runit.rb +34 -0
- data/lib/fiveman/export/supervisord.rb +16 -0
- data/lib/fiveman/export/systemd.rb +34 -0
- data/lib/fiveman/export/upstart.rb +46 -0
- data/lib/fiveman/export.rb +36 -0
- data/lib/fiveman/helpers.rb +45 -0
- data/lib/fiveman/process.rb +80 -0
- data/lib/fiveman/procfile.rb +94 -0
- data/lib/fiveman/vendor/thor/lib/thor/actions/create_file.rb +103 -0
- data/lib/fiveman/vendor/thor/lib/thor/actions/create_link.rb +59 -0
- data/lib/fiveman/vendor/thor/lib/thor/actions/directory.rb +118 -0
- data/lib/fiveman/vendor/thor/lib/thor/actions/empty_directory.rb +135 -0
- data/lib/fiveman/vendor/thor/lib/thor/actions/file_manipulation.rb +327 -0
- data/lib/fiveman/vendor/thor/lib/thor/actions/inject_into_file.rb +103 -0
- data/lib/fiveman/vendor/thor/lib/thor/actions.rb +318 -0
- data/lib/fiveman/vendor/thor/lib/thor/base.rb +656 -0
- data/lib/fiveman/vendor/thor/lib/thor/command.rb +133 -0
- data/lib/fiveman/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +85 -0
- data/lib/fiveman/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
- data/lib/fiveman/vendor/thor/lib/thor/core_ext/ordered_hash.rb +129 -0
- data/lib/fiveman/vendor/thor/lib/thor/error.rb +32 -0
- data/lib/fiveman/vendor/thor/lib/thor/group.rb +281 -0
- data/lib/fiveman/vendor/thor/lib/thor/invocation.rb +177 -0
- data/lib/fiveman/vendor/thor/lib/thor/line_editor/basic.rb +35 -0
- data/lib/fiveman/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
- data/lib/fiveman/vendor/thor/lib/thor/line_editor.rb +17 -0
- data/lib/fiveman/vendor/thor/lib/thor/parser/argument.rb +70 -0
- data/lib/fiveman/vendor/thor/lib/thor/parser/arguments.rb +175 -0
- data/lib/fiveman/vendor/thor/lib/thor/parser/option.rb +146 -0
- data/lib/fiveman/vendor/thor/lib/thor/parser/options.rb +220 -0
- data/lib/fiveman/vendor/thor/lib/thor/parser.rb +4 -0
- data/lib/fiveman/vendor/thor/lib/thor/rake_compat.rb +71 -0
- data/lib/fiveman/vendor/thor/lib/thor/runner.rb +322 -0
- data/lib/fiveman/vendor/thor/lib/thor/shell/basic.rb +436 -0
- data/lib/fiveman/vendor/thor/lib/thor/shell/color.rb +149 -0
- data/lib/fiveman/vendor/thor/lib/thor/shell/html.rb +126 -0
- data/lib/fiveman/vendor/thor/lib/thor/shell.rb +81 -0
- data/lib/fiveman/vendor/thor/lib/thor/util.rb +268 -0
- data/lib/fiveman/vendor/thor/lib/thor/version.rb +3 -0
- data/lib/fiveman/vendor/thor/lib/thor.rb +492 -0
- data/lib/fiveman/version.rb +5 -0
- data/lib/fiveman.rb +17 -0
- data/man/fiveman.1 +284 -0
- data/spec/fiveman/cli_spec.rb +111 -0
- data/spec/fiveman/engine_spec.rb +114 -0
- data/spec/fiveman/export/base_spec.rb +19 -0
- data/spec/fiveman/export/bluepill_spec.rb +37 -0
- data/spec/fiveman/export/daemon_spec.rb +97 -0
- data/spec/fiveman/export/inittab_spec.rb +40 -0
- data/spec/fiveman/export/launchd_spec.rb +31 -0
- data/spec/fiveman/export/runit_spec.rb +36 -0
- data/spec/fiveman/export/supervisord_spec.rb +38 -0
- data/spec/fiveman/export/systemd_spec.rb +155 -0
- data/spec/fiveman/export/upstart_spec.rb +118 -0
- data/spec/fiveman/export_spec.rb +24 -0
- data/spec/fiveman/helpers_spec.rb +26 -0
- data/spec/fiveman/process_spec.rb +71 -0
- data/spec/fiveman/procfile_spec.rb +57 -0
- data/spec/fiveman_spec.rb +16 -0
- data/spec/helper_spec.rb +19 -0
- data/spec/resources/Procfile +5 -0
- data/spec/resources/Procfile.bad +2 -0
- data/spec/resources/bin/echo +2 -0
- data/spec/resources/bin/env +2 -0
- data/spec/resources/bin/test +2 -0
- data/spec/resources/bin/utf8 +2 -0
- data/spec/resources/export/bluepill/app-concurrency.pill +49 -0
- data/spec/resources/export/bluepill/app.pill +81 -0
- data/spec/resources/export/daemon/app-alpha-1.conf +7 -0
- data/spec/resources/export/daemon/app-alpha-2.conf +7 -0
- data/spec/resources/export/daemon/app-alpha.conf +2 -0
- data/spec/resources/export/daemon/app-bravo-1.conf +7 -0
- data/spec/resources/export/daemon/app-bravo.conf +2 -0
- data/spec/resources/export/daemon/app.conf +14 -0
- data/spec/resources/export/inittab/inittab.concurrency +4 -0
- data/spec/resources/export/inittab/inittab.default +6 -0
- data/spec/resources/export/launchd/launchd-a.default +29 -0
- data/spec/resources/export/launchd/launchd-b.default +29 -0
- data/spec/resources/export/launchd/launchd-c.default +30 -0
- data/spec/resources/export/runit/app-alpha-1/log/run +7 -0
- data/spec/resources/export/runit/app-alpha-1/run +4 -0
- data/spec/resources/export/runit/app-alpha-2/log/run +7 -0
- data/spec/resources/export/runit/app-alpha-2/run +4 -0
- data/spec/resources/export/runit/app-bravo-1/log/run +7 -0
- data/spec/resources/export/runit/app-bravo-1/run +4 -0
- data/spec/resources/export/supervisord/app-alpha-1.conf +42 -0
- data/spec/resources/export/supervisord/app-alpha-2.conf +22 -0
- data/spec/resources/export/systemd/app-alpha.1.service +18 -0
- data/spec/resources/export/systemd/app-alpha.2.service +18 -0
- data/spec/resources/export/systemd/app-alpha.target +2 -0
- data/spec/resources/export/systemd/app-bravo.1.service +18 -0
- data/spec/resources/export/systemd/app-bravo.target +2 -0
- data/spec/resources/export/systemd/app.target +5 -0
- data/spec/resources/export/upstart/app-alpha-1.conf +11 -0
- data/spec/resources/export/upstart/app-alpha-2.conf +11 -0
- data/spec/resources/export/upstart/app-alpha.conf +2 -0
- data/spec/resources/export/upstart/app-bravo-1.conf +11 -0
- data/spec/resources/export/upstart/app-bravo.conf +2 -0
- data/spec/resources/export/upstart/app.conf +2 -0
- data/spec/spec_helper.rb +177 -0
- metadata +177 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5da022efab06e93613061a457c76c4382c679274f39768725a64f2951c22a61e
|
|
4
|
+
data.tar.gz: 92500760912ab6f866aba84b5111d71b64250632726a00074f363fc91f964eee
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 1e4d0704ccb1f5d5b33404adc3fb27fe07bb272ecffbe946f1d5ea15701d68da3142a74d07a8e9fc8513dd06f2ee9d7939bac3eb25f7765e1e41a0c84e5f5649
|
|
7
|
+
data.tar.gz: 9c7a6ed669e551237e67a56c5f0b957ed66c29b21f4d753be63b699e2a7cfb42b659ebd19183a96fa5bf9ac6f1d63c841f3e1fa378056976e2838912cf2eefe9
|
data/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Fiveman
|
|
2
|
+
|
|
3
|
+
> This project is a fork of [foreman](https://github.com/ddollar/foreman) because I don't like how it looks.
|
|
4
|
+
|
|
5
|
+
Manage Procfile-based applications
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
$ gem install fiveman
|
|
10
|
+
|
|
11
|
+
Ruby users should take care *not* to install fiveman in their project's `Gemfile`. See this [wiki article](https://github.com/ddollar/fiveman/wiki/Don't-Bundle-Fiveman) for more details.
|
data/bin/fiveman
ADDED
data/bin/fiveman-runner
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
#
|
|
3
|
+
#/ Usage: fiveman-runner [-d <dir>] [-p] <command> [<args>...]
|
|
4
|
+
#/
|
|
5
|
+
#/ Run a command with exec, optionally changing directory first
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
error() {
|
|
10
|
+
echo $@ >&2
|
|
11
|
+
exit 1
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
usage() {
|
|
15
|
+
cat $0 | grep '^#/' | cut -c4-
|
|
16
|
+
exit
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
read_profile=""
|
|
20
|
+
|
|
21
|
+
while getopts ":hd:p" OPT; do
|
|
22
|
+
case $OPT in
|
|
23
|
+
d) cd "$OPTARG" ;;
|
|
24
|
+
p) read_profile="1" ;;
|
|
25
|
+
h) usage ;;
|
|
26
|
+
\?) error "invalid option: -$OPTARG" ;;
|
|
27
|
+
:) error "option -$OPTARG requires an argument" ;;
|
|
28
|
+
esac
|
|
29
|
+
done
|
|
30
|
+
|
|
31
|
+
shift $((OPTIND-1))
|
|
32
|
+
|
|
33
|
+
[ -z "$1" ] && usage
|
|
34
|
+
|
|
35
|
+
if [ "$read_profile" = "1" ]; then
|
|
36
|
+
if [ -f .profile ]; then
|
|
37
|
+
. ./.profile
|
|
38
|
+
fi
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
exec "$@"
|
data/data/example/error
ADDED
data/data/example/ticker
ADDED
data/data/example/utf8
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Bluepill.application("<%= app %>", :foreground => false, :log_file => "/var/log/bluepill.log") do |app|
|
|
2
|
+
|
|
3
|
+
app.uid = "<%= user %>"
|
|
4
|
+
app.gid = "<%= user %>"
|
|
5
|
+
|
|
6
|
+
<% engine.each_process do |name, process| %>
|
|
7
|
+
<% 1.upto(engine.formation[name]) do |num| %>
|
|
8
|
+
<% port = engine.port_for(process, num) %>
|
|
9
|
+
app.process("<%= name %>-<%= num %>") do |process|
|
|
10
|
+
process.start_command = %Q{<%= process.command %>}
|
|
11
|
+
|
|
12
|
+
process.working_dir = "<%= engine.root %>"
|
|
13
|
+
process.daemonize = true
|
|
14
|
+
process.environment = <%= engine.env.merge("PORT" => port.to_s).inspect %>
|
|
15
|
+
process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
|
|
16
|
+
process.stop_grace_time = 45.seconds
|
|
17
|
+
|
|
18
|
+
process.stdout = process.stderr = "<%= log %>/<%= app %>-<%= name %>-<%= num %>.log"
|
|
19
|
+
|
|
20
|
+
process.monitor_children do |children|
|
|
21
|
+
children.stop_command "kill {{PID}}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
process.group = "<%= app %>-<%= name %>"
|
|
25
|
+
end
|
|
26
|
+
<% end %>
|
|
27
|
+
<% end %>
|
|
28
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
start on starting <%= app %>-<%= name.gsub('_', '-') %>
|
|
2
|
+
stop on stopping <%= app %>-<%= name.gsub('_', '-') %>
|
|
3
|
+
respawn
|
|
4
|
+
|
|
5
|
+
env PORT=<%= port %><% engine.env.each_pair do |var, env| %>
|
|
6
|
+
env <%= var %>=<%= env %><% end %>
|
|
7
|
+
|
|
8
|
+
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
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string><%= "#{app}-#{name}-#{num}" %></string>
|
|
7
|
+
<key>EnvironmentVariables</key>
|
|
8
|
+
<dict>
|
|
9
|
+
<%- engine.env.merge("PORT" => port).each_pair do |var,env| -%>
|
|
10
|
+
<key><%= var %></key>
|
|
11
|
+
<string><%= env %></string>
|
|
12
|
+
<%- end -%>
|
|
13
|
+
</dict>
|
|
14
|
+
<key>ProgramArguments</key>
|
|
15
|
+
<array>
|
|
16
|
+
<%- command_args.each do |command| -%>
|
|
17
|
+
<string><%= command %></string>
|
|
18
|
+
<%- end -%>
|
|
19
|
+
</array>
|
|
20
|
+
<key>KeepAlive</key>
|
|
21
|
+
<true/>
|
|
22
|
+
<key>RunAtLoad</key>
|
|
23
|
+
<true/>
|
|
24
|
+
<key>StandardOutPath</key>
|
|
25
|
+
<string><%= log %>/<%= app %>-<%= name %>-<%=num%>.log</string>
|
|
26
|
+
<key>StandardErrorPath</key>
|
|
27
|
+
<string><%= log %>/<%= app %>-<%= name %>-<%=num%>.log</string>
|
|
28
|
+
<key>UserName</key>
|
|
29
|
+
<string><%= user %></string>
|
|
30
|
+
<key>WorkingDirectory</key>
|
|
31
|
+
<string><%= engine.root %></string>
|
|
32
|
+
</dict>
|
|
33
|
+
</plist>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<%
|
|
2
|
+
app_names = []
|
|
3
|
+
engine.each_process do |name, process|
|
|
4
|
+
1.upto(engine.formation[name]) do |num|
|
|
5
|
+
port = engine.port_for(process, num)
|
|
6
|
+
full_name = "#{app}-#{name}-#{num}"
|
|
7
|
+
environment = engine.env.merge("PORT" => port.to_s).map do |key, value|
|
|
8
|
+
value = shell_quote(value)
|
|
9
|
+
value = value.gsub('\=', '=')
|
|
10
|
+
value = value.gsub('\&', '&')
|
|
11
|
+
value = value.gsub('\?', '?')
|
|
12
|
+
"#{key}=\"#{value}\""
|
|
13
|
+
end
|
|
14
|
+
app_names << full_name
|
|
15
|
+
-%>
|
|
16
|
+
[program:<%= full_name %>]
|
|
17
|
+
command=<%= process.command %>
|
|
18
|
+
autostart=true
|
|
19
|
+
autorestart=true
|
|
20
|
+
stdout_logfile=<%= log %>/<%= name %>-<%= num %>.log
|
|
21
|
+
stderr_logfile=<%= log %>/<%= name %>-<%= num %>.error.log
|
|
22
|
+
user=<%= user %>
|
|
23
|
+
directory=<%= engine.root %>
|
|
24
|
+
environment=<%= environment.join(',') %>
|
|
25
|
+
|
|
26
|
+
<%
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
-%>
|
|
30
|
+
[group:<%= app %>]
|
|
31
|
+
programs=<%= app_names.join(',') %>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
PartOf=<%= app %>.target
|
|
3
|
+
StopWhenUnneeded=yes
|
|
4
|
+
|
|
5
|
+
[Service]
|
|
6
|
+
User=<%= user %>
|
|
7
|
+
WorkingDirectory=<%= engine.root %>
|
|
8
|
+
Environment=PORT=<%= port %>
|
|
9
|
+
Environment=PS=<%= process_name %>
|
|
10
|
+
<% engine.env.each_pair do |var,env| -%>
|
|
11
|
+
Environment="<%= var %>=<%= env %>"
|
|
12
|
+
<% end -%>
|
|
13
|
+
ExecStart=/bin/bash -lc 'exec -a "<%= app %>-<%= process_name %>" <%= process.command %>'
|
|
14
|
+
Restart=always
|
|
15
|
+
RestartSec=14s
|
|
16
|
+
StandardInput=null
|
|
17
|
+
StandardOutput=syslog
|
|
18
|
+
StandardError=syslog
|
|
19
|
+
SyslogIdentifier=%n
|
|
20
|
+
KillMode=mixed
|
|
21
|
+
TimeoutStopSec=<%= engine.options[:timeout] %>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
start on starting <%= app %>-<%= name %>
|
|
2
|
+
stop on stopping <%= app %>-<%= name %>
|
|
3
|
+
respawn
|
|
4
|
+
|
|
5
|
+
env PORT=<%= port %>
|
|
6
|
+
<% engine.env.each do |name,value| -%>
|
|
7
|
+
<% next if name.upcase == "PORT" -%>
|
|
8
|
+
env <%= name %>='<%= value.gsub(/'/, "'\"'\"'") %>'
|
|
9
|
+
<% end -%>
|
|
10
|
+
|
|
11
|
+
setuid <%= user %>
|
|
12
|
+
|
|
13
|
+
chdir <%= engine.root %>
|
|
14
|
+
|
|
15
|
+
exec <%= process.command %>
|
data/lib/fiveman/cli.rb
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
require "fiveman"
|
|
2
|
+
require "fiveman/helpers"
|
|
3
|
+
require "fiveman/engine"
|
|
4
|
+
require "fiveman/engine/cli"
|
|
5
|
+
require "fiveman/export"
|
|
6
|
+
require "fiveman/version"
|
|
7
|
+
require "shellwords"
|
|
8
|
+
require "yaml"
|
|
9
|
+
require "fiveman/vendor/thor/lib/thor"
|
|
10
|
+
|
|
11
|
+
class Fiveman::CLI < Fiveman::Thor
|
|
12
|
+
|
|
13
|
+
include Fiveman::Helpers
|
|
14
|
+
|
|
15
|
+
map ["-v", "--version"] => :version
|
|
16
|
+
|
|
17
|
+
class_option :procfile, :type => :string, :aliases => "-f", :desc => "Default: Procfile"
|
|
18
|
+
class_option :root, :type => :string, :aliases => "-d", :desc => "Default: Procfile directory"
|
|
19
|
+
|
|
20
|
+
desc "start [PROCESS]", "Start the application (or a specific PROCESS)"
|
|
21
|
+
|
|
22
|
+
method_option :color, :type => :boolean, :aliases => "-c", :desc => "Force color to be enabled"
|
|
23
|
+
method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
|
|
24
|
+
method_option :formation, :type => :string, :aliases => "-m", :banner => '"alpha=5,bar=3"', :desc => 'Specify what processes will run and how many. Default: "all=1"'
|
|
25
|
+
method_option :port, :type => :numeric, :aliases => "-p"
|
|
26
|
+
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."
|
|
27
|
+
method_option :timestamp, :type => :boolean, :default => true, :desc => "Include timestamp in output"
|
|
28
|
+
|
|
29
|
+
class << self
|
|
30
|
+
# Hackery. Take the run method away from Thor so that we can redefine it.
|
|
31
|
+
def is_thor_reserved_word?(word, type)
|
|
32
|
+
return false if word == "run"
|
|
33
|
+
super
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def start(process=nil)
|
|
38
|
+
check_procfile!
|
|
39
|
+
load_environment!
|
|
40
|
+
engine.load_procfile(procfile)
|
|
41
|
+
engine.options[:formation] = "#{process}=1" if process
|
|
42
|
+
engine.start
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
desc "export FORMAT LOCATION", "Export the application to another process management format"
|
|
46
|
+
|
|
47
|
+
method_option :app, :type => :string, :aliases => "-a"
|
|
48
|
+
method_option :log, :type => :string, :aliases => "-l"
|
|
49
|
+
method_option :run, :type => :string, :aliases => "-r", :desc => "Specify the pid file directory, defaults to /var/run/<application>"
|
|
50
|
+
method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
|
|
51
|
+
method_option :port, :type => :numeric, :aliases => "-p"
|
|
52
|
+
method_option :user, :type => :string, :aliases => "-u"
|
|
53
|
+
method_option :template, :type => :string, :aliases => "-t"
|
|
54
|
+
method_option :formation, :type => :string, :aliases => "-m", :banner => '"alpha=5,bar=3"', :desc => 'Specify what processes will run and how many. Default: "all=1"'
|
|
55
|
+
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."
|
|
56
|
+
|
|
57
|
+
def export(format, location=nil)
|
|
58
|
+
check_procfile!
|
|
59
|
+
load_environment!
|
|
60
|
+
engine.load_procfile(procfile)
|
|
61
|
+
formatter = Fiveman::Export.formatter(format)
|
|
62
|
+
formatter.new(location, engine, options).export
|
|
63
|
+
rescue Fiveman::Export::Exception => ex
|
|
64
|
+
error ex.message
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
desc "check", "Validate your application's Procfile"
|
|
68
|
+
|
|
69
|
+
def check
|
|
70
|
+
check_procfile!
|
|
71
|
+
engine.load_procfile(procfile)
|
|
72
|
+
error "no processes defined" unless engine.processes.length > 0
|
|
73
|
+
puts "valid procfile detected (#{engine.process_names.join(', ')})"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
desc "run COMMAND [ARGS...]", "Run a command using your application's environment"
|
|
77
|
+
|
|
78
|
+
method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
|
|
79
|
+
stop_on_unknown_option! :run
|
|
80
|
+
|
|
81
|
+
def run(*args)
|
|
82
|
+
load_environment!
|
|
83
|
+
|
|
84
|
+
if File.file?(procfile)
|
|
85
|
+
engine.load_procfile(procfile)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
pid = fork do
|
|
89
|
+
begin
|
|
90
|
+
engine.env.each { |k,v| ENV[k] = v }
|
|
91
|
+
if args.size == 1 && process = engine.process(args.first)
|
|
92
|
+
process.exec(:env => engine.env)
|
|
93
|
+
else
|
|
94
|
+
exec args.shelljoin
|
|
95
|
+
end
|
|
96
|
+
rescue Errno::EACCES
|
|
97
|
+
error "not executable: #{args.first}"
|
|
98
|
+
rescue Errno::ENOENT
|
|
99
|
+
error "command not found: #{args.first}"
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
trap("INT") do
|
|
103
|
+
Process.kill(:INT, pid)
|
|
104
|
+
end
|
|
105
|
+
Process.wait(pid)
|
|
106
|
+
exit $?.exitstatus || 0
|
|
107
|
+
rescue Interrupt
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
desc "version", "Display Fiveman gem version"
|
|
111
|
+
|
|
112
|
+
def version
|
|
113
|
+
puts Fiveman::VERSION
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
no_tasks do
|
|
117
|
+
def engine
|
|
118
|
+
@engine ||= begin
|
|
119
|
+
engine_class = Fiveman::Engine::CLI
|
|
120
|
+
engine = engine_class.new(options)
|
|
121
|
+
engine
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
private ######################################################################
|
|
127
|
+
|
|
128
|
+
def error(message)
|
|
129
|
+
puts "ERROR: #{message}"
|
|
130
|
+
exit 1
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def check_procfile!
|
|
134
|
+
error("#{procfile} does not exist.") unless File.file?(procfile)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def load_environment!
|
|
138
|
+
if options[:env]
|
|
139
|
+
options[:env].split(",").each do |file|
|
|
140
|
+
engine.load_env file
|
|
141
|
+
end
|
|
142
|
+
else
|
|
143
|
+
default_env = File.join(engine.root, ".env")
|
|
144
|
+
engine.load_env default_env if File.file?(default_env)
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def procfile
|
|
149
|
+
case
|
|
150
|
+
when options[:procfile] then options[:procfile]
|
|
151
|
+
when options[:root] then File.expand_path(File.join(options[:root], "Procfile"))
|
|
152
|
+
else "Procfile"
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def options
|
|
157
|
+
original_options = super
|
|
158
|
+
return original_options unless File.file?(".fiveman")
|
|
159
|
+
defaults = ::YAML::load_file(".fiveman") || {}
|
|
160
|
+
Fiveman::Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options))
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require "fiveman/engine"
|
|
2
|
+
|
|
3
|
+
class Fiveman::Engine::CLI < Fiveman::Engine
|
|
4
|
+
|
|
5
|
+
module Color
|
|
6
|
+
|
|
7
|
+
ANSI = {
|
|
8
|
+
:reset => 0,
|
|
9
|
+
:black => 30,
|
|
10
|
+
:red => 31,
|
|
11
|
+
:green => 32,
|
|
12
|
+
:yellow => 33,
|
|
13
|
+
:blue => 34,
|
|
14
|
+
:magenta => 35,
|
|
15
|
+
:cyan => 36,
|
|
16
|
+
:white => 37,
|
|
17
|
+
:bright_black => 30,
|
|
18
|
+
:bright_red => 31,
|
|
19
|
+
:bright_green => 32,
|
|
20
|
+
:bright_yellow => 33,
|
|
21
|
+
:bright_blue => 34,
|
|
22
|
+
:bright_magenta => 35,
|
|
23
|
+
:bright_cyan => 36,
|
|
24
|
+
:bright_white => 37,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
def self.enable(io, force=false)
|
|
28
|
+
io.extend(self)
|
|
29
|
+
@@color_force = force
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def color?
|
|
33
|
+
return true if @@color_force
|
|
34
|
+
return false if Fiveman.windows?
|
|
35
|
+
return false unless self.respond_to?(:isatty)
|
|
36
|
+
self.isatty && ENV["TERM"]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def color(name)
|
|
40
|
+
return "" unless color?
|
|
41
|
+
return "" unless ansi = ANSI[name.to_sym]
|
|
42
|
+
"\e[#{ansi}m"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
FIVEMAN_COLORS = %w( cyan yellow green magenta red blue bright_cyan bright_yellow
|
|
48
|
+
bright_green bright_magenta bright_red bright_blue )
|
|
49
|
+
|
|
50
|
+
def startup
|
|
51
|
+
@colors = map_colors
|
|
52
|
+
proctitle "fiveman: master" unless Fiveman.windows?
|
|
53
|
+
Color.enable($stdout, options[:color])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def output(name, data)
|
|
57
|
+
data.to_s.lines.map(&:chomp).each do |message|
|
|
58
|
+
output = $stdout.color(:reset)
|
|
59
|
+
output += message
|
|
60
|
+
$stdout.puts output
|
|
61
|
+
$stdout.flush
|
|
62
|
+
end
|
|
63
|
+
rescue Errno::EPIPE
|
|
64
|
+
terminate_gracefully
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def shutdown
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def name_padding
|
|
73
|
+
@name_padding ||= begin
|
|
74
|
+
index_padding = @names.values.map { |n| formation[n] }.max.to_s.length + 1
|
|
75
|
+
name_padding = @names.values.map { |n| n.length + index_padding }.sort.last
|
|
76
|
+
[ 6, name_padding ].max
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def pad_process_name(name)
|
|
81
|
+
name.ljust(name_padding, " ")
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def map_colors
|
|
85
|
+
colors = Hash.new("white")
|
|
86
|
+
@names.values.each_with_index do |name, index|
|
|
87
|
+
colors[name] = FIVEMAN_COLORS[index % FIVEMAN_COLORS.length]
|
|
88
|
+
end
|
|
89
|
+
colors["system"] = "bright_white"
|
|
90
|
+
colors
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def proctitle(title)
|
|
94
|
+
$0 = title
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def termtitle(title)
|
|
98
|
+
printf("\033]0;#{title}\007") unless Fiveman.windows?
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|