foreman 0.3.2 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -6,6 +6,7 @@ $:.unshift File.expand_path("../lib", __FILE__)
6
6
  require "foreman"
7
7
 
8
8
  task :default => :spec
9
+ task :release => :man
9
10
 
10
11
  desc "Run all specs"
11
12
  Rspec::Core::RakeTask.new(:spec) do |t|
@@ -23,6 +24,16 @@ Rspec::Core::RakeTask.new("rcov:build") do |t|
23
24
  t.rcov_opts = [ "--exclude", Gem.default_dir , "--exclude", "spec" ]
24
25
  end
25
26
 
27
+ desc 'Build the manual'
28
+ task :man do
29
+ require 'ronn'
30
+ ENV['RONN_MANUAL'] = "Foreman Manual"
31
+ ENV['RONN_ORGANIZATION'] = "Foreman #{Foreman::VERSION}"
32
+ sh "ronn -w -s toc -r5 --markdown man/*.ronn"
33
+ sh "git add man/*.?"
34
+ sh "git commit -m \"updating man pages\""
35
+ end
36
+
26
37
  ######################################################
27
38
 
28
39
  begin
data/lib/foreman.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Foreman
2
2
 
3
- VERSION = "0.3.2"
3
+ VERSION = "0.4.1"
4
4
 
5
5
  class AppDoesNotExist < Exception; end
6
6
 
data/lib/foreman/cli.rb CHANGED
@@ -6,46 +6,58 @@ require "thor"
6
6
 
7
7
  class Foreman::CLI < Thor
8
8
 
9
- desc "start [PROCFILE]", "Run the app described in PROCFILE"
9
+ class_option :procfile, :type => :string, :aliases => "-p", :desc => "Default: ./Procfile"
10
10
 
11
- def start(procfile="Procfile")
12
- error "#{procfile} does not exist." unless procfile_exists?(procfile)
13
- Foreman::Engine.new(procfile).start
14
- end
11
+ desc "start [PROCESS]", "Start the application, or a specific process"
15
12
 
16
- desc "execute PROCESS [PROCFILE]", "Run an instance of the specified process from PROCFILE"
13
+ method_option :screen, :type => :boolean, :aliases => "-s"
17
14
 
18
- def execute(process, procfile="Procfile")
19
- error "#{procfile} does not exist." unless procfile_exists?(procfile)
20
- Foreman::Engine.new(procfile).execute(process)
15
+ def start(process=nil)
16
+ check_procfile!
17
+
18
+ if process
19
+ engine.execute(process)
20
+ elsif options[:screen]
21
+ engine.screen
22
+ else
23
+ engine.start
24
+ end
21
25
  end
22
26
 
23
- desc "screen [PROCFILE]", "Run the app described in PROCFILE as screen windows"
27
+ desc "export FORMAT LOCATION", "Export the application to another process management format"
24
28
 
25
- def screen(procfile="Procfile")
26
- error "#{procfile} does not exist." unless procfile_exists?(procfile)
27
- Foreman::Engine.new(procfile).screen
28
- end
29
+ method_option :app, :type => :string, :aliases => "-a"
30
+ method_option :concurrency, :type => :string, :aliases => "-c",
31
+ :banner => '"alpha=5,bar=3"'
29
32
 
30
- desc "export APP [PROCFILE] [FORMAT]", "Export the app described in PROCFILE as APP to another FORMAT"
31
-
32
- def export(app, procfile="Procfile", format="upstart")
33
- error "#{procfile} does not exist." unless procfile_exists?(procfile)
33
+ def export(format, location=nil)
34
+ check_procfile!
34
35
 
35
36
  formatter = case format
36
37
  when "upstart" then Foreman::Export::Upstart
37
38
  else error "Unknown export format: #{format}."
38
39
  end
39
40
 
40
- formatter.new(Foreman::Engine.new(procfile)).export(app)
41
+ formatter.new(engine).export(location,
42
+ :name => options[:app],
43
+ :concurrency => options[:concurrency]
44
+ )
45
+ rescue Foreman::Export::Exception => ex
46
+ error ex.message
41
47
  end
42
48
 
43
- desc "scale APP PROCESS AMOUNT", "Change the concurrency of a given process type"
49
+ private ######################################################################
50
+
51
+ def check_procfile!
52
+ error("Procfile does not exist.") unless File.exist?(procfile)
53
+ end
54
+
55
+ def engine
56
+ @engine ||= Foreman::Engine.new(procfile)
57
+ end
44
58
 
