foreman 0.50.0-x86-mswin32

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