overman 0.0.1 → 0.87.3

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.
Files changed (138) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +52 -0
  3. data/bin/foreman-runner +41 -0
  4. data/bin/overman +7 -0
  5. data/data/example/Procfile +4 -0
  6. data/data/example/Procfile.without_colon +2 -0
  7. data/data/example/error +7 -0
  8. data/data/example/log/neverdie.log +4 -0
  9. data/data/example/spawnee +14 -0
  10. data/data/example/spawner +7 -0
  11. data/data/example/ticker +14 -0
  12. data/data/example/utf8 +11 -0
  13. data/data/export/bluepill/master.pill.erb +28 -0
  14. data/data/export/daemon/master.conf.erb +14 -0
  15. data/data/export/daemon/process.conf.erb +8 -0
  16. data/data/export/daemon/process_master.conf.erb +2 -0
  17. data/data/export/launchd/launchd.plist.erb +33 -0
  18. data/data/export/runit/log/run.erb +7 -0
  19. data/data/export/runit/run.erb +4 -0
  20. data/data/export/supervisord/app.conf.erb +31 -0
  21. data/data/export/systemd/master.target.erb +5 -0
  22. data/data/export/systemd/process.service.erb +21 -0
  23. data/data/export/upstart/master.conf.erb +2 -0
  24. data/data/export/upstart/process.conf.erb +15 -0
  25. data/data/export/upstart/process_master.conf.erb +2 -0
  26. data/lib/foreman/cli.rb +162 -0
  27. data/lib/foreman/distribution.rb +9 -0
  28. data/lib/foreman/engine/cli.rb +105 -0
  29. data/lib/foreman/engine.rb +494 -0
  30. data/lib/foreman/env.rb +29 -0
  31. data/lib/foreman/export/base.rb +171 -0
  32. data/lib/foreman/export/bluepill.rb +12 -0
  33. data/lib/foreman/export/daemon.rb +28 -0
  34. data/lib/foreman/export/inittab.rb +42 -0
  35. data/lib/foreman/export/launchd.rb +22 -0
  36. data/lib/foreman/export/runit.rb +34 -0
  37. data/lib/foreman/export/supervisord.rb +16 -0
  38. data/lib/foreman/export/systemd.rb +34 -0
  39. data/lib/foreman/export/upstart.rb +46 -0
  40. data/lib/foreman/export.rb +36 -0
  41. data/lib/foreman/helpers.rb +45 -0
  42. data/lib/foreman/process.rb +81 -0
  43. data/lib/foreman/procfile.rb +94 -0
  44. data/lib/foreman/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  45. data/lib/foreman/vendor/thor/lib/thor/actions/create_link.rb +59 -0
  46. data/lib/foreman/vendor/thor/lib/thor/actions/directory.rb +118 -0
  47. data/lib/foreman/vendor/thor/lib/thor/actions/empty_directory.rb +135 -0
  48. data/lib/foreman/vendor/thor/lib/thor/actions/file_manipulation.rb +327 -0
  49. data/lib/foreman/vendor/thor/lib/thor/actions/inject_into_file.rb +103 -0
  50. data/lib/foreman/vendor/thor/lib/thor/actions.rb +318 -0
  51. data/lib/foreman/vendor/thor/lib/thor/base.rb +656 -0
  52. data/lib/foreman/vendor/thor/lib/thor/command.rb +133 -0
  53. data/lib/foreman/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +85 -0
  54. data/lib/foreman/vendor/thor/lib/thor/core_ext/io_binary_read.rb +12 -0
  55. data/lib/foreman/vendor/thor/lib/thor/core_ext/ordered_hash.rb +129 -0
  56. data/lib/foreman/vendor/thor/lib/thor/error.rb +32 -0
  57. data/lib/foreman/vendor/thor/lib/thor/group.rb +281 -0
  58. data/lib/foreman/vendor/thor/lib/thor/invocation.rb +177 -0
  59. data/lib/foreman/vendor/thor/lib/thor/line_editor/basic.rb +35 -0
  60. data/lib/foreman/vendor/thor/lib/thor/line_editor/readline.rb +88 -0
  61. data/lib/foreman/vendor/thor/lib/thor/line_editor.rb +17 -0
  62. data/lib/foreman/vendor/thor/lib/thor/parser/argument.rb +70 -0
  63. data/lib/foreman/vendor/thor/lib/thor/parser/arguments.rb +175 -0
  64. data/lib/foreman/vendor/thor/lib/thor/parser/option.rb +146 -0
  65. data/lib/foreman/vendor/thor/lib/thor/parser/options.rb +220 -0
  66. data/lib/foreman/vendor/thor/lib/thor/parser.rb +4 -0
  67. data/lib/foreman/vendor/thor/lib/thor/rake_compat.rb +71 -0
  68. data/lib/foreman/vendor/thor/lib/thor/runner.rb +322 -0
  69. data/lib/foreman/vendor/thor/lib/thor/shell/basic.rb +436 -0
  70. data/lib/foreman/vendor/thor/lib/thor/shell/color.rb +149 -0
  71. data/lib/foreman/vendor/thor/lib/thor/shell/html.rb +126 -0
  72. data/lib/foreman/vendor/thor/lib/thor/shell.rb +81 -0
  73. data/lib/foreman/vendor/thor/lib/thor/util.rb +268 -0
  74. data/lib/foreman/vendor/thor/lib/thor/version.rb +3 -0
  75. data/lib/foreman/vendor/thor/lib/thor.rb +492 -0
  76. data/lib/foreman/version.rb +5 -0
  77. data/lib/foreman.rb +17 -0
  78. data/man/overman.1 +284 -0
  79. data/spec/foreman/cli_spec.rb +111 -0
  80. data/spec/foreman/engine_spec.rb +114 -0
  81. data/spec/foreman/export/base_spec.rb +19 -0
  82. data/spec/foreman/export/bluepill_spec.rb +37 -0
  83. data/spec/foreman/export/daemon_spec.rb +97 -0
  84. data/spec/foreman/export/inittab_spec.rb +40 -0
  85. data/spec/foreman/export/launchd_spec.rb +31 -0
  86. data/spec/foreman/export/runit_spec.rb +36 -0
  87. data/spec/foreman/export/supervisord_spec.rb +38 -0
  88. data/spec/foreman/export/systemd_spec.rb +155 -0
  89. data/spec/foreman/export/upstart_spec.rb +118 -0
  90. data/spec/foreman/export_spec.rb +24 -0
  91. data/spec/foreman/helpers_spec.rb +26 -0
  92. data/spec/foreman/process_spec.rb +71 -0
  93. data/spec/foreman/procfile_spec.rb +57 -0
  94. data/spec/foreman_spec.rb +16 -0
  95. data/spec/helper_spec.rb +19 -0
  96. data/spec/resources/Procfile +5 -0
  97. data/spec/resources/Procfile.bad +2 -0
  98. data/spec/resources/bin/echo +2 -0
  99. data/spec/resources/bin/env +2 -0
  100. data/spec/resources/bin/test +2 -0
  101. data/spec/resources/bin/utf8 +2 -0
  102. data/spec/resources/export/bluepill/app-concurrency.pill +49 -0
  103. data/spec/resources/export/bluepill/app.pill +81 -0
  104. data/spec/resources/export/daemon/app-alpha-1.conf +7 -0
  105. data/spec/resources/export/daemon/app-alpha-2.conf +7 -0
  106. data/spec/resources/export/daemon/app-alpha.conf +2 -0
  107. data/spec/resources/export/daemon/app-bravo-1.conf +7 -0
  108. data/spec/resources/export/daemon/app-bravo.conf +2 -0
  109. data/spec/resources/export/daemon/app.conf +14 -0
  110. data/spec/resources/export/inittab/inittab.concurrency +4 -0
  111. data/spec/resources/export/inittab/inittab.default +6 -0
  112. data/spec/resources/export/launchd/launchd-a.default +29 -0
  113. data/spec/resources/export/launchd/launchd-b.default +29 -0
  114. data/spec/resources/export/launchd/launchd-c.default +30 -0
  115. data/spec/resources/export/runit/app-alpha-1/log/run +7 -0
  116. data/spec/resources/export/runit/app-alpha-1/run +4 -0
  117. data/spec/resources/export/runit/app-alpha-2/log/run +7 -0
  118. data/spec/resources/export/runit/app-alpha-2/run +4 -0
  119. data/spec/resources/export/runit/app-bravo-1/log/run +7 -0
  120. data/spec/resources/export/runit/app-bravo-1/run +4 -0
  121. data/spec/resources/export/supervisord/app-alpha-1.conf +42 -0
  122. data/spec/resources/export/supervisord/app-alpha-2.conf +22 -0
  123. data/spec/resources/export/systemd/app-alpha.1.service +18 -0
  124. data/spec/resources/export/systemd/app-alpha.2.service +18 -0
  125. data/spec/resources/export/systemd/app-alpha.target +2 -0
  126. data/spec/resources/export/systemd/app-bravo.1.service +18 -0
  127. data/spec/resources/export/systemd/app-bravo.target +2 -0
  128. data/spec/resources/export/systemd/app.target +5 -0
  129. data/spec/resources/export/upstart/app-alpha-1.conf +11 -0
  130. data/spec/resources/export/upstart/app-alpha-2.conf +11 -0
  131. data/spec/resources/export/upstart/app-alpha.conf +2 -0
  132. data/spec/resources/export/upstart/app-bravo-1.conf +11 -0
  133. data/spec/resources/export/upstart/app-bravo.conf +2 -0
  134. data/spec/resources/export/upstart/app.conf +2 -0
  135. data/spec/spec_helper.rb +177 -0
  136. metadata +147 -16
  137. data/lib/overman/version.rb +0 -5
  138. data/lib/overman.rb +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d480b8870bea6ea71782fc5161f05d07dd615025653f6dfa84a2697c3efec9d