45
- def scale(app, process, amount)
46
- config = Foreman::Configuration.new(app)
47
- error "No such process: #{process}." unless config.processes[process]
48
- config.scale(process, amount)
59
+ def procfile
60
+ options[:procfile] || "./Procfile"
49
61
  end
50
62
 
51
63
  private ######################################################################
@@ -83,8 +83,8 @@ private ######################################################################
83
83
  info stdin.gets, process
84
84
  end
85
85
  end
86
- rescue PTY::ChildExited
87
- # exited
86
+ rescue PTY::ChildExited, Interrupt
87
+ info "process exiting", process
88
88
  end
89
89
  end
90
90
  end
@@ -1,6 +1,7 @@
1
1
  require "foreman"
2
2
 
3
3
  module Foreman::Export
4
+ class Exception < ::Exception; end
4
5
  end
5
6
 
6
7
  require "foreman/export/upstart"
@@ -0,0 +1,48 @@
1
+ require "foreman/configuration"
2
+ require "foreman/export"
3
+
4
+ class Foreman::Export::Base
5
+
6
+ attr_reader :engine
7
+
8
+ def initialize(engine)
9
+ @engine = engine
10
+ end
11
+
12
+ def export
13
+ raise "export method must be overridden"
14
+ end
15
+
16
+ private ######################################################################
17
+
18
+ def error(message)
19
+ raise Foreman::Export::Exception.new(message)
20
+ end
21
+
22
+ def say(message)
23
+ puts "[foreman export] %s" % message
24
+ end
25
+
26
+ def export_template(name)
27
+ File.read(File.expand_path("../../../../export/#{name}", __FILE__))
28
+ end
29
+
30
+ def parse_concurrency(concurrency)
31
+ @concurrency ||= begin
32
+ pairs = concurrency.to_s.gsub(/\s/, "").split(",")
33
+ pairs.inject(Hash.new(1)) do |hash, pair|
34
+ process, amount = pair.split("=")
35
+ hash.update(process => amount.to_i)
36
+ end
37
+ end
38
+ end
39
+
40
+ def write_file(filename, contents)
41
+ say "writing: #{filename}"
42
+
43
+ File.open(filename, "w") do |file|
44
+ file.puts contents
45
+ end
46
+ end
47
+
48
+ end
@@ -1,51 +1,42 @@
1
+ require "erb"
1
2
  require "foreman/configuration"
2
- require "foreman/export"
3
+ require "foreman/export/base"
3
4
 
4
- class Foreman::Export::Upstart
5
+ class Foreman::Export::Upstart < Foreman::Export::Base
5
6
 
6
- attr_reader :engine
7
+ def export(location, options={})
8
+ error("Must specify a location") unless location
7
9
 
8
- def initialize(engine)
9
- @engine = engine
10
- end
11
-
12
- def export(app)
13
- FileUtils.mkdir_p "/etc/foreman"
14
- FileUtils.mkdir_p "/etc/init"
15
-
16
- config = Foreman::Configuration.new(app)
10
+ FileUtils.mkdir_p location
17
11
 
18
- write_file "/etc/init/#{app}.conf", <<-UPSTART_MASTER
19
- pre-start script
12
+ app = options[:app] || File.basename(engine.directory)
20
13
 
21
- bash << "EOF"
22
- mkdir -p /var/log/#{app}
14
+ Dir["#{location}/#{app}*.conf"].each do |file|
15
+ say "cleaning up: #{file}"
16
+ FileUtils.rm(file)
17
+ end
23
18
 
