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.
- data/README.md +46 -0
- data/bin/foreman +7 -0
- data/bin/foreman-runner +32 -0
- data/bin/taskman +8 -0
- data/data/example/Procfile +4 -0
- data/data/example/Procfile.without_colon +2 -0
- data/data/example/error +7 -0
- data/data/example/log/neverdie.log +4 -0
- data/data/example/spawnee +14 -0
- data/data/example/spawner +7 -0
- data/data/example/ticker +14 -0
- data/data/example/utf8 +11 -0
- data/data/export/bluepill/master.pill.erb +28 -0
- data/data/export/launchd/launchd.plist.erb +22 -0
- data/data/export/runit/log/run.erb +7 -0
- data/data/export/runit/run.erb +3 -0
- data/data/export/supervisord/app.conf.erb +27 -0
- data/data/export/upstart/master.conf.erb +8 -0
- data/data/export/upstart/process.conf.erb +5 -0
- data/data/export/upstart/process_master.conf.erb +2 -0
- data/lib/foreman.rb +23 -0
- data/lib/foreman/cli.rb +140 -0
- data/lib/foreman/distribution.rb +9 -0
- data/lib/foreman/engine.rb +313 -0
- data/lib/foreman/engine/cli.rb +105 -0
- data/lib/foreman/env.rb +27 -0
- data/lib/foreman/export.rb +34 -0
- data/lib/foreman/export/base.rb +146 -0
- data/lib/foreman/export/bluepill.rb +12 -0
- data/lib/foreman/export/inittab.rb +33 -0
- data/lib/foreman/export/launchd.rb +15 -0
- data/lib/foreman/export/runit.rb +34 -0
- data/lib/foreman/export/supervisord.rb +16 -0
- data/lib/foreman/export/upstart.rb +25 -0
- data/lib/foreman/helpers.rb +45 -0
- data/lib/foreman/process.rb +102 -0
- data/lib/foreman/procfile.rb +92 -0
- data/lib/foreman/version.rb +5 -0
- data/man/foreman.1 +244 -0
- data/spec/foreman/cli_spec.rb +87 -0
- data/spec/foreman/engine_spec.rb +104 -0
- data/spec/foreman/export/base_spec.rb +19 -0
- data/spec/foreman/export/bluepill_spec.rb +37 -0
- data/spec/foreman/export/inittab_spec.rb +40 -0
- data/spec/foreman/export/launchd_spec.rb +21 -0
- data/spec/foreman/export/runit_spec.rb +36 -0
- data/spec/foreman/export/supervisord_spec.rb +36 -0
- data/spec/foreman/export/upstart_spec.rb +88 -0
- data/spec/foreman/export_spec.rb +24 -0
- data/spec/foreman/helpers_spec.rb +26 -0
- data/spec/foreman/process_spec.rb +48 -0
- data/spec/foreman/procfile_spec.rb +41 -0
- data/spec/foreman_spec.rb +16 -0
- data/spec/helper_spec.rb +18 -0
- data/spec/resources/Procfile +4 -0
- data/spec/resources/bin/echo +2 -0
- data/spec/resources/bin/env +2 -0
- data/spec/resources/bin/test +2 -0
- data/spec/resources/bin/utf8 +2 -0
- data/spec/resources/export/bluepill/app-concurrency.pill +49 -0
- data/spec/resources/export/bluepill/app.pill +46 -0
- data/spec/resources/export/inittab/inittab.concurrency +4 -0
- data/spec/resources/export/inittab/inittab.default +4 -0
- data/spec/resources/export/launchd/launchd-a.default +22 -0
- data/spec/resources/export/launchd/launchd-b.default +22 -0
- data/spec/resources/export/runit/app-alpha-1/log/run +7 -0
- data/spec/resources/export/runit/app-alpha-1/run +3 -0
- data/spec/resources/export/runit/app-alpha-2/log/run +7 -0
- data/spec/resources/export/runit/app-alpha-2/run +3 -0
- data/spec/resources/export/runit/app-bravo-1/log/run +7 -0
- data/spec/resources/export/runit/app-bravo-1/run +3 -0
- data/spec/resources/export/supervisord/app-alpha-1.conf +24 -0
- data/spec/resources/export/supervisord/app-alpha-2.conf +24 -0
- data/spec/resources/export/upstart/app-alpha-1.conf +5 -0
- data/spec/resources/export/upstart/app-alpha-2.conf +5 -0
- data/spec/resources/export/upstart/app-alpha.conf +2 -0
- data/spec/resources/export/upstart/app-bravo-1.conf +5 -0
- data/spec/resources/export/upstart/app-bravo.conf +2 -0
- data/spec/resources/export/upstart/app.conf +8 -0
- data/spec/spec_helper.rb +153 -0
- 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,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
|