foreman 0.50.0-x86-mingw32

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 (81) hide show
  1. data/README.md +46 -0
  2. data/bin/foreman +7 -0
  3. data/bin/foreman-runner +32 -0
  4. data/bin/taskman +8 -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/launchd/launchd.plist.erb +22 -0
  15. data/data/export/runit/log/run.erb +7 -0
  16. data/data/export/runit/run.erb +3 -0
  17. data/data/export/supervisord/app.conf.erb +27 -0
  18. data/data/export/upstart/master.conf.erb +8 -0
  19. data/data/export/upstart/process.conf.erb +5 -0
  20. data/data/export/upstart/process_master.conf.erb +2 -0
  21. data/lib/foreman.rb +23 -0
  22. data/lib/foreman/cli.rb +140 -0
  23. data/lib/foreman/distribution.rb +9 -0
  24. data/lib/foreman/engine.rb +313 -0
  25. data/lib/foreman/engine/cli.rb +105 -0
  26. data/lib/foreman/env.rb +27 -0
  27. data/lib/foreman/export.rb +34 -0
  28. data/lib/foreman/export/base.rb +146 -0
  29. data/lib/foreman/export/bluepill.rb +12 -0
  30. data/lib/foreman/export/inittab.rb +33 -0
  31. data/lib/foreman/export/launchd.rb +15 -0
  32. data/lib/foreman/export/runit.rb +34 -0
  33. data/lib/foreman/export/supervisord.rb +16 -0
  34. data/lib/foreman/export/upstart.rb +25 -0
  35. data/lib/foreman/helpers.rb +45 -0
  36. data/lib/foreman/process.rb +102 -0
  37. data/lib/foreman/procfile.rb +92 -0
  38. data/lib/foreman/version.rb +5 -0
  39. data/man/foreman.1 +244 -0
  40. data/spec/foreman/cli_spec.rb +87 -0
  41. data/spec/foreman/engine_spec.rb +104 -0
  42. data/spec/foreman/export/base_spec.rb +19 -0
  43. data/spec/foreman/export/bluepill_spec.rb +37 -0
  44. data/spec/foreman/export/inittab_spec.rb +40 -0
  45. data/spec/foreman/export/launchd_spec.rb +21 -0
  46. data/spec/foreman/export/runit_spec.rb +36 -0
  47. data/spec/foreman/export/supervisord_spec.rb +36 -0
  48. data/spec/foreman/export/upstart_spec.rb +88 -0
  49. data/spec/foreman/export_spec.rb +24 -0
  50. data/spec/foreman/helpers_spec.rb +26 -0
  51. data/spec/foreman/process_spec.rb +48 -0
  52. data/spec/foreman/procfile_spec.rb +41 -0
  53. data/spec/foreman_spec.rb +16 -0
  54. data/spec/helper_spec.rb +18 -0
  55. data/spec/resources/Procfile +4 -0
  56. data/spec/resources/bin/echo +2 -0
  57. data/spec/resources/bin/env +2 -0
  58. data/spec/resources/bin/test +2 -0
  59. data/spec/resources/bin/utf8 +2 -0
  60. data/spec/resources/export/bluepill/app-concurrency.pill +49 -0
  61. data/spec/resources/export/bluepill/app.pill +46 -0
  62. data/spec/resources/export/inittab/inittab.concurrency +4 -0
  63. data/spec/resources/export/inittab/inittab.default +4 -0
  64. data/spec/resources/export/launchd/launchd-a.default +22 -0
  65. data/spec/resources/export/launchd/launchd-b.default +22 -0
  66. data/spec/resources/export/runit/app-alpha-1/log/run +7 -0
  67. data/spec/resources/export/runit/app-alpha-1/run +3 -0
  68. data/spec/resources/export/runit/app-alpha-2/log/run +7 -0
  69. data/spec/resources/export/runit/app-alpha-2/run +3 -0
  70. data/spec/resources/export/runit/app-bravo-1/log/run +7 -0
  71. data/spec/resources/export/runit/app-bravo-1/run +3 -0
  72. data/spec/resources/export/supervisord/app-alpha-1.conf +24 -0
  73. data/spec/resources/export/supervisord/app-alpha-2.conf +24 -0
  74. data/spec/resources/export/upstart/app-alpha-1.conf +5 -0
  75. data/spec/resources/export/upstart/app-alpha-2.conf +5 -0
  76. data/spec/resources/export/upstart/app-alpha.conf +2 -0
  77. data/spec/resources/export/upstart/app-bravo-1.conf +5 -0
  78. data/spec/resources/export/upstart/app-bravo.conf +2 -0
  79. data/spec/resources/export/upstart/app.conf +8 -0
  80. data/spec/spec_helper.rb +153 -0
  81. metadata +148 -0
