cumuli 0.1.0 → 0.2.0
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rvmrc +1 -1
- data/README.md +6 -0
- data/Rakefile +1 -14
- data/bin/cumuli +1 -1
- data/cumuli.gemspec +3 -2
- data/lib/cumuli/app/app.rb +92 -0
- data/lib/cumuli/app/foreman_process.rb +54 -0
- data/lib/cumuli/app/procs.rb +51 -0
- data/lib/cumuli/app/stdout_logger.rb +16 -0
- data/lib/cumuli/app.rb +5 -0
- data/lib/cumuli/cli/args.rb +13 -11
- data/lib/cumuli/cli/commander.rb +21 -19
- data/lib/cumuli/cli/terminal.rb +24 -22
- data/lib/cumuli/facade.rb +19 -0
- data/lib/cumuli/ps.rb +63 -0
- data/lib/cumuli/tasks/cumuli.rake +13 -0
- data/lib/cumuli/tasks.rb +1 -0
- data/lib/cumuli/version.rb +1 -1
- data/lib/cumuli/waiter.rb +23 -0
- data/lib/cumuli.rb +8 -0
- data/spec/app/app_spec.rb +35 -0
- data/spec/app/procs_spec.rb +21 -0
- data/spec/{args_spec.rb → cli/args_spec.rb} +2 -2
- data/spec/{commander_spec.rb → cli/commander_spec.rb} +3 -3
- data/spec/{terminal_spec.rb → cli/terminal_spec.rb} +4 -3
- data/spec/fixtures/app_set/Procfile +2 -1
- data/spec/fixtures/app_set/loopy/.rvmrc +1 -1
- data/spec/fixtures/app_set/{legacied → noded}/.rvmrc +1 -1
- data/spec/fixtures/app_set/noded/nodified.js +7 -0
- data/spec/support/log_helpers.rb +7 -0
- data/spec/support/mock_apps.rb +7 -0
- data/spec/waiter_spec.rb +48 -0
- metadata +35 -16
- data/spec/fixtures/app_set/legacied/half_loop.rb +0 -5
- data/spec/fixtures/app_set/legacied/quarter_loop.rb +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58e619931f7a11f25a4f514ec52b1a3e400c5b45
|
4
|
+
data.tar.gz: a2c6821ee16d9cef7f3cc7ce336244252977db7c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dcbf82ac48e8fc4ddf82e9242e1f2756f7fe8cfe015421a762be40f11f28b099acab29fa973f46545695496b337721f4041da2ffcd0488bf9513a87962606c82
|
7
|
+
data.tar.gz: 275079f9f57e77f16f32ae7509f25927a7324485cd895bc2469df00753c7493118cc100ff3452480ef591a48037e9ac6b24491eec47a5554807dca49c8dbbc3c
|
data/.gitignore
CHANGED
data/.rvmrc
CHANGED
data/README.md
CHANGED
@@ -69,6 +69,12 @@ framework.
|
|
69
69
|
|
70
70
|
app.stop # gracefully kills all the related processes
|
71
71
|
|
72
|
+
## Known Issues
|
73
|
+
|
74
|
+
If you start the Cumuli app and stop it the first time, it will successfully start and stop all processes. However, if you use the same Cumuli app class to
|
75
|
+
start and stop the processes again, it will fail to stop any of the
|
76
|
+
processes.
|
77
|
+
|
72
78
|
## Contributing
|
73
79
|
|
74
80
|
1. Fork it
|
data/Rakefile
CHANGED
@@ -1,15 +1,2 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
-
|
3
|
-
desc "kill the ruby stuff, debugging script"
|
4
|
-
task :kill_rubies do
|
5
|
-
ps_list = `ps axo pid,comm | grep ruby`
|
6
|
-
pids = ps_list.lines.map(&:split).map(&:first).map(&:to_i) - [Process.pid]
|
7
|
-
pids.each do |pid|
|
8
|
-
Process.kill("SIGINT", pid)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
task :ps do
|
13
|
-
ps = `ps axo pid,ppid,comm,args,user`
|
14
|
-
puts ps.lines.select{|l| l.match(/ruby|resque|foreman|rvm/)}
|
15
|
-
end
|
2
|
+
require "#{File.dirname(__FILE__)}/lib/cumuli/tasks.rb"
|
data/bin/cumuli
CHANGED
data/cumuli.gemspec
CHANGED
@@ -6,7 +6,7 @@ require 'cumuli/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "cumuli"
|
8
8
|
spec.version = Cumuli::VERSION
|
9
|
-
spec.authors = ["SocialChorus", "Kane Baccigalupi", "Fito von Zastrow"]
|
9
|
+
spec.authors = ["SocialChorus", "Kane Baccigalupi", "Fito von Zastrow", "Roy Pfaffman"]
|
10
10
|
spec.email = ["developers@socialchorus.com"]
|
11
11
|
spec.description = %q{Cumuli runs several foreman processes in different directories}
|
12
12
|
spec.summary = %q{Cumuli makes SOA on Heroku easier by delegating to Foreman in a Procfile}
|
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_dependency "foreman"
|
22
|
+
|
21
23
|
spec.add_development_dependency "rspec"
|
22
|
-
spec.add_development_dependency "foreman"
|
23
24
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
25
|
spec.add_development_dependency "rake"
|
25
26
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Cumuli
|
2
|
+
class App
|
3
|
+
DEFAULT_WAIT_TIME = 5 #120
|
4
|
+
SIGNALS = ['TERM', 'INT', 'HUP']
|
5
|
+
|
6
|
+
attr_accessor :env, :wait_time, :app_dir, :log_dir
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
@env = options[:env]
|
10
|
+
@wait_time = options[:wait_time]
|
11
|
+
@log_dir = options[:log_dir] || "#{Dir.pwd}/log"
|
12
|
+
@app_dir = options[:app_dir] || Dir.pwd
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
return if foreman_process.started?
|
17
|
+
|
18
|
+
Dir.chdir(app_dir) do
|
19
|
+
listen_for_signals
|
20
|
+
logger.print "Starting ..."
|
21
|
+
foreman_process.start
|
22
|
+
wait_for_apps if wait?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def logger
|
27
|
+
@logger = StdoutLogger.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def foreman_process
|
31
|
+
@termial ||= ForemanProcess.new(env, log_dir)
|
32
|
+
end
|
33
|
+
|
34
|
+
def apps
|
35
|
+
@apps ||= Procs.new(app_dir)
|
36
|
+
end
|
37
|
+
|
38
|
+
def pid
|
39
|
+
foreman_process.pid
|
40
|
+
end
|
41
|
+
|
42
|
+
def wait?
|
43
|
+
wait_time && wait_time > 0
|
44
|
+
end
|
45
|
+
|
46
|
+
def listen_for_signals
|
47
|
+
SIGNALS.each do |signal|
|
48
|
+
trap(signal) do
|
49
|
+
stop
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def app_ports
|
55
|
+
@apps.map.values.compact
|
56
|
+
end
|
57
|
+
|
58
|
+
def wait_for_apps
|
59
|
+
app_ports.each do |port|
|
60
|
+
wait_for_app(port)
|
61
|
+
end
|
62
|
+
|
63
|
+
logger.add_space
|
64
|
+
end
|
65
|
+
|
66
|
+
def wait_for_app(port)
|
67
|
+
logger.print "waiting for apps on port: #{port}"
|
68
|
+
|
69
|
+
timeout = wait_time || DEFAULT_WAIT_TIME
|
70
|
+
Waiter.new("Application on port #{port} unavailable after #{timeout} seconds")
|
71
|
+
.wait_until(timeout) { open_socket(port) }
|
72
|
+
logger.print "Application on #{port} available"
|
73
|
+
rescue Exception => e
|
74
|
+
stop
|
75
|
+
raise e
|
76
|
+
end
|
77
|
+
|
78
|
+
def open_socket(port)
|
79
|
+
TCPSocket.new('localhost', port)
|
80
|
+
true
|
81
|
+
rescue Errno::ECONNREFUSED
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
85
|
+
def stop
|
86
|
+
if foreman_process.started?
|
87
|
+
foreman_process.stop
|
88
|
+
@foreman_process = nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Cumuli
|
2
|
+
class App
|
3
|
+
class ForemanProcess
|
4
|
+
attr_reader :pid, :env, :log_dir
|
5
|
+
|
6
|
+
def initialize(env, log_dir)
|
7
|
+
@env = env
|
8
|
+
@log_dir = log_dir
|
9
|
+
ensure_log_dir_and_file
|
10
|
+
end
|
11
|
+
|
12
|
+
def ensure_log_dir_and_file
|
13
|
+
FileUtils.mkdir_p(log_dir)
|
14
|
+
FileUtils.touch(log_file)
|
15
|
+
end
|
16
|
+
|
17
|
+
def command
|
18
|
+
"HEROKU_ENV=#{env} RAILS_ENV=#{env} foreman start"
|
19
|
+
end
|
20
|
+
|
21
|
+
def log_file
|
22
|
+
"#{log_dir}/#{env}.log"
|
23
|
+
end
|
24
|
+
|
25
|
+
def start
|
26
|
+
@pid = fork do
|
27
|
+
listen_for_signals
|
28
|
+
$stdout.reopen(log_file)
|
29
|
+
exec(command)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def listen_for_signals
|
34
|
+
Cumuli::App::SIGNALS.each do |signal|
|
35
|
+
trap(signal) do
|
36
|
+
puts "#{self.class}: trapped signal #{signal} in #{Process.pid} ... stopping"
|
37
|
+
stop
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def started?
|
43
|
+
!!pid
|
44
|
+
end
|
45
|
+
|
46
|
+
def stop
|
47
|
+
return if @killed_it
|
48
|
+
Process.kill('INT', 0) # kills all processes in the group
|
49
|
+
@killed_it = true
|
50
|
+
@pid = nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Cumuli
|
2
|
+
class App
|
3
|
+
class Procs
|
4
|
+
attr_reader :port_map, :path, :apps
|
5
|
+
|
6
|
+
def initialize(path=nil)
|
7
|
+
@path = (path || Dir.pwd) + "/Procfile"
|
8
|
+
parse_procfile
|
9
|
+
end
|
10
|
+
|
11
|
+
def map
|
12
|
+
@map ||= apps.inject({}) do |hash, app|
|
13
|
+
hash[app.name] = app.port
|
14
|
+
hash
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def file
|
19
|
+
@file ||= File.read(path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def parse_procfile
|
23
|
+
@apps = file.lines.map do |line|
|
24
|
+
SubApp.new(line)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def names
|
29
|
+
map.keys
|
30
|
+
end
|
31
|
+
|
32
|
+
class SubApp
|
33
|
+
attr_reader :parts
|
34
|
+
|
35
|
+
def initialize(line)
|
36
|
+
@parts = line.split
|
37
|
+
end
|
38
|
+
|
39
|
+
def name
|
40
|
+
parts.first.gsub(':', '')
|
41
|
+
end
|
42
|
+
|
43
|
+
def port
|
44
|
+
if index = parts.find_index('-p')
|
45
|
+
parts[index + 1] && parts[index + 1].to_i
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/cumuli/app.rb
ADDED
data/lib/cumuli/cli/args.rb
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
module Cumuli
|
2
|
-
class
|
3
|
-
|
2
|
+
class CLI
|
3
|
+
class Args
|
4
|
+
attr_reader :argv, :dir
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
def initialize(argv)
|
7
|
+
@argv = argv
|
8
|
+
@dir ||= argv.shift
|
9
|
+
end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
def name
|
12
|
+
@name ||= dir.match(/([a-z_]+)$/i)[0]
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
def foreman_options
|
16
|
+
argv.join(' ')
|
17
|
+
end
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
data/lib/cumuli/cli/commander.rb
CHANGED
@@ -1,29 +1,31 @@
|
|
1
1
|
module Cumuli
|
2
|
-
class
|
3
|
-
|
2
|
+
class CLI
|
3
|
+
class Commander
|
4
|
+
attr_reader :args
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
def initialize(args)
|
7
|
+
@args = args
|
8
|
+
end
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
def build
|
11
|
+
"#{rvm_preface} foreman start #{args.foreman_options}"
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
def rvm_preface
|
15
|
+
"rvm ruby-#{rvm_version} exec" if rvmrc?
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
def rvmrc_descriptor
|
19
|
+
'./.rvmrc'
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
def rvmrc?
|
23
|
+
File.exist?(rvmrc_descriptor)
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
26
|
+
def rvm_version
|
27
|
+
File.read(rvmrc_descriptor).match(/(\d\.\d\.\d@\w+)/)[0]
|
28
|
+
end
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
data/lib/cumuli/cli/terminal.rb
CHANGED
@@ -1,34 +1,36 @@
|
|
1
1
|
module Cumuli
|
2
|
-
class
|
3
|
-
|
2
|
+
class CLI
|
3
|
+
class Terminal
|
4
|
+
VARS = ['GEM_HOME', 'GEM_PATH', 'RUBYOPT', 'RBENV_DIR']
|
4
5
|
|
5
|
-
|
6
|
+
attr_reader :command
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
8
|
+
def initialize(command)
|
9
|
+
@command = command
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
def bundled?
|
13
|
+
Object.const_defined?('Bundler')
|
14
|
+
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
def spawn
|
17
|
+
bundled? ? call_bundled : execute_command
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
def call_bundled
|
21
|
+
Bundler.with_clean_env do
|
22
|
+
clear_env
|
23
|
+
execute_command
|
24
|
+
end
|
23
25
|
end
|
24
|
-
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
def execute_command
|
28
|
+
exec(command)
|
29
|
+
end
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
def clear_env
|
32
|
+
VARS.each { |e| ENV.delete(e) }
|
33
|
+
end
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Cumuli
|
2
|
+
def self.start(env='test')
|
3
|
+
@app ||= App.new({
|
4
|
+
env: env,
|
5
|
+
log_dir: log_dir,
|
6
|
+
app_dir: app_dir,
|
7
|
+
wait_time: wait_time || App::DEFAULT_WAIT_TIME
|
8
|
+
})
|
9
|
+
@app.start
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.stop
|
13
|
+
@app.stop
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
attr_accessor :env, :log_dir, :app_dir, :wait_time
|
18
|
+
end
|
19
|
+
end
|
data/lib/cumuli/ps.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Cumuli
|
2
|
+
class PS
|
3
|
+
REGEX = /ruby|resque|foreman|rvm|node/
|
4
|
+
|
5
|
+
attr_reader :lines
|
6
|
+
|
7
|
+
def initialize(list=self.class.list)
|
8
|
+
@lines = list.lines
|
9
|
+
@lines.shift # to remove header line
|
10
|
+
end
|
11
|
+
|
12
|
+
def matching(regex = REGEX)
|
13
|
+
@matching ||= lines
|
14
|
+
.select{|l| l.match(regex)}
|
15
|
+
.select{|l| !l.match(/^#{Process.pid} /) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def kill
|
19
|
+
pids.each do |pid|
|
20
|
+
Process.kill("SIGINT", pid)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def pids(regex = REGEX)
|
25
|
+
matching(regex)
|
26
|
+
.map(&:split)
|
27
|
+
.map(&:first)
|
28
|
+
.map(&:to_i)
|
29
|
+
end
|
30
|
+
|
31
|
+
def ppid_hash
|
32
|
+
lines
|
33
|
+
.map(&:split)
|
34
|
+
.inject({}) do |hash, line_values|
|
35
|
+
pid = line_values[0].to_i
|
36
|
+
ppid = line_values[1].to_i
|
37
|
+
hash[ppid] ||= []
|
38
|
+
hash[ppid] << pid
|
39
|
+
hash
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def line(pid)
|
44
|
+
lines.detect{|l| l.match(/^#{pid} /)}
|
45
|
+
end
|
46
|
+
|
47
|
+
def tree(pid)
|
48
|
+
child_pids = ppid_hash[pid]
|
49
|
+
puts "#{pid} => #{child_pids}"
|
50
|
+
child_pids.map{|cpid| tree(cpid) } if child_pids
|
51
|
+
end
|
52
|
+
|
53
|
+
def report(pid)
|
54
|
+
tree(pid)
|
55
|
+
puts "\n"
|
56
|
+
puts matching
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.list
|
60
|
+
`ps axo pid,ppid,comm,args,user`
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
namespace :cumuli do
|
2
|
+
require_relative "../ps"
|
3
|
+
|
4
|
+
desc "kill the processes showing up in the nimbus:ps task"
|
5
|
+
task :kill do
|
6
|
+
Cumuli::PS.new.kill
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "look at processes likely related to cumuli"
|
10
|
+
task :ps do
|
11
|
+
puts Cumuli::PS.new.matching
|
12
|
+
end
|
13
|
+
end
|
data/lib/cumuli/tasks.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
load "#{File.dirname(__FILE__)}/tasks/cumuli.rake"
|
data/lib/cumuli/version.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Cumuli
|
2
|
+
class Waiter
|
3
|
+
TIMEOUT = 30
|
4
|
+
MESSAGE = "#wait_until did not resolve after #{TIMEOUT} seconds"
|
5
|
+
|
6
|
+
attr_reader :message
|
7
|
+
|
8
|
+
def initialize(message=MESSAGE)
|
9
|
+
@message = message
|
10
|
+
end
|
11
|
+
|
12
|
+
def wait_until(timeout=TIMEOUT, &block)
|
13
|
+
begin
|
14
|
+
Timeout.timeout(timeout) do
|
15
|
+
sleep(0.1) until value = block.call
|
16
|
+
value
|
17
|
+
end
|
18
|
+
rescue Timeout::Error
|
19
|
+
raise message
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/cumuli.rb
CHANGED
@@ -3,5 +3,13 @@ $stdout.sync = true
|
|
3
3
|
lib = File.expand_path(File.dirname(__FILE__))
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
|
6
|
+
require 'logger'
|
7
|
+
require 'timeout'
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
require "cumuli/facade"
|
11
|
+
require "cumuli/ps"
|
12
|
+
require "cumuli/waiter"
|
6
13
|
require "cumuli/cli"
|
14
|
+
require "cumuli/app"
|
7
15
|
require "cumuli/version"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cumuli::App do
|
4
|
+
describe '#start' do
|
5
|
+
let(:opts) {
|
6
|
+
{
|
7
|
+
env: 'test',
|
8
|
+
wait: false,
|
9
|
+
log_dir: log_dir,
|
10
|
+
app_dir: app_set_dir
|
11
|
+
}
|
12
|
+
}
|
13
|
+
let(:app) { Cumuli::App.new(opts) }
|
14
|
+
let(:logs) { File.readlines("#{log_dir}/test.log") }
|
15
|
+
|
16
|
+
before do
|
17
|
+
clear_logs
|
18
|
+
app.start
|
19
|
+
app.wait_for_app(2323)
|
20
|
+
end
|
21
|
+
|
22
|
+
after do
|
23
|
+
app.stop
|
24
|
+
end
|
25
|
+
|
26
|
+
it "launches subprocesses with the foreman command" do
|
27
|
+
ps_line = Cumuli::PS.new.matching.detect{|line| line.match(/foreman: master/) }
|
28
|
+
ps_line.should_not be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
it "redirects subprocess output to the logs" do
|
32
|
+
logs.detect {|line| line.match(/started with pid/) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cumuli::App::Procs do
|
4
|
+
let(:procs) { Cumuli::App::Procs.new(app_set_dir) }
|
5
|
+
|
6
|
+
it "#names includes all the app names listed in the Procfile" do
|
7
|
+
procs.names.should =~ [
|
8
|
+
'loopy', 'nodified'
|
9
|
+
]
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#map' do
|
13
|
+
it "maps names to ports" do
|
14
|
+
procs.map['nodified'].should == 2323
|
15
|
+
end
|
16
|
+
|
17
|
+
it "return a nil port when the app has no port" do
|
18
|
+
procs.map['loopy'].should == nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Cumuli::Args do
|
3
|
+
describe Cumuli::CLI::Args do
|
4
4
|
let(:argv) { ["../mactivator", "-p", "4000"] }
|
5
|
-
let(:args) { Cumuli::Args.new(argv) }
|
5
|
+
let(:args) { Cumuli::CLI::Args.new(argv) }
|
6
6
|
|
7
7
|
it "#dir will return the first element passed in" do
|
8
8
|
args.dir.should == "../mactivator"
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Cumuli::Commander do
|
3
|
+
describe Cumuli::CLI::Commander do
|
4
4
|
describe "#build" do
|
5
5
|
let(:args) { mock({foreman_options: 'foreman-options-here'}) }
|
6
|
-
let(:commander) { Cumuli::Commander.new(args) }
|
6
|
+
let(:commander) { Cumuli::CLI::Commander.new(args) }
|
7
7
|
|
8
8
|
context "application directory has no .rvmrc" do
|
9
9
|
before do
|
@@ -32,7 +32,7 @@ describe Cumuli::Commander do
|
|
32
32
|
|
33
33
|
describe "reading from the file system" do
|
34
34
|
it "prefaces with the right rvm information" do
|
35
|
-
Dir.chdir(File.dirname(__FILE__) + "
|
35
|
+
Dir.chdir(File.dirname(__FILE__) + "/../fixtures/app_set/loopy") do
|
36
36
|
commander.build.should include('rvm ruby-2.0.0')
|
37
37
|
end
|
38
38
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Cumuli::Terminal do
|
3
|
+
describe Cumuli::CLI::Terminal do
|
4
4
|
it "clears environmental variables" do
|
5
5
|
preserving_env do
|
6
6
|
ENV['GEM_HOME'] = 'somewhere-over-the-rainbow'
|
7
7
|
|
8
|
-
terminal = Cumuli::Terminal.new('$GEM_HOME')
|
8
|
+
terminal = Cumuli::CLI::Terminal.new('$GEM_HOME')
|
9
9
|
terminal.clear_env
|
10
10
|
|
11
11
|
ENV['GEM_HOME'].should == nil
|
@@ -15,9 +15,10 @@ describe Cumuli::Terminal do
|
|
15
15
|
it "spawns a new thread that runs the command" do
|
16
16
|
preserving_env do
|
17
17
|
pid = fork do
|
18
|
-
Cumuli::Terminal.new('STRAWBOSSED=true').spawn
|
18
|
+
Cumuli::CLI::Terminal.new('STRAWBOSSED=true').spawn
|
19
19
|
ENV['STRAWBOSSED'].should == true
|
20
20
|
end
|
21
|
+
|
21
22
|
Process.kill('INT', pid)
|
22
23
|
end
|
23
24
|
end
|
@@ -1 +1,2 @@
|
|
1
|
-
loopy:
|
1
|
+
loopy: ../../../bin/cumuli ./loopy
|
2
|
+
nodified: ../../../bin/cumuli ./noded -p 2323
|
data/spec/waiter_spec.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cumuli::Waiter do
|
4
|
+
let(:timeout) { 0.1 }
|
5
|
+
|
6
|
+
context "default message" do
|
7
|
+
let(:waiter) { Cumuli::Waiter.new }
|
8
|
+
|
9
|
+
it "will raise a default message if the block never resolves to a non-falsey value" do
|
10
|
+
expect {
|
11
|
+
waiter.wait_until(timeout){ false }
|
12
|
+
}.to raise_error(Cumuli::Waiter::MESSAGE)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "will return the truthy value that it gets from the block" do
|
16
|
+
waiter.wait_until{ 'truthy' }.should == 'truthy'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "initialization with a message" do
|
21
|
+
let(:message) { "Something went unexpected" }
|
22
|
+
let(:waiter) { Cumuli::Waiter.new(message) }
|
23
|
+
|
24
|
+
it "raises the message if the block does not resolve" do
|
25
|
+
expect {
|
26
|
+
waiter.wait_until(timeout){ false }
|
27
|
+
}.to raise_error(message)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "intitialization with an exception" do
|
32
|
+
let(:exception) { RuntimeError.new("Something went unexpected") }
|
33
|
+
let(:waiter) { Cumuli::Waiter.new(exception) }
|
34
|
+
|
35
|
+
it "raises the message if the block does not resolve" do
|
36
|
+
# Rspec is having issues with the normal expect block ...
|
37
|
+
# so let's do this the long way
|
38
|
+
raised = false
|
39
|
+
begin
|
40
|
+
waiter.wait_until(timeout){ false }
|
41
|
+
rescue Exception => e
|
42
|
+
raised = true
|
43
|
+
e.should == exception
|
44
|
+
end
|
45
|
+
raised.should == true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
metadata
CHANGED
@@ -1,25 +1,26 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cumuli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SocialChorus
|
8
8
|
- Kane Baccigalupi
|
9
9
|
- Fito von Zastrow
|
10
|
+
- Roy Pfaffman
|
10
11
|
autorequire:
|
11
12
|
bindir: bin
|
12
13
|
cert_chain: []
|
13
14
|
date: 2013-07-09 00:00:00.000000000 Z
|
14
15
|
dependencies:
|
15
16
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
17
|
+
name: foreman
|
17
18
|
requirement: !ruby/object:Gem::Requirement
|
18
19
|
requirements:
|
19
20
|
- - '>='
|
20
21
|
- !ruby/object:Gem::Version
|
21
22
|
version: '0'
|
22
|
-
type: :
|
23
|
+
type: :runtime
|
23
24
|
prerelease: false
|
24
25
|
version_requirements: !ruby/object:Gem::Requirement
|
25
26
|
requirements:
|
@@ -27,7 +28,7 @@ dependencies:
|
|
27
28
|
- !ruby/object:Gem::Version
|
28
29
|
version: '0'
|
29
30
|
- !ruby/object:Gem::Dependency
|
30
|
-
name:
|
31
|
+
name: rspec
|
31
32
|
requirement: !ruby/object:Gem::Requirement
|
32
33
|
requirements:
|
33
34
|
- - '>='
|
@@ -86,25 +87,39 @@ files:
|
|
86
87
|
- bin/cumuli
|
87
88
|
- cumuli.gemspec
|
88
89
|
- lib/cumuli.rb
|
90
|
+
- lib/cumuli/app.rb
|
91
|
+
- lib/cumuli/app/app.rb
|
92
|
+
- lib/cumuli/app/foreman_process.rb
|
93
|
+
- lib/cumuli/app/procs.rb
|
94
|
+
- lib/cumuli/app/stdout_logger.rb
|
89
95
|
- lib/cumuli/cli.rb
|
90
96
|
- lib/cumuli/cli/args.rb
|
91
97
|
- lib/cumuli/cli/cli.rb
|
92
98
|
- lib/cumuli/cli/commander.rb
|
93
99
|
- lib/cumuli/cli/terminal.rb
|
100
|
+
- lib/cumuli/facade.rb
|
101
|
+
- lib/cumuli/ps.rb
|
102
|
+
- lib/cumuli/tasks.rb
|
103
|
+
- lib/cumuli/tasks/cumuli.rake
|
94
104
|
- lib/cumuli/version.rb
|
95
|
-
-
|
96
|
-
- spec/
|
105
|
+
- lib/cumuli/waiter.rb
|
106
|
+
- spec/app/app_spec.rb
|
107
|
+
- spec/app/procs_spec.rb
|
108
|
+
- spec/cli/args_spec.rb
|
109
|
+
- spec/cli/commander_spec.rb
|
110
|
+
- spec/cli/terminal_spec.rb
|
97
111
|
- spec/fixtures/app_set/Procfile
|
98
|
-
- spec/fixtures/app_set/legacied/.rvmrc
|
99
|
-
- spec/fixtures/app_set/legacied/half_loop.rb
|
100
|
-
- spec/fixtures/app_set/legacied/quarter_loop.rb
|
101
112
|
- spec/fixtures/app_set/loopy/.rvmrc
|
102
113
|
- spec/fixtures/app_set/loopy/Procfile
|
103
114
|
- spec/fixtures/app_set/loopy/half_loop.rb
|
104
115
|
- spec/fixtures/app_set/loopy/loop.rb
|
116
|
+
- spec/fixtures/app_set/noded/.rvmrc
|
117
|
+
- spec/fixtures/app_set/noded/nodified.js
|
105
118
|
- spec/spec_helper.rb
|
106
119
|
- spec/support/functional_helpers.rb
|
107
|
-
- spec/
|
120
|
+
- spec/support/log_helpers.rb
|
121
|
+
- spec/support/mock_apps.rb
|
122
|
+
- spec/waiter_spec.rb
|
108
123
|
homepage: http://github.com/socialchorus/cumuli
|
109
124
|
licenses:
|
110
125
|
- MIT
|
@@ -130,16 +145,20 @@ signing_key:
|
|
130
145
|
specification_version: 4
|
131
146
|
summary: Cumuli makes SOA on Heroku easier by delegating to Foreman in a Procfile
|
132
147
|
test_files:
|
133
|
-
- spec/
|
134
|
-
- spec/
|
148
|
+
- spec/app/app_spec.rb
|
149
|
+
- spec/app/procs_spec.rb
|
150
|
+
- spec/cli/args_spec.rb
|
151
|
+
- spec/cli/commander_spec.rb
|
152
|
+
- spec/cli/terminal_spec.rb
|
135
153
|
- spec/fixtures/app_set/Procfile
|
136
|
-
- spec/fixtures/app_set/legacied/.rvmrc
|
137
|
-
- spec/fixtures/app_set/legacied/half_loop.rb
|
138
|
-
- spec/fixtures/app_set/legacied/quarter_loop.rb
|
139
154
|
- spec/fixtures/app_set/loopy/.rvmrc
|
140
155
|
- spec/fixtures/app_set/loopy/Procfile
|
141
156
|
- spec/fixtures/app_set/loopy/half_loop.rb
|
142
157
|
- spec/fixtures/app_set/loopy/loop.rb
|
158
|
+
- spec/fixtures/app_set/noded/.rvmrc
|
159
|
+
- spec/fixtures/app_set/noded/nodified.js
|
143
160
|
- spec/spec_helper.rb
|
144
161
|
- spec/support/functional_helpers.rb
|
145
|
-
- spec/
|
162
|
+
- spec/support/log_helpers.rb
|
163
|
+
- spec/support/mock_apps.rb
|
164
|
+
- spec/waiter_spec.rb
|