24
- if [ -f /etc/foreman/#{app}.conf ]; then
25
- source /etc/foreman/#{app}.conf
26
- fi
19
+ concurrency = parse_concurrency(options[:concurrency])
27
20
 
28
- for process in $( echo "$#{app}_processes" ); do
29
- process_count_config="#{app}_$process"
30
- process_count=${!process_count_config}
21
+ master_template = export_template("upstart/master.conf.erb")
22
+ master_config = ERB.new(master_template).result(binding)
23
+ write_file "#{location}/#{app}.conf", master_config
31
24
 
32
- for ((i=1; i<=${process_count:=1}; i+=1)); do
33
- start #{app}-$process NUM=$i
34
- done
35
- done
36
- EOF
25
+ process_template = export_template("upstart/process.conf.erb")
26
+
27
+ engine.processes.values.each do |process|
28
+ 1.upto(concurrency[process.name]) do |num|
29
+ process_config = ERB.new(process_template).result(binding)
30
+ write_file "#{location}/#{app}-#{process.name}-#{num}.conf", process_config
31
+ end
32
+ end
37
33
 
38
- end script
34
+ return
35
+ write_file "#{location}/#{app}.conf", <<-UPSTART_MASTER
39
36
  UPSTART_MASTER
40
37
 
41
- engine.processes.values.each do |process|
42
- write_file "/etc/init/#{app}-#{process.name}.conf", <<-UPSTART_CHILD
43
- instance $NUM
44
- stop on stopping #{app}
45
- respawn
46
-
47
- chdir #{engine.directory}
48
- exec #{process.command} >>/var/log/#{app}/#{process.name}.log 2>&1
38
+ engine.processes.each do |process|
39
+ write_file process_conf, <<-UPSTART_CHILD
49
40
  UPSTART_CHILD
50
41
  end
51
42
 
@@ -55,12 +46,4 @@ exec #{process.command} >>/var/log/#{app}/#{process.name}.log 2>&1
55
46
  config.write
56
47
  end
57
48
 
58
- private ######################################################################
59
-
60
- def write_file(filename, contents)
61
- File.open(filename, "w") do |file|
62
- file.puts contents
63
- end
64
- end
65
-
66
49
  end
@@ -25,27 +25,6 @@ describe "Foreman::CLI" do
25
25
  end
26
26
  end
27
27
 
28
- describe "execute" do
29
- describe "with a non-existent Procfile" do
30
- it "prints an error" do
31
- mock_error(subject, "Procfile does not exist.") do
32
- dont_allow.instance_of(Foreman::Engine).start
33
- subject.execute("alpha")
34
- end
35
- end
36
- end
37
-
38
- describe "with a Procfile" do
39
- before(:each) { write_procfile }
40
-
41
- it "runs successfully" do
42
- dont_allow(subject).error
43
- mock.instance_of(Foreman::Engine).execute("alpha")
44
- subject.execute("alpha")
45
- end
46
- end
47
- end
48
-
49
28
  describe "export" do
50
29
  describe "with a non-existent Procfile" do
51
30
  it "prints an error" do
@@ -62,7 +41,7 @@ describe "Foreman::CLI" do
62
41
  describe "with an invalid formatter" do
63
42
  it "prints an error" do
64
43
  mock_error(subject, "Unknown export format: invalidformatter.") do
65
- subject.export("testapp", "Procfile", "invalidformatter")
44
+ subject.export("invalidformatter")
66
45
  end
67
46
  end
68
47
  end
@@ -72,33 +51,11 @@ describe "Foreman::CLI" do
72
51
 
73
52
  it "runs successfully" do
74
53
  dont_allow(subject).error
75
- subject.export("testapp")
76
- end
77
- end
78
- end
79
- end
80
-
81
- describe "scale" do
82
- describe "without an existing configuration" do
83
- it "displays an error" do
84
- mock_error(subject, "No such process: alpha.") do
85
- subject.scale("testapp", "alpha", "2")
86
- end
87
- end
88
- end
89
-
90
- describe "with an existing configuration" do
91
- before(:each) { write_foreman_config("testapp") }
92
-
93
- it "scales a process that exists" do
94
- mock.instance_of(Foreman::Configuration).scale("alpha", "2")
95
- subject.scale("testapp", "alpha", "2")
96
- end
97
-
98
- it "errors if a process that does not exist is specified" do
99
- mock_error(subject, "No such process: invalidprocess.") do
100
- dont_allow.instance_of(Foreman::Configuration).scale
101
- subject.scale("testapp", "invalidprocess", "2")
54
+ mock.instance_of(Foreman::Export::Upstart).export("/tmp/foo", {
55
+ :concurrency => nil,
56
+ :name => nil
57
+ })
58
+ subject.export("upstart", "/tmp/foo")
102
59
  end
103
60
  end
104
61
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreman
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 13
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 3
9
- - 2
10
- version: 0.3.2
8
+ - 4
9
+ - 1
10
+ version: 0.4.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - David Dollar
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-22 00:00:00 -04:00
18
+ date: 2010-06-23 00:00:00 -04:00
19
19
  default_executable: foreman
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -146,6 +146,7 @@ files:
146
146
  - lib/foreman/configuration.rb
147
147
  - lib/foreman/engine.rb
148
148
  - lib/foreman/export.rb
149
+ - lib/foreman/export/base.rb
149
150
  - lib/foreman/export/upstart.rb
150
151
  - lib/foreman/process.rb
151
152
  - spec/foreman/cli_spec.rb