overman 0.0.1 → 0.87.3

Sign up to get free protection for your applications and to get access to all the features.
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