4
- data.tar.gz: '09b2e9d46aeec0a4094474e8ca09f434345764b603e3c47ab8a83c99758862fc'
3
+ metadata.gz: 16dff0543ec0529199820c87e2bb1aa9df5ddfe0d2287c8993a4f223d72a6c85
4
+ data.tar.gz: f586a1017a45d1d8e517af84157441e1f28e910e35a15f069cfd69de8e8bc31b
5
5
  SHA512:
6
- metadata.gz: b86b65cd4c20dd2469bef0f643bc4842943aa9d3db6d1425d5c985aa07707af6962f0e268d4cd8526acc976b2d85466ecd28bc80e5c6dea42355d219101b228f
7
- data.tar.gz: 067c74e38e42349c41c2ec234761e011630683bbeeb89e59265e9475f2a257e4da984ff58fd551511daaf34f46452ed3b26b640ad769b8ab369d4e086c7e4135
6
+ metadata.gz: 1f88e4b71f8936627deea9c573f83c8071778738b769bc490127d14527adafb80202901b2b47ae09fe62d05d6c8a3933ee458215e03c020022b067fc09f91932
7
+ data.tar.gz: 20c42a00a35ace143e4234c4b80958c6981a010987373c48748a1df522fd2e643ffd811eed231c20b5305829173fc2379e622f4c759f9c3c9a4595b79c6ce2a8
data/README.md CHANGED
@@ -0,0 +1,52 @@
1
+ # Overman (`ddollar/foreman` fork)
2
+
3
+ [![CI](https://github.com/spinels/overman/actions/workflows/ci.yml/badge.svg)](https://github.com/spinels/overman/actions/workflows/ci.yml)
4
+
5
+ Manage Procfile-based applications
6
+
7
+ ## Installation
8
+
9
+ $ gem install overman
10
+
11
+ Ruby users should take care *not* to install overman in their project's `Gemfile`. See this [wiki article](https://github.com/ddollar/foreman/wiki/Don't-Bundle-Foreman) for more details.
12
+
13
+ ## Getting Started
14
+
15
+ * http://blog.daviddollar.org/2011/05/06/introducing-foreman.html
16
+
17
+ ## Supported Ruby versions
18
+
19
+ See [ci.yml](.github/workflows/ci.yml) for a list of Ruby versions against which Foreman is tested.
20
+
21
+ ## Documentation
22
+
23
+ * [man page](http://ddollar.github.io/foreman/)
24
+ * [wiki](https://github.com/ddollar/foreman/wiki)
25
+ * [changelog](https://github.com/ddollar/foreman/blob/master/Changelog.md)
26
+
27
+ ## Ports
28
+
29
+ * [forego](https://github.com/ddollar/forego) - Go
30
+ * [node-foreman](https://github.com/strongloop/node-foreman) - Node.js
31
+ * [gaffer](https://github.com/jingweno/gaffer) - Java/JVM
32
+ * [goreman](https://github.com/mattn/goreman) - Go
33
+ * [honcho](https://github.com/nickstenning/honcho) - python
34
+ * [proclet](https://github.com/kazeburo/Proclet) - Perl
35
+ * [shoreman](https://github.com/chrismytton/shoreman) - shell
36
+ * [crank](https://github.com/arktisklada/crank) - Crystal
37
+ * [houseman](https://github.com/fujimura/houseman) - Haskell
38
+ * [spm](https://github.com/bytegust/spm) - Go
39
+
40
+ ## Authors
41
+
42
+ #### Created and maintained by
43
+ David Dollar
44
+
45
+ #### Patches contributed by
46
+ [Contributor List](https://github.com/ddollar/foreman/contributors)
47
+
48
+ ## License
49
+
50
+ Foreman is licensed under the MIT license.
51
+
52
+ See LICENSE for the full license text.
@@ -0,0 +1,41 @@
1
+ #!/bin/sh
2
+ #
3
+ #/ Usage: foreman-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/bin/overman ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path("../../lib", __FILE__)
4
+
5
+ require "foreman/cli"
6
+
7
+ Foreman::CLI.start
@@ -0,0 +1,4 @@
1
+ ticker: ruby ./ticker $PORT
2
+ error: ruby ./error
3
+ utf8: ruby ./utf8
4
+ spawner: ./spawner
@@ -0,0 +1,2 @@
1
+ ticker ./ticker $PORT
2
+ error ./error
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $stdout.sync = true
4
+
5
+ puts "will error in 10s"
6
+ sleep 5
7
+ raise "Dying"
@@ -0,0 +1,4 @@
1
+ tick
2
+ tick
3
+ ./never_die:6:in `sleep': Interrupt
4
+ from ./never_die:6
@@ -0,0 +1,14 @@
1
+ #!/bin/sh
2
+
3
+ NAME="$1"
4
+
5
+ sigterm() {
6
+ echo "$NAME: got sigterm"
7
+ }
8
+
9
+ #trap sigterm SIGTERM
10
+
11
+ while true; do
12
+ echo "$NAME: ping $$"
13
+ sleep 1
14
+ done
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+
3
+ ./spawnee A &
4
+ ./spawnee B &
5
+ ./spawnee C &
6
+
7
+ wait
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $stdout.sync = true
4
+
5
+ %w( SIGINT SIGTERM ).each do |signal|
6
+ trap(signal) do
7
+ puts "received #{signal} but i'm ignoring it!"
8
+ end
9
+ end
10
+
11
+ while true
12
+ puts "tick: #{ARGV.inspect} -- FOO:#{ENV["FOO"]}"
13
+ sleep 1
14
+ end
data/data/example/utf8 ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: BINARY
3
+
4
+ $stdout.sync = true
5
+
6
+ while true
7
+ puts "\u65e5\u672c\u8a9e\u6587\u5b57\u5217"
8
+ puts "\u0915\u0932\u094d\u0907\u0928\u0643\u0637\u0628\u041a\u0430\u043b\u0438\u043d\u0430"
9
+ puts "\xff\x03"
10
+ sleep 1
11
+ end
@@ -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,14 @@
1
+ pre-start script
2
+
3
+ bash << "EOF"
4
+ mkdir -p <%= log %>
5
+ chown -R <%= user %> <%= log %>
6
+ mkdir -p <%= run %>
7
+ chown -R <%= user %> <%= run %>
8
+ EOF
9
+
10
+ end script
11
+
12
+ start on runlevel [2345]
13
+
14
+ stop on runlevel [016]
@@ -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,2 @@
1
+ start on starting <%= app %>
2
+ stop on stopping <%= app %>
@@ -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,7 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ LOG=<%= log %>/<%= name %>-<%= num %>
5
+
6
+ test -d "$LOG" || mkdir -p -m 2750 "$LOG" && chown <%= user %> "$LOG"
7
+ exec chpst -u <%= user %> svlogd "$LOG"
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ cd <%= engine.root %>
3
+ exec 2>&1
4
+ exec chpst -u <%= user %> -e <%= File.join(location, "#{process_directory}/env") %> <%= process.command %>
@@ -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,5 @@
1
+ [Unit]
2
+ Wants=<%= service_names.join(' ') %>
3
+
4
+ [Install]
5
+ WantedBy=multi-user.target
@@ -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,2 @@
1
+ start on runlevel [2345]
2
+ stop on runlevel [!2345]
@@ -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 %>
@@ -0,0 +1,2 @@
1
+ start on starting <%= app %>
2
+ stop on stopping <%= app %>
@@ -0,0 +1,162 @@
1
+ require "foreman"
2
+ require "foreman/helpers"
3
+ require "foreman/engine"
4
+ require "foreman/engine/cli"
5
+ require "foreman/export"
6
+ require "foreman/version"
7
+ require "shellwords"
8
+ require "yaml"
9
+ require "foreman/vendor/thor/lib/thor"
10
+
11
+ class Foreman::CLI < Foreman::Thor
12
+
13
+ include Foreman::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 = Foreman::Export.formatter(format)
62
+ formatter.new(location, engine, options).export
63
+ rescue Foreman::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 Foreman gem version"
111
+
112
+ def version
113
+ puts Foreman::VERSION
114
+ end
115
+
116
+ no_tasks do
117
+ def engine
118
+ @engine ||= begin
119
+ engine_class = Foreman::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?(".foreman")
159
+ defaults = ::YAML::load_file(".foreman") || {}
160
+ Foreman::Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options))
161
+ end
162
+ end
@@ -0,0 +1,9 @@
1
+ module Foreman
2
+ module Distribution
3
+ def self.files
4
+ Dir[File.expand_path("../../../{bin,data,lib}/**/*", __FILE__)].select do |file|
5
+ File.file?(file)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,105 @@
1
+ require "foreman/engine"
2
+
3
+ class Foreman::Engine::CLI < Foreman::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 Foreman.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
+ FOREMAN_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 "foreman: master" unless Foreman.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 = ""
59
+ output += $stdout.color(@colors[name.split(".").first].to_sym)
60
+ output += "#{Time.now.strftime("%H:%M:%S")} " if options[:timestamp]
61
+ output += "#{pad_process_name(name)} | "
62
+ output += $stdout.color(:reset)
63
+ output += message
64
+ $stdout.puts output
65
+ $stdout.flush
66
+ end
67
+ rescue Errno::EPIPE
68
+ terminate_gracefully
69
+ end
70
+
71
+ def shutdown
72
+ end
73
+
74
+ private
75
+
76
+ def name_padding
77
+ @name_padding ||= begin
78
+ index_padding = @names.values.map { |n| formation[n] }.max.to_s.length + 1
79
+ name_padding = @names.values.map { |n| n.length + index_padding }.sort.last
80
+ [ 6, name_padding ].max
81
+ end
82
+ end
83
+
84
+ def pad_process_name(name)
85
+ name.ljust(name_padding, " ")
86
+ end
87
+
88
+ def map_colors
89
+ colors = Hash.new("white")
90
+ @names.values.each_with_index do |name, index|
91
+ colors[name] = FOREMAN_COLORS[index % FOREMAN_COLORS.length]
92
+ end
93
+ colors["system"] = "bright_white"
94
+ colors
95
+ end
96
+
97
+ def proctitle(title)
98
+ $0 = title
99
+ end
100
+
101
+ def termtitle(title)
102
+ printf("\033]0;#{title}\007") unless Foreman.windows?
103
+ end
104
+
105
+ end