@@ -0,0 +1,34 @@
1
+ require "foreman"
2
+ require "foreman/helpers"
3
+ require "pathname"
4
+
5
+ module Foreman::Export
6
+ extend Foreman::Helpers
7
+
8
+ class Exception < ::Exception; end
9
+
10
+ def self.formatter(format)
11
+ begin
12
+ require "foreman/export/#{ format.tr('-', '_') }"
13
+ classy_format = classify(format)
14
+ formatter = constantize("Foreman::Export::#{ classy_format }")
15
+ rescue NameError => ex
16
+ error "Unknown export format: #{format} (no class Foreman::Export::#{ classy_format })."
17
+ rescue LoadError => ex
18
+ error "Unknown export format: #{format} (unable to load file 'foreman/export/#{ format.tr('-', '_') }')."
19
+ end
20
+ end
21
+
22
+ def self.error(message)
23
+ raise Foreman::Export::Exception.new(message)
24
+ end
25
+
26
+ end
27
+
28
+ require "foreman/export/base"
29
+ require "foreman/export/inittab"
30
+ require "foreman/export/upstart"
31
+ require "foreman/export/bluepill"
32
+ require "foreman/export/runit"
33
+ require "foreman/export/supervisord"
34
+ require "foreman/export/launchd"
@@ -0,0 +1,146 @@
1
+ require "foreman/export"
2
+ require "ostruct"
3
+ require "pathname"
4
+ require "shellwords"
5
+
6
+ class Foreman::Export::Base
7
+
8
+ attr_reader :location
9
+ attr_reader :engine
10
+ attr_reader :options
11
+ attr_reader :formation
12
+
13
+ # deprecated
14
+ attr_reader :port
15
+
16
+ def initialize(location, engine, options={})
17
+ @location = location
18
+ @engine = engine
19
+ @options = options.dup
20
+ @formation = engine.formation
21
+
22
+ # deprecated
23
+ def port
24
+ Foreman::Export::Base.warn_deprecation!
25
+ engine.base_port
26
+ end
27
+
28
+ # deprecated
29
+ def template
30
+ Foreman::Export::Base.warn_deprecation!
31
+ options[:template]
32
+ end
33
+
34
+ # deprecated
35
+ def @engine.procfile
36
+ Foreman::Export::Base.warn_deprecation!
37
+ @processes.map do |process|
38
+ OpenStruct.new(
39
+ :name => @names[process],
40
+ :process => process
41
+ )
42
+ end
43
+ end
44
+ end
45
+
46
+ def export
47
+ error("Must specify a location") unless location
48
+ FileUtils.mkdir_p(location) rescue error("Could not create: #{location}")
49
+ FileUtils.mkdir_p(log) rescue error("Could not create: #{log}")
50
+ FileUtils.chown(user, nil, log) rescue error("Could not chown #{log} to #{user}")
51
+ end
52
+
53
+ def app
54
+ options[:app] || "app"
55
+ end
56
+
57
+ def log
58
+ options[:log] || "/var/log/#{app}"
59
+ end
60
+
61
+ def user
62
+ options[:user] || app
63
+ end
64
+
65
+ private ######################################################################
66
+
67
+ def self.warn_deprecation!
68
+ @@deprecation_warned ||= false
69
+ return if @@deprecation_warned
70
+ puts "WARNING: Using deprecated exporter interface. Please update your exporter"
71
+ puts "the interface shown in the upstart exporter:"
72
+ puts
73
+ puts "https://github.com/ddollar/foreman/blob/master/lib/foreman/export/upstart.rb"
74
+ puts "https://github.com/ddollar/foreman/blob/master/data/export/upstart/process.conf.erb"
75
+ puts
76
+ @@deprecation_warned = true
77
+ end
78
+
79
+ def error(message)
80
+ raise Foreman::Export::Exception.new(message)
81
+ end
82
+
83
+ def say(message)
84
+ puts "[foreman export] %s" % message
85
+ end
86
+
87
+ def clean(filename)
88
+ return unless File.exists?(filename)
89
+ say "cleaning up: #{filename}"
90
+ FileUtils.rm(filename)
91
+ end
92
+
93
+ def shell_quote(value)
94
+ '"' + Shellwords.escape(value) + '"'
95
+ end
96
+
97
+ # deprecated
98
+ def old_export_template(exporter, file, template_root)
99
+ if template_root && File.exist?(file_path = File.join(template_root, file))
100
+ File.read(file_path)
101
+ elsif File.exist?(file_path = File.expand_path(File.join("~/.foreman/templates", file)))
102
+ File.read(file_path)
103
+ else
104
+ File.read(File.expand_path("../../../../data/export/#{exporter}/#{file}", __FILE__))
105
+ end
106
+ end
107
+
108
+ def export_template(name, file=nil, template_root=nil)
109
+ if file && template_root
110
+ old_export_template name, file, template_root
111
+ else
112
+ name_without_first = name.split("/")[1..-1].join("/")
113
+ matchers = []
114
+ matchers << File.join(options[:template], name_without_first) if options[:template]
115
+ matchers << File.expand_path("~/.foreman/templates/#{name}")
116
+ matchers << File.expand_path("../../../../data/export/#{name}", __FILE__)
117
+ File.read(matchers.detect { |m| File.exists?(m) })
118
+ end
119
+ end
120
+
121
+ def write_template(name, target, binding)
122
+ compiled = ERB.new(export_template(name)).result(binding)
123
+ write_file target, compiled
124
+ end
125
+
126
+ def chmod(mode, file)
127
+ say "setting #{file} to mode #{mode}"
128
+ FileUtils.chmod mode, File.join(location, file)
129
+ end
130
+
131
+ def create_directory(dir)
132
+ say "creating: #{dir}"
133
+ FileUtils.mkdir_p(File.join(location, dir))
134
+ end
135
+
136
+ def write_file(filename, contents)
137
+ say "writing: #{filename}"
138
+
139
+ filename = File.join(location, filename) unless Pathname.new(filename).absolute?
140
+
141
+ File.open(filename, "w") do |file|
142
+ file.puts contents
143
+ end
144
+ end
145
+
146
+ end
@@ -0,0 +1,12 @@
1
+ require "erb"
2
+ require "foreman/export"
3
+
4
+ class Foreman::Export::Bluepill < Foreman::Export::Base
5
+
6
+ def export
7
+ super
8
+ clean "#{location}/#{app}.pill"
9
+ write_template "bluepill/master.pill.erb", "#{app}.pill", binding
10
+ end
11
+
12
+ end
@@ -0,0 +1,33 @@
1
+ require "foreman/export"
2
+
3
+ class Foreman::Export::Inittab < Foreman::Export::Base
4
+
5
+ def export
6
+ error("Must specify a location") unless location
7
+
8
+ inittab = []
9
+ inittab << "# ----- foreman #{app} processes -----"
10
+
11
+ index = 1
12
+ engine.each_process do |name, process|
13
+ 1.upto(engine.formation[name]) do |num|
14
+ id = app.slice(0, 2).upcase + sprintf("%02d", index)
15
+ port = engine.port_for(process, num)
16
+ inittab << "#{id}:4:respawn:/bin/su - #{user} -c 'PORT=#{port} #{process.command} >> #{log}/#{name}-#{num}.log 2>&1'"
17
+ index += 1
18
+ end
19
+ end
20
+
21
+ inittab << "# ----- end foreman #{app} processes -----"
22
+
23
+ inittab = inittab.join("\n") + "\n"
24
+
25
+ if location == "-"
26
+ puts inittab
27
+ else
28
+ say "writing: #{location}"
29
+ File.open(location, "w") { |file| file.puts inittab }
30
+ end
31
+ end
32
+
33
+ end
@@ -0,0 +1,15 @@
1
+ require "erb"
2
+ require "foreman/export"
3
+
4
+ class Foreman::Export::Launchd < Foreman::Export::Base
5
+
6
+ def export
7
+ super
8
+ engine.each_process do |name, process|
9
+ 1.upto(engine.formation[name]) do |num|
10
+ write_template "launchd/launchd.plist.erb", "#{app}-#{name}-#{num}.plist", binding
11
+ end
12
+ end
13
+ end
14
+
15
+ end
@@ -0,0 +1,34 @@
1
+ require "erb"
2
+ require "foreman/export"
3
+
4
+ class Foreman::Export::Runit < Foreman::Export::Base
5
+
6
+ ENV_VARIABLE_REGEX = /([a-zA-Z_]+[a-zA-Z0-9_]*)=(\S+)/
7
+
8
+ def export
9
+ super
10
+
11
+ engine.each_process do |name, process|
12
+ 1.upto(engine.formation[name]) do |num|
13
+ process_directory = "#{app}-#{name}-#{num}"
14
+
15
+ create_directory process_directory
16
+ create_directory "#{process_directory}/env"
17
+ create_directory "#{process_directory}/log"
18
+
19
+ write_template "runit/run.erb", "#{process_directory}/run", binding
20
+ chmod 0755, "#{process_directory}/run"
21
+
22
+ port = engine.port_for(process, num)
23
+ engine.env.merge("PORT" => port.to_s).each do |key, value|
24
+ write_file "#{process_directory}/env/#{key}", value
25
+ end
26
+
27
+ write_template "runit/log/run.erb", "#{process_directory}/log/run", binding
28
+ chmod 0755, "#{process_directory}/log/run"
29
+ end
30
+ end
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,16 @@
1
+ require "erb"
2
+ require "foreman/export"
3
+
4
+ class Foreman::Export::Supervisord < Foreman::Export::Base
5
+
6
+ def export
7
+ super
8
+
9
+ Dir["#{location}/#{app}*.conf"].each do |file|
10
+ clean file
11
+ end
12
+
13
+ write_template "supervisord/app.conf.erb", "#{app}.conf", binding
14
+ end
15
+
16
+ end
@@ -0,0 +1,25 @@
1
+ require "erb"
2
+ require "foreman/export"
3
+
4
+ class Foreman::Export::Upstart < Foreman::Export::Base
5
+
6
+ def export
7
+ super
8
+
9
+ Dir["#{location}/#{app}*.conf"].each do |file|
10
+ clean file
11
+ end
12
+
13
+ write_template "upstart/master.conf.erb", "#{app}.conf", binding
14
+
15
+ engine.each_process do |name, process|
16
+ next if engine.formation[name] < 1
17
+ write_template "upstart/process_master.conf.erb", "#{app}-#{name}.conf", binding
18
+
19
+ 1.upto(engine.formation[name]) do |num|
20
+ port = engine.port_for(process, num)
21
+ write_template "upstart/process.conf.erb", "#{app}-#{name}-#{num}.conf", binding
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,45 @@
1
+ module Foreman::Helpers
2
+ # Copied whole sale from, https://github.com/defunkt/resque/
3
+
4
+ # Given a word with dashes, returns a camel cased version of it.
5
+ #
6
+ # classify('job-name') # => 'JobName'
7
+ def classify(dashed_word)
8
+ dashed_word.split('-').each { |part| part[0] = part[0].chr.upcase }.join
9
+ end # Tries to find a constant with the name specified in the argument string:
10
+
11
+ #
12
+ # constantize("Module") # => Module
13
+ # constantize("Test::Unit") # => Test::Unit
14
+ #
15
+ # The name is assumed to be the one of a top-level constant, no matter
16
+ # whether it starts with "::" or not. No lexical context is taken into
17
+ # account:
18
+ #
19
+ # C = 'outside'
20
+ # module M
21
+ # C = 'inside'
22
+ # C # => 'inside'
23
+ # constantize("C") # => 'outside', same as ::C
24
+ # end
25
+ #
26
+ # NameError is raised when the constant is unknown.
27
+ def constantize(camel_cased_word)
28
+ camel_cased_word = camel_cased_word.to_s
29
+
30
+ names = camel_cased_word.split('::')
31
+ names.shift if names.empty? || names.first.empty?
32
+
33
+ constant = Object
34
+ names.each do |name|
35
+ args = Module.method(:const_get).arity != 1 ? [false] : []
36
+
37
+ if constant.const_defined?(name, *args)
38
+ constant = constant.const_get(name)
39
+ else
40
+ constant = constant.const_missing(name)
41
+ end
42
+ end
43
+ constant
44
+ end
45
+ end
@@ -0,0 +1,102 @@
1
+ require "foreman"
2
+ require "rubygems"
3
+
4
+ class Foreman::Process
5
+
6
+ attr_reader :command
7
+ attr_reader :env
8
+
9
+ # Create a Process
10
+ #
11
+ # @param [String] command The command to run
12
+ # @param [Hash] options
13
+ #
14
+ # @option options [String] :cwd (./) Change to this working directory before executing the process
15
+ # @option options [Hash] :env ({}) Environment variables to set for this process
16
+ #
17
+ def initialize(command, options={})
18
+ @command = command
19
+ @options = options.dup
20
+
21
+ @options[:env] ||= {}
22
+ end
23
+
24
+ # Run a +Process+
25
+ #
26
+ # @param [Hash] options
27
+ #
28
+ # @option options :env ({}) Environment variables to set for this execution
29
+ # @option options :output ($stdout) The output stream
30
+ #
31
+ # @returns [Fixnum] pid The +pid+ of the process
32
+ #
33
+ def run(options={})
34
+ env = options[:env] ? @options[:env].merge(options[:env]) : @options[:env]
35
+ output = options[:output] || $stdout
36
+
37
+ if Foreman.windows?
38
+ Dir.chdir(cwd) do
39
+ expanded_command = command.dup
40
+ env.each do |key, val|
41
+ expanded_command.gsub!("$#{key}", val)
42
+ end
43
+ Process.spawn env, expanded_command, :out => output, :err => output
44
+ end
45
+ elsif Foreman.jruby?
46
+ Dir.chdir(cwd) do
47
+ require "posix/spawn"
48
+ POSIX::Spawn.spawn env, command, :out => output, :err => output
49
+ end
50
+ elsif Foreman.ruby_18?
51
+ Dir.chdir(cwd) do
52
+ fork do
53
+ $stdout.reopen output
54
+ $stderr.reopen output
55
+ env.each { |k,v| ENV[k] = v }
56
+ exec command
57
+ end
58
+ end
59
+ else
60
+ Dir.chdir(cwd) do
61
+ Process.spawn env, command, :out => output, :err => output
62
+ end
63
+ end
64
+ end
65
+
66
+ # Send a signal to this +Process+
67
+ #
68
+ # @param [String] signal The signal to send
69
+ #
70
+ def kill(signal)
71
+ if Foreman.windows?
72
+ pid && Process.kill(signal, pid)
73
+ else
74
+ pid && Process.kill("-#{signal}", pid)
75
+ end
76
+ rescue Errno::ESRCH
77
+ false
78
+ end
79
+
80
+ # Test whether or not this +Process+ is still running
81
+ #
82
+ # @returns [Boolean]
83
+ #
84
+ def alive?
85
+ kill(0)
86
+ end
87
+
88
+ # Test whether or not this +Process+ has terminated
89
+ #
90
+ # @returns [Boolean]
91
+ #
92
+ def dead?
93
+ !alive?
94
+ end
95
+
96
+ private
97
+
98
+ def cwd
99
+ @options[:cwd] || "."
100
+ end
101
+
102
+ end