foreman-systemd 0.78.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.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +64 -0
  3. data/bin/foreman +7 -0
  4. data/bin/foreman-runner +41 -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 +28 -0
  21. data/data/export/systemd/master.target.erb +6 -0
  22. data/data/export/systemd/process.service.erb +16 -0
  23. data/data/export/systemd/process_master.target.erb +4 -0
  24. data/data/export/upstart/master.conf.erb +2 -0
  25. data/data/export/upstart/process.conf.erb +14 -0
  26. data/data/export/upstart/process_master.conf.erb +2 -0
  27. data/lib/foreman.rb +17 -0
  28. data/lib/foreman/cli.rb +161 -0
  29. data/lib/foreman/distribution.rb +9 -0
  30. data/lib/foreman/engine.rb +441 -0
  31. data/lib/foreman/engine/cli.rb +104 -0
  32. data/lib/foreman/env.rb +29 -0
  33. data/lib/foreman/export.rb +36 -0
  34. data/lib/foreman/export/base.rb +156 -0
  35. data/lib/foreman/export/bluepill.rb +12 -0
  36. data/lib/foreman/export/daemon.rb +28 -0
  37. data/lib/foreman/export/inittab.rb +42 -0
  38. data/lib/foreman/export/launchd.rb +22 -0
  39. data/lib/foreman/export/runit.rb +34 -0
  40. data/lib/foreman/export/supervisord.rb +16 -0
  41. data/lib/foreman/export/systemd.rb +32 -0
  42. data/lib/foreman/export/upstart.rb +43 -0
  43. data/lib/foreman/helpers.rb +45 -0
  44. data/lib/foreman/process.rb +80 -0
  45. data/lib/foreman/procfile.rb +92 -0
  46. data/lib/foreman/version.rb +5 -0
  47. data/man/foreman.1 +278 -0
  48. data/spec/foreman/cli_spec.rb +107 -0
  49. data/spec/foreman/engine_spec.rb +112 -0
  50. data/spec/foreman/export/base_spec.rb +19 -0
  51. data/spec/foreman/export/bluepill_spec.rb +37 -0
  52. data/spec/foreman/export/daemon_spec.rb +97 -0
  53. data/spec/foreman/export/inittab_spec.rb +40 -0
  54. data/spec/foreman/export/launchd_spec.rb +31 -0
  55. data/spec/foreman/export/runit_spec.rb +36 -0
  56. data/spec/foreman/export/supervisord_spec.rb +36 -0
  57. data/spec/foreman/export/systemd_spec.rb +91 -0
  58. data/spec/foreman/export/upstart_spec.rb +118 -0
  59. data/spec/foreman/export_spec.rb +24 -0
  60. data/spec/foreman/helpers_spec.rb +26 -0
  61. data/spec/foreman/process_spec.rb +71 -0
  62. data/spec/foreman/procfile_spec.rb +43 -0
  63. data/spec/foreman_spec.rb +16 -0
  64. data/spec/helper_spec.rb +19 -0
  65. data/spec/resources/Procfile +5 -0
  66. data/spec/resources/bin/echo +2 -0
  67. data/spec/resources/bin/env +2 -0
  68. data/spec/resources/bin/test +2 -0
  69. data/spec/resources/bin/utf8 +2 -0
  70. data/spec/resources/export/bluepill/app-concurrency.pill +49 -0
  71. data/spec/resources/export/bluepill/app.pill +81 -0
  72. data/spec/resources/export/daemon/app-alpha-1.conf +7 -0
  73. data/spec/resources/export/daemon/app-alpha-2.conf +7 -0
  74. data/spec/resources/export/daemon/app-alpha.conf +2 -0
  75. data/spec/resources/export/daemon/app-bravo-1.conf +7 -0
  76. data/spec/resources/export/daemon/app-bravo.conf +2 -0
  77. data/spec/resources/export/daemon/app.conf +14 -0
  78. data/spec/resources/export/inittab/inittab.concurrency +4 -0
  79. data/spec/resources/export/inittab/inittab.default +6 -0
  80. data/spec/resources/export/launchd/launchd-a.default +29 -0
  81. data/spec/resources/export/launchd/launchd-b.default +29 -0
  82. data/spec/resources/export/launchd/launchd-c.default +30 -0
  83. data/spec/resources/export/runit/app-alpha-1/log/run +7 -0
  84. data/spec/resources/export/runit/app-alpha-1/run +4 -0
  85. data/spec/resources/export/runit/app-alpha-2/log/run +7 -0
  86. data/spec/resources/export/runit/app-alpha-2/run +4 -0
  87. data/spec/resources/export/runit/app-bravo-1/log/run +7 -0
  88. data/spec/resources/export/runit/app-bravo-1/run +4 -0
  89. data/spec/resources/export/supervisord/app-alpha-1.conf +46 -0
  90. data/spec/resources/export/supervisord/app-alpha-2.conf +24 -0
  91. data/spec/resources/export/systemd/concurrency/app-alpha-1.service +14 -0
  92. data/spec/resources/export/systemd/concurrency/app-alpha-2.service +14 -0
  93. data/spec/resources/export/systemd/concurrency/app-alpha.target +3 -0
  94. data/spec/resources/export/systemd/concurrency/app.target +6 -0
  95. data/spec/resources/export/systemd/standard/app-alpha-1.service +14 -0
  96. data/spec/resources/export/systemd/standard/app-alpha.target +3 -0
  97. data/spec/resources/export/systemd/standard/app-bravo-1.service +14 -0
  98. data/spec/resources/export/systemd/standard/app-bravo.target +3 -0
  99. data/spec/resources/export/systemd/standard/app.target +6 -0
  100. data/spec/resources/export/upstart/app-alpha-1.conf +11 -0
  101. data/spec/resources/export/upstart/app-alpha-2.conf +11 -0
  102. data/spec/resources/export/upstart/app-alpha.conf +2 -0
  103. data/spec/resources/export/upstart/app-bravo-1.conf +11 -0
  104. data/spec/resources/export/upstart/app-bravo.conf +2 -0
  105. data/spec/resources/export/upstart/app.conf +2 -0
  106. data/spec/spec_helper.rb +166 -0
  107. metadata +164 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9865c6f9b79dad208c1f50914ceb5a3e83a8bb76
4
+ data.tar.gz: 8fe409579cf4d8d9c74b56c0829169e11cd8621f
5
+ SHA512:
6
+ metadata.gz: dc06e84934cea95497f9c2a63889e8bb5f6d5dd7ef63b61f818806681aca00c71a1afcf6a2bc903e02758562fc4e31a423c708b9f783da14a04946b0dda5c9ec
7
+ data.tar.gz: d302f2133a60208fa63d6e76b3d7a3ff7a2326c78a9a5d1611752f1ddcc4c90f7cf786d790da9ade5095ef207d99a9e95c4588718d6b2f67ca8dd913c993f59a
@@ -0,0 +1,64 @@
1
+ # Foreman
2
+
3
+ [![Build Status](https://travis-ci.org/ddollar/foreman.svg?branch=master)](https://travis-ci.org/ddollar/foreman)
4
+ [![Code Climate](https://codeclimate.com/github/ddollar/foreman.png)](https://codeclimate.com/github/ddollar/foreman)
5
+ [![Inline docs](http://inch-ci.org/github/ddollar/foreman.svg?branch=master)](http://inch-ci.org/github/ddollar/foreman)
6
+
7
+ Manage Procfile-based applications
8
+
9
+ <table>
10
+ <tr>
11
+ <th>If you have...</th>
12
+ <th>Install with...</th>
13
+ </tr>
14
+ <tr>
15
+ <td>Ruby (MRI, JRuby, Windows)</td>
16
+ <td><pre>$ gem install foreman</pre></td>
17
+ </tr>
18
+ <tr>
19
+ <td>Mac OS X</td>
20
+ <td><a href="http://assets.foreman.io/foreman/foreman.pkg">foreman.pkg</a></td>
21
+ </tr>
22
+ </table>
23
+
24
+ ## Installation
25
+
26
+ $ gem install foreman
27
+
28
+ Ruby users should take care *not* to install foreman in their project's `Gemfile`.
29
+
30
+ ## Getting Started
31
+
32
+ * http://blog.daviddollar.org/2011/05/06/introducing-foreman.html
33
+
34
+ ## Supported Ruby versions
35
+
36
+ See [.travis.yml](.travis.yml) for a list of Ruby versions against which Foreman is tested.
37
+
38
+ ## Documentation
39
+
40
+ * [man page](http://ddollar.github.com/foreman)
41
+ * [wiki](http://github.com/ddollar/foreman/wiki)
42
+ * [changelog](https://github.com/ddollar/foreman/blob/master/Changelog.md)
43
+
44
+ ## Ports
45
+
46
+ * [forego](https://github.com/ddollar/forego) - Go
47
+ * [gaffer](https://github.com/jingweno/gaffer) - Java/JVM
48
+ * [honcho](https://github.com/nickstenning/honcho) - python
49
+ * [proclet](https://github.com/kazeburo/Proclet) - Perl
50
+ * [shoreman](https://github.com/hecticjeff/shoreman) - shell
51
+
52
+ ## Authors
53
+
54
+ #### Created and maintained by
55
+ David Dollar
56
+
57
+ #### Patches contributed by
58
+ [Contributor List](https://github.com/ddollar/foreman/contributors)
59
+
60
+ ## License
61
+
62
+ Foreman is licensed under the MIT license.
63
+
64
+ See LICENSE for the full license text.
@@ -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,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 "$@"
@@ -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
@@ -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.upcase %>=<%= 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.upcase %></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,28 @@
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
+ "#{key}=\"#{shell_quote(value)}\""
9
+ end
10
+ app_names << full_name
11
+ -%>
12
+ [program:<%= full_name %>]
13
+ command=<%= process.command %>
14
+ autostart=true
15
+ autorestart=true
16
+ stopsignal=QUIT
17
+ stdout_logfile=<%= log %>/<%= name %>-<%= num %>.log
18
+ stderr_logfile=<%= log %>/<%= name %>-<%= num %>.error.log
19
+ user=<%= user %>
20
+ directory=<%= engine.root %>
21
+ environment=<%= environment.join(',') %>
22
+
23
+ <%
24
+ end
25
+ end
26
+ -%>
27
+ [group:<%= app %>]
28
+ programs=<%= app_names.join(',') %>
@@ -0,0 +1,6 @@
1
+ [Unit]
2
+ StopWhenUnneeded=true
3
+ Wants=<%= process_master_names.join(' ') %>
4
+
5
+ [Install]
6
+ WantedBy=multi-user.target
@@ -0,0 +1,16 @@
1
+ [Unit]
2
+ StopWhenUnneeded=true
3
+ PartOf=<%= "#{app}-#{name}.target" %>
4
+
5
+ [Service]
6
+ User=<%= user %>
7
+ WorkingDirectory=<%= engine.root %>
8
+ Environment=PORT=<%= port %><% engine.env.each_pair do |var,env| %>
9
+ Environment=<%= var.upcase %>=<%= env %><% end %>
10
+ ExecStart=/bin/bash -lc '<%= process.command %>'
11
+ Restart=always
12
+ StandardInput=null
13
+ StandardOutput=syslog
14
+ StandardError=syslog
15
+ SyslogIdentifier=%n
16
+ KillMode=process
@@ -0,0 +1,4 @@
1
+ [Unit]
2
+ StopWhenUnneeded=true
3
+ Wants=<%= process_names.join(' ') %>
4
+ PartOf=<%= "#{app}.target" %>
@@ -0,0 +1,2 @@
1
+ start on runlevel [2345]
2
+ stop on runlevel [!2345]
@@ -0,0 +1,14 @@
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
+ env <%= name.upcase %>='<%= value.gsub(/'/, "'\"'\"'") %>'
8
+ <% end -%>
9
+
10
+ setuid <%= user %>
11
+
12
+ chdir <%= engine.root %>
13
+
14
+ exec <%= process.command %>
@@ -0,0 +1,2 @@
1
+ start on starting <%= app %>
2
+ stop on stopping <%= app %>
@@ -0,0 +1,17 @@
1
+ require "foreman/version"
2
+
3
+ module Foreman
4
+
5
+ def self.runner
6
+ File.expand_path("../../bin/foreman-runner", __FILE__)
7
+ end
8
+
9
+ def self.ruby_18?
10
+ defined?(RUBY_VERSION) and RUBY_VERSION =~ /^1\.8\.\d+/
11
+ end
12
+
13
+ def self.windows?
14
+ defined?(RUBY_PLATFORM) and RUBY_PLATFORM =~ /(win|w)32$/
15
+ end
16
+
17
+ end
@@ -0,0 +1,161 @@
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 "thor"
10
+
11
+ class Foreman::CLI < 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"'
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
+
28
+ class << self
29
+ # Hackery. Take the run method away from Thor so that we can redefine it.
30
+ def is_thor_reserved_word?(word, type)
31
+ return false if word == "run"
32
+ super
33
+ end
34
+ end
35
+
36
+ def start(process=nil)
37
+ check_procfile!
38
+ load_environment!
39
+ engine.load_procfile(procfile)
40
+ engine.options[:formation] = "#{process}=1" if process
41
+ engine.start
42
+ end
43
+
44
+ desc "export FORMAT LOCATION", "Export the application to another process management format"
45
+
46
+ method_option :app, :type => :string, :aliases => "-a"
47
+ method_option :log, :type => :string, :aliases => "-l"
48
+ method_option :run, :type => :string, :aliases => "-r", :desc => "Specify the pid file directory, defaults to /var/run/<application>"
49
+ method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
50
+ method_option :port, :type => :numeric, :aliases => "-p"
51
+ method_option :user, :type => :string, :aliases => "-u"
52
+ method_option :template, :type => :string, :aliases => "-t"
53
+ method_option :concurrency, :type => :string, :aliases => "-c", :banner => '"alpha=5,bar=3"'
54
+
55
+ def export(format, location=nil)
56
+ check_procfile!
57
+ load_environment!
58
+ engine.load_procfile(procfile)
59
+ formatter = Foreman::Export.formatter(format)
60
+ formatter.new(location, engine, options).export
61
+ rescue Foreman::Export::Exception => ex
62
+ error ex.message
63
+ end
64
+
65
+ desc "check", "Validate your application's Procfile"
66
+
67
+ def check
68
+ check_procfile!
69
+ engine.load_procfile(procfile)
70
+ error "no processes defined" unless engine.processes.length > 0
71
+ puts "valid procfile detected (#{engine.process_names.join(', ')})"
72
+ end
73
+
74
+ desc "run COMMAND [ARGS...]", "Run a command using your application's environment"
75
+
76
+ method_option :env, :type => :string, :aliases => "-e", :desc => "Specify an environment file to load, defaults to .env"
77
+ stop_on_unknown_option! :run
78
+
79
+ def run(*args)
80
+ load_environment!
81
+
82
+ if File.exist?(procfile)
83
+ engine.load_procfile(procfile)
84
+ end
85
+
86
+ pid = fork do
87
+ begin
88
+ engine.env.each { |k,v| ENV[k] = v }
89
+ if args.size == 1 && process = engine.process(args.first)
90
+ process.exec(:env => engine.env)
91
+ else
92
+ exec args.shelljoin
93
+ end
94
+ rescue Errno::EACCES
95
+ error "not executable: #{args.first}"
96
+ rescue Errno::ENOENT
97
+ error "command not found: #{args.first}"
98
+ end
99
+ end
100
+ trap("INT") do
101
+ Process.kill(:INT, pid)
102
+ end
103
+ Process.wait(pid)
104
+ exit $?.exitstatus
105
+ rescue Interrupt
106
+ end
107
+
108
+ desc "version", "Display Foreman gem version"
109
+
110
+ def version
111
+ puts Foreman::VERSION
112
+ end
113
+
114
+ no_tasks do
115
+ def engine
116
+ @engine ||= begin
117
+ engine_class = Foreman::Engine::CLI
118
+ engine = engine_class.new(options)
119
+ engine
120
+ end
121
+ end
122
+ end
123
+
124
+ private ######################################################################
125
+
126
+ def error(message)
127
+ puts "ERROR: #{message}"
128
+ exit 1
129
+ end
130
+
131
+ def check_procfile!
132
+ error("#{procfile} does not exist.") unless File.exist?(procfile)
133
+ end
134
+
135
+ def load_environment!
136
+ if options[:env]
137
+ options[:env].split(",").each do |file|
138
+ engine.load_env file
139
+ end
140
+ else
141
+ default_env = File.join(engine.root, ".env")
142
+ engine.load_env default_env if File.exists?(default_env)
143
+ end
144
+ end
145
+
146
+ def procfile
147
+ case
148
+ when options[:procfile] then options[:procfile]
149
+ when options[:root] then File.expand_path(File.join(options[:root], "Procfile"))
150
+ else "Procfile"
151
+ end
152
+ end
153
+
154
+ def options
155
+ original_options = super
156
+ return original_options unless File.exists?(".foreman")
157
+ defaults = ::YAML::load_file(".foreman") || {}
158
+ Thor::CoreExt::HashWithIndifferentAccess.new(defaults.merge(original_options))
159
+ end
160
+
161
+ end