foreman-systemd 0.78.0

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