foreman 0.46.0-mingw32 → 0.50.0-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 +6 -0
- data/bin/foreman-runner +3 -7
- data/bin/taskman +8 -0
- data/data/example/Procfile +4 -3
- data/data/example/spawnee +14 -0
- data/data/example/spawner +7 -0
- data/data/export/bluepill/master.pill.erb +11 -10
- data/data/export/launchd/launchd.plist.erb +22 -0
- data/data/export/runit/log/run.erb +7 -0
- data/data/export/runit/run.erb +2 -2
- data/data/export/supervisord/app.conf.erb +12 -12
- data/data/export/upstart/master.conf.erb +2 -2
- data/data/export/upstart/process.conf.erb +3 -3
- data/lib/foreman.rb +4 -0
- data/lib/foreman/cli.rb +59 -23
- data/lib/foreman/engine.rb +233 -147
- data/lib/foreman/engine/cli.rb +105 -0
- data/lib/foreman/env.rb +27 -0
- data/lib/foreman/export.rb +2 -2
- data/lib/foreman/export/base.rb +107 -12
- data/lib/foreman/export/bluepill.rb +3 -17
- data/lib/foreman/export/inittab.rb +8 -11
- data/lib/foreman/export/launchd.rb +15 -0
- data/lib/foreman/export/runit.rb +14 -39
- data/lib/foreman/export/supervisord.rb +3 -13
- data/lib/foreman/export/upstart.rb +9 -27
- data/lib/foreman/process.rb +73 -67
- data/lib/foreman/procfile.rb +59 -25
- data/lib/foreman/version.rb +1 -1
- data/man/foreman.1 +5 -1
- data/spec/foreman/cli_spec.rb +46 -150
- data/spec/foreman/engine_spec.rb +47 -74
- data/spec/foreman/export/base_spec.rb +4 -7
- data/spec/foreman/export/bluepill_spec.rb +7 -6
- data/spec/foreman/export/inittab_spec.rb +7 -7
- data/spec/foreman/export/launchd_spec.rb +21 -0
- data/spec/foreman/export/runit_spec.rb +12 -17
- data/spec/foreman/export/supervisord_spec.rb +7 -56
- data/spec/foreman/export/upstart_spec.rb +22 -21
- data/spec/foreman/process_spec.rb +27 -110
- data/spec/foreman/procfile_spec.rb +26 -16
- 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/export/bluepill/app-concurrency.pill +6 -4
- data/spec/resources/export/bluepill/app.pill +6 -4
- 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 → app-alpha-1/log/run} +0 -0
- data/spec/resources/export/runit/{app-alpha-1-run → app-alpha-1/run} +0 -0
- data/spec/resources/export/runit/{app-alpha-2-log-run → app-alpha-2/log/run} +0 -0
- data/spec/resources/export/runit/{app-alpha-2-run → app-alpha-2/run} +0 -0
- data/spec/resources/export/runit/{app-bravo-1-log-run → app-bravo-1/log/run} +0 -0
- data/spec/resources/export/runit/{app-bravo-1-run → app-bravo-1/run} +0 -0
- data/spec/resources/export/supervisord/app-alpha-1.conf +24 -0
- data/spec/resources/export/supervisord/app-alpha-2.conf +4 -4
- data/spec/spec_helper.rb +57 -6
- metadata +29 -21
- data/data/export/runit/log_run.erb +0 -7
- data/lib/foreman/color.rb +0 -40
- data/lib/foreman/procfile_entry.rb +0 -26
- data/lib/foreman/utils.rb +0 -18
- data/spec/foreman/color_spec.rb +0 -31
- data/spec/foreman/procfile_entry_spec.rb +0 -13
- data/spec/resources/export/supervisord/app-env-with-comma.conf +0 -24
- data/spec/resources/export/supervisord/app-env.conf +0 -21
- data/spec/resources/export/supervisord/app.conf +0 -24
@@ -0,0 +1,105 @@
|
|
1
|
+
require "foreman/engine"
|
2
|
+
|
3
|
+
class Foreman::Engine::CLI < Foreman::Engine
|
4
|
+
|
5
|
+
module Color
|
6
|
+
|
7
|
+
ANSI = {
|
8
|
+
:reset => 0,
|
9
|
+
:black => 30,
|
10
|
+
:red => 31,
|
11
|
+
:green => 32,
|
12
|
+
:yellow => 33,
|
13
|
+
:blue => 34,
|
14
|
+
:magenta => 35,
|
15
|
+
:cyan => 36,
|
16
|
+
:white => 37,
|
17
|
+
:bright_black => 30,
|
18
|
+
:bright_red => 31,
|
19
|
+
:bright_green => 32,
|
20
|
+
:bright_yellow => 33,
|
21
|
+
:bright_blue => 34,
|
22
|
+
:bright_magenta => 35,
|
23
|
+
:bright_cyan => 36,
|
24
|
+
:bright_white => 37,
|
25
|
+
}
|
26
|
+
|
27
|
+
def self.enable(io, force=false)
|
28
|
+
io.extend(self)
|
29
|
+
@@color_force = force
|
30
|
+
end
|
31
|
+
|
32
|
+
def color?
|
33
|
+
return true if @@color_force
|
34
|
+
return true if Foreman.windows?
|
35
|
+
return false unless self.respond_to?(:isatty)
|
36
|
+
self.isatty && ENV["TERM"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def color(name)
|
40
|
+
return "" unless color?
|
41
|
+
return "" unless ansi = ANSI[name.to_sym]
|
42
|
+
"\e[#{ansi}m"
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
FOREMAN_COLORS = %w( cyan yellow green magenta red blue intense_cyan intense_yellow
|
48
|
+
intense_green intense_magenta intense_red, intense_blue )
|
49
|
+
|
50
|
+
def startup
|
51
|
+
@colors = map_colors
|
52
|
+
proctitle "foreman: master"
|
53
|
+
require "win32console" if Foreman.windows?
|
54
|
+
Color.enable($stdout, options[:color]) unless $stdout.respond_to?(:color?)
|
55
|
+
end
|
56
|
+
|
57
|
+
def output(name, data)
|
58
|
+
data.to_s.chomp.split("\n").each do |message|
|
59
|
+
output = ""
|
60
|
+
output += $stdout.color(@colors[name.split(".").first].to_sym)
|
61
|
+
output += "#{Time.now.strftime("%H:%M:%S")} #{pad_process_name(name)} | "
|
62
|
+
output += $stdout.color(:reset)
|
63
|
+
output += message
|
64
|
+
$stdout.puts output
|
65
|
+
$stdout.flush
|
66
|
+
end
|
67
|
+
rescue Errno::EPIPE
|
68
|
+
terminate_gracefully
|
69
|
+
end
|
70
|
+
|
71
|
+
def shutdown
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def name_padding
|
77
|
+
@name_padding ||= begin
|
78
|
+
index_padding = @names.values.map { |n| formation[n] }.max.to_s.length + 1
|
79
|
+
name_padding = @names.values.map { |n| n.length + index_padding }.sort.last
|
80
|
+
[ 6, name_padding ].max
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def pad_process_name(name)
|
85
|
+
name.ljust(name_padding, " ")
|
86
|
+
end
|
87
|
+
|
88
|
+
def map_colors
|
89
|
+
colors = Hash.new("white")
|
90
|
+
@names.values.each_with_index do |name, index|
|
91
|
+
colors[name] = FOREMAN_COLORS[index % FOREMAN_COLORS.length]
|
92
|
+
end
|
93
|
+
colors["system"] = "intense_white"
|
94
|
+
colors
|
95
|
+
end
|
96
|
+
|
97
|
+
def proctitle(title)
|
98
|
+
$0 = title
|
99
|
+
end
|
100
|
+
|
101
|
+
def termtitle(title)
|
102
|
+
printf("\033]0;#{title}\007") unless Foreman.windows?
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
data/lib/foreman/env.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require "foreman"
|
2
|
+
|
3
|
+
class Foreman::Env
|
4
|
+
|
5
|
+
attr_reader :entries
|
6
|
+
|
7
|
+
def initialize(filename)
|
8
|
+
@entries = File.read(filename).split("\n").inject({}) do |ax, line|
|
9
|
+
if line =~ /\A([A-Za-z_0-9]+)=(.*)\z/
|
10
|
+
key = $1
|
11
|
+
case val = $2
|
12
|
+
when /\A'(.*)'\z/ then ax[key] = $1
|
13
|
+
when /\A"(.*)"\z/ then ax[key] = $1.gsub(/\\(.)/, '\1')
|
14
|
+
else ax[key] = val
|
15
|
+
end
|
16
|
+
end
|
17
|
+
ax
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def entries
|
22
|
+
@entries.each do |key, value|
|
23
|
+
yield key, value
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/foreman/export.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "foreman"
|
2
2
|
require "foreman/helpers"
|
3
|
+
require "pathname"
|
3
4
|
|
4
5
|
module Foreman::Export
|
5
6
|
extend Foreman::Helpers
|
@@ -24,11 +25,10 @@ module Foreman::Export
|
|
24
25
|
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
28
|
require "foreman/export/base"
|
29
29
|
require "foreman/export/inittab"
|
30
30
|
require "foreman/export/upstart"
|
31
31
|
require "foreman/export/bluepill"
|
32
32
|
require "foreman/export/runit"
|
33
33
|
require "foreman/export/supervisord"
|
34
|
-
|
34
|
+
require "foreman/export/launchd"
|
data/lib/foreman/export/base.rb
CHANGED
@@ -1,27 +1,81 @@
|
|
1
1
|
require "foreman/export"
|
2
|
-
require "
|
2
|
+
require "ostruct"
|
3
|
+
require "pathname"
|
4
|
+
require "shellwords"
|
3
5
|
|
4
6
|
class Foreman::Export::Base
|
5
7
|
|
6
|
-
attr_reader :location
|
8
|
+
attr_reader :location
|
9
|
+
attr_reader :engine
|
10
|
+
attr_reader :options
|
11
|
+
attr_reader :formation
|
12
|
+
|
13
|
+
# deprecated
|
14
|
+
attr_reader :port
|
7
15
|
|
8
16
|
def initialize(location, engine, options={})
|
9
|
-
@location
|
10
|
-
@engine
|
11
|
-
@
|
12
|
-
@
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
17
44
|
end
|
18
45
|
|
19
46
|
def export
|
20
|
-
|
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
|
21
63
|
end
|
22
64
|
|
23
65
|
private ######################################################################
|
24
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
|
+
|
25
79
|
def error(message)
|
26
80
|
raise Foreman::Export::Exception.new(message)
|
27
81
|
end
|
@@ -29,8 +83,19 @@ private ######################################################################
|
|
29
83
|
def say(message)
|
30
84
|
puts "[foreman export] %s" % message
|
31
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
|
32
96
|
|
33
|
-
|
97
|
+
# deprecated
|
98
|
+
def old_export_template(exporter, file, template_root)
|
34
99
|
if template_root && File.exist?(file_path = File.join(template_root, file))
|
35
100
|
File.read(file_path)
|
36
101
|
elsif File.exist?(file_path = File.expand_path(File.join("~/.foreman/templates", file)))
|
@@ -40,9 +105,39 @@ private ######################################################################
|
|
40
105
|
end
|
41
106
|
end
|
42
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
|
+
|
43
136
|
def write_file(filename, contents)
|
44
137
|
say "writing: #{filename}"
|
45
138
|
|
139
|
+
filename = File.join(location, filename) unless Pathname.new(filename).absolute?
|
140
|
+
|
46
141
|
File.open(filename, "w") do |file|
|
47
142
|
file.puts contents
|
48
143
|
end
|
@@ -4,23 +4,9 @@ require "foreman/export"
|
|
4
4
|
class Foreman::Export::Bluepill < Foreman::Export::Base
|
5
5
|
|
6
6
|
def export
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
app = self.app || File.basename(engine.directory)
|
12
|
-
user = self.user || app
|
13
|
-
log_root = self.log || "/var/log/#{app}"
|
14
|
-
template_root = self.template
|
15
|
-
|
16
|
-
Dir["#{location}/#{app}.pill"].each do |file|
|
17
|
-
say "cleaning up: #{file}"
|
18
|
-
FileUtils.rm(file)
|
19
|
-
end
|
20
|
-
|
21
|
-
master_template = export_template("bluepill", "master.pill.erb", template_root)
|
22
|
-
master_config = ERB.new(master_template).result(binding)
|
23
|
-
write_file "#{location}/#{app}.pill", master_config
|
7
|
+
super
|
8
|
+
clean "#{location}/#{app}.pill"
|
9
|
+
write_template "bluepill/master.pill.erb", "#{app}.pill", binding
|
24
10
|
end
|
25
11
|
|
26
12
|
end
|
@@ -3,21 +3,19 @@ require "foreman/export"
|
|
3
3
|
class Foreman::Export::Inittab < Foreman::Export::Base
|
4
4
|
|
5
5
|
def export
|
6
|
-
|
7
|
-
user = self.user || app
|
8
|
-
log_root = self.log || "/var/log/#{app}"
|
6
|
+
error("Must specify a location") unless location
|
9
7
|
|
10
8
|
inittab = []
|
11
9
|
inittab << "# ----- foreman #{app} processes -----"
|
12
10
|
|
13
|
-
|
14
|
-
|
11
|
+
index = 1
|
12
|
+
engine.each_process do |name, process|
|
13
|
+
1.upto(engine.formation[name]) do |num|
|
15
14
|
id = app.slice(0, 2).upcase + sprintf("%02d", index)
|
16
|
-
port = engine.port_for(process, num
|
17
|
-
inittab << "#{id}:4:respawn:/bin/su - #{user} -c 'PORT=#{port} #{process.command} >> #{
|
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'"
|
18
17
|
index += 1
|
19
18
|
end
|
20
|
-
index
|
21
19
|
end
|
22
20
|
|
23
21
|
inittab << "# ----- end foreman #{app} processes -----"
|
@@ -27,9 +25,8 @@ class Foreman::Export::Inittab < Foreman::Export::Base
|
|
27
25
|
if location == "-"
|
28
26
|
puts inittab
|
29
27
|
else
|
30
|
-
|
31
|
-
|
32
|
-
write_file(location, inittab)
|
28
|
+
say "writing: #{location}"
|
29
|
+
File.open(location, "w") { |file| file.puts inittab }
|
33
30
|
end
|
34
31
|
end
|
35
32
|
|
@@ -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
|
data/lib/foreman/export/runit.rb
CHANGED
@@ -2,58 +2,33 @@ require "erb"
|
|
2
2
|
require "foreman/export"
|
3
3
|
|
4
4
|
class Foreman::Export::Runit < Foreman::Export::Base
|
5
|
+
|
5
6
|
ENV_VARIABLE_REGEX = /([a-zA-Z_]+[a-zA-Z0-9_]*)=(\S+)/
|
6
7
|
|
7
8
|
def export
|
8
|
-
|
9
|
-
|
10
|
-
app = self.app || File.basename(engine.directory)
|
11
|
-
user = self.user || app
|
12
|
-
log_root = self.log || "/var/log/#{app}"
|
13
|
-
template_root = self.template
|
9
|
+
super
|
14
10
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
engine.procfile.entries.each do |process|
|
19
|
-
1.upto(self.concurrency[process.name]) do |num|
|
20
|
-
process_directory = "#{location}/#{app}-#{process.name}-#{num}"
|
21
|
-
process_env_directory = "#{process_directory}/env"
|
22
|
-
process_log_directory = "#{process_directory}/log"
|
11
|
+
engine.each_process do |name, process|
|
12
|
+
1.upto(engine.formation[name]) do |num|
|
13
|
+
process_directory = "#{app}-#{name}-#{num}"
|
23
14
|
|
24
15
|
create_directory process_directory
|
25
|
-
create_directory
|
26
|
-
create_directory
|
27
|
-
|
28
|
-
run = ERB.new(run_template).result(binding)
|
29
|
-
write_file "#{process_directory}/run", run
|
30
|
-
FileUtils.chmod 0755, "#{process_directory}/run"
|
16
|
+
create_directory "#{process_directory}/env"
|
17
|
+
create_directory "#{process_directory}/log"
|
31
18
|
|
32
|
-
|
33
|
-
|
34
|
-
merge(engine.environment).
|
35
|
-
merge(inline_variables(process.command))
|
19
|
+
write_template "runit/run.erb", "#{process_directory}/run", binding
|
20
|
+
chmod 0755, "#{process_directory}/run"
|
36
21
|
|
37
|
-
|
38
|
-
|
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
|
39
25
|
end
|
40
26
|
|
41
|
-
|
42
|
-
|
43
|
-
FileUtils.chmod 0755, "#{process_log_directory}/run"
|
27
|
+
write_template "runit/log/run.erb", "#{process_directory}/log/run", binding
|
28
|
+
chmod 0755, "#{process_directory}/log/run"
|
44
29
|
end
|
45
30
|
end
|
46
31
|
|
47
32
|
end
|
48
33
|
|
49
|
-
private
|
50
|
-
def create_directory(location)
|
51
|
-
say "creating: #{location}"
|
52
|
-
FileUtils.mkdir_p(location)
|
53
|
-
end
|
54
|
-
|
55
|
-
def inline_variables(command)
|
56
|
-
variable_name_regex =
|
57
|
-
Hash[*command.scan(ENV_VARIABLE_REGEX).flatten]
|
58
|
-
end
|
59
34
|
end
|