necro 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NDcwZDQzZWIxNWM4Y2FhMjVmNzYyODE0MDdhMjk3Nzc1ZjMyNzFmOA==
5
+ data.tar.gz: !binary |-
6
+ ZjAyZDg0NmNjMTU0MmQ0Y2NjY2MwMGZjMTE3ZDhhZDQ5NDNlOGI0MA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ YmRkZGViN2M5NjYzYTAxYjU2YmIxMGVhYTAyN2VlNDg5MjEwMzBiNGY5NWNl
10
+ YWRhNDM1YTY4ZDc4OGUyMGVkZWEwMmQ4MjM2M2RhNDc2MmM4OGZmYWEwZGQ2
11
+ YWVmYjRkNjFhZDgxNDE0NmNjY2I0NjI2YjhhODc3ODBlZDA4Yjk=
12
+ data.tar.gz: !binary |-
13
+ YWE4ZjI0NDA2OTg4NTJkNDNkMmU5ZWUwNTg5ZjI3ODMwY2QzMGY3YzM1MmM0
14
+ OGNiZmE3YTU1NjUxODk2ZGMzNjljOWUwNzhlOWY0YzJhYTM4ZjZjZDM3ZTRh
15
+ ODg1Mzc2NmI1NGZiMDkzMWE5NzU4YmYwYjRiNzJlMTM5M2EzODM=
@@ -0,0 +1,5 @@
1
+ process.yml
2
+ necro.ini
3
+ config/
4
+ *.gem
5
+
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ script: bundle exec rake spec
6
+
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'pry'
6
+
@@ -0,0 +1,5 @@
1
+ desc "Run the tests"
2
+ task :spec do
3
+ spec_files = Dir["spec/**/*.rb"]
4
+ sh("bacon -I spec #{spec_files.join(" ")}")
5
+ end
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require "necro"
5
+ rescue LoadError
6
+ necro_lib_path = File.expand_path('../../lib', __FILE__)
7
+ $:.unshift(necro_lib_path)
8
+ require "necro"
9
+ end
10
+
11
+ Necro::Runner.run(ARGV)
12
+
13
+
@@ -0,0 +1,19 @@
1
+ $: << File.dirname(__FILE__) unless $:.include?(File.expand_path(File.dirname(__FILE__)))
2
+
3
+ module Necro
4
+ VERSION = "0.0.2"
5
+ end
6
+
7
+ require "colored"
8
+ require_relative "necro/runner"
9
+ require_relative "necro/command_listener"
10
+ require_relative "necro/errors"
11
+ require_relative "necro/config"
12
+ require_relative "necro/commander"
13
+ require_relative "necro/command_worker"
14
+ require_relative "necro/reactor"
15
+
16
+
17
+
18
+
19
+
@@ -0,0 +1,3 @@
1
+ require_relative "command_listener/server"
2
+ require_relative "command_listener/client"
3
+
@@ -0,0 +1,34 @@
1
+ module Necro
2
+ module CommandListener
3
+ class Client
4
+ attr_accessor :client_socket
5
+ def initialize(client_socket)
6
+ @client_socket = client_socket
7
+ end
8
+
9
+ def read_and_execute
10
+ command_info = client_socket.read()
11
+ if command_info && !command_info.empty?
12
+ worker_command, command_label, rest_args = command_info.strip.split(" ")
13
+ if worker_command && command_label
14
+ run_command(worker_command, command_label, rest_args)
15
+ end
16
+ end
17
+ client_socket.close()
18
+ end
19
+
20
+ def run_command(worker_command, command_label, rest_args = nil)
21
+ case worker_command
22
+ when 'add'
23
+ Necro::COMMANDER.add_command_by_label(command_label)
24
+ when 'remove'
25
+ Necro::COMMANDER.remove_command(command_label, rest_args)
26
+ when 'reload'
27
+ Necro::COMMANDER.reload_command(command_label)
28
+ else
29
+ $stdout.puts("\n Invalid command".red)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,31 @@
1
+ require "fileutils"
2
+
3
+ module Necro
4
+ module CommandListener
5
+ class Server
6
+ SOCKET_PATH = "/tmp/necro"
7
+ def initialize
8
+ @open_clients = []
9
+ clean_old_socket()
10
+ UNIXServer.open(SOCKET_PATH) do |client|
11
+ loop do
12
+ client_socket = client.accept
13
+ process_client(client_socket)
14
+ end
15
+ end
16
+ end
17
+
18
+ def clean_old_socket
19
+ if File.exists?(SOCKET_PATH)
20
+ FileUtils.rm(SOCKET_PATH, :force => true)
21
+ end
22
+ end
23
+
24
+ def process_client(client_socket)
25
+ client = Necro::CommandListener::Client.new(client_socket)
26
+ client.read_and_execute
27
+ end
28
+ end
29
+ end
30
+
31
+ end
@@ -0,0 +1,30 @@
1
+ module Necro
2
+ class CommandWorker
3
+ attr_accessor :command_label, :pipe_end, :pid, :color
4
+
5
+ def initialize(command_label, pipe_end, pid, color)
6
+ @command_label = command_label
7
+ @pipe_end = pipe_end
8
+ @pid = pid
9
+ @color = color
10
+ end
11
+
12
+ # Copied verbatim from Eventmachine code
13
+ def receive_data data
14
+ (@buf ||= '') << data
15
+
16
+ while @buf.slice!(/(.*?)\r?\n/)
17
+ receive_line($1)
18
+ end
19
+ end
20
+
21
+ def unbind
22
+ # $stdout.print(".")
23
+ end
24
+
25
+ # Print the lines received over the network
26
+ def receive_line(line)
27
+ $stdout.puts "#{@command_label.send(color)} : #{line}"
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,157 @@
1
+ require "io/console"
2
+ require 'pty'
3
+
4
+ module Necro
5
+ class Commander
6
+ MAX_PROCESS_COUNT = 10
7
+ LABEL_COLORS = ['green', 'yellow', 'blue', 'magenta', 'cyan']
8
+ attr_accessor :reactor, :workers, :thread_group, :open_pipes
9
+
10
+ def initialize
11
+ # mapping between open pipes and worker classes
12
+ @open_pipes = {}
13
+
14
+ # mapping between command label and worker classes
15
+ @workers = {}
16
+
17
+ @thread_group = ThreadGroup.new()
18
+ @worker_mutex = Mutex.new()
19
+ @reactor = Necro::Reactor.new
20
+ Thread.abort_on_exception = true
21
+ end
22
+
23
+ def start_manager
24
+ if !Necro::CONFIG.processes || Necro::CONFIG.processes.empty?
25
+ raise Necro::Errors::InvalidConfig.new("No processes configured in config file")
26
+ end
27
+ unix_server_thread = Thread.new { Necro::CommandListener::Server.new() }
28
+ thread_group.add(unix_server_thread)
29
+ Necro::CONFIG.processes.each { |process_info| add_command(process_info) }
30
+ reactor.start
31
+ end
32
+
33
+ def add_command(process_info)
34
+ m, s = PTY.open
35
+ s.raw! # disable newline conversion.
36
+
37
+ pid = run_command(process_info, s)
38
+
39
+ s.close()
40
+
41
+ selected_color = LABEL_COLORS.shift()
42
+ LABEL_COLORS.push(selected_color)
43
+ worker = Necro::CommandWorker.new(process_info.label, m, pid, selected_color)
44
+
45
+ add_worker(worker)
46
+ wait_on_pid(process_info.label,pid)
47
+ end
48
+
49
+ def add_command_by_label(command_label)
50
+ process_info = Necro::CONFIG.processes.detect {|pconfig|
51
+ pconfig.label == command_label
52
+ }
53
+ if process_info
54
+ add_command(process_info)
55
+ end
56
+ end
57
+
58
+ def reload_command(command_label)
59
+ remove_command(command_label)
60
+ add_command_by_label(command_label)
61
+ end
62
+
63
+ def remove_command(command_label, rest_args)
64
+ worker = workers[command_label]
65
+ signal_to_use = rest_args ? Array(rest_args).first : 'INT'
66
+
67
+ if worker
68
+ $stdout.puts("Removing #{command_label} with signal #{signal_to_use}".red)
69
+ process_kill(worker.pid, signal_to_use)
70
+ end
71
+ end
72
+
73
+ def get_worker_from_fd(fd)
74
+ open_pipes[fd.fileno]
75
+ end
76
+
77
+ def get_worker_from_label(label)
78
+ workers[label]
79
+ end
80
+
81
+ private
82
+ def process_kill(pid, signal_to_use)
83
+ if signal_to_use.to_i == 0
84
+ Process.kill(signal_to_use, pid)
85
+ else
86
+ Process.kill(signal_to_use.to_i, pid)
87
+ end
88
+ end
89
+
90
+ # Remove worker from all collections
91
+ def remove_worker(command_label)
92
+ @worker_mutex.synchronize do
93
+ worker = @workers[command_label]
94
+ if worker
95
+ @open_pipes.delete(worker.pipe_end.fileno)
96
+ @reactor.remove_from_monitoring(worker.pipe_end)
97
+ @workers.delete(command_label)
98
+ end
99
+ end
100
+ end
101
+
102
+ # add worker to global collections
103
+ def add_worker(worker)
104
+ @worker_mutex.synchronize do
105
+ @open_pipes[worker.pipe_end.fileno] = worker
106
+ @workers[worker.command_label] = worker
107
+ @reactor.add_to_monitor(worker.pipe_end)
108
+ end
109
+ end
110
+
111
+ def run_command(process_info, write_pipe)
112
+ if defined?(Bundler)
113
+ Bundler.with_clean_env do
114
+ spawn(process_info.cmd,
115
+ :chdir => process_info.dir || "/", :out => write_pipe, :err => write_pipe
116
+ )
117
+ end
118
+ else
119
+ spawn(process_info.cmd,
120
+ :chdir => process_info.dir || "/", :out => write_pipe, :err => write_pipe
121
+ )
122
+ end
123
+ end
124
+
125
+ def wait_on_pid(command_label,pid)
126
+ raise Necro::Errors::ToomanyOpenConnections if @thread_group.enclosed?
127
+ thread = Thread.new do
128
+ Process.wait(pid)
129
+ message = "Process with command #{command_label} exited with status #{$?.exitstatus}"
130
+ $stdout.puts("\n#{message}".red)
131
+ notify_user(message)
132
+ remove_worker(command_label)
133
+ end
134
+ @thread_group.add(thread)
135
+ end
136
+
137
+ def notify_user(message)
138
+ if defined?(Bundler)
139
+ Bundler.with_clean_env do
140
+ check_and_notify_with_terminal_notifier(message)
141
+ end
142
+ else
143
+ check_and_notify_with_terminal_notifier(message)
144
+ end
145
+ end
146
+
147
+ def check_and_notify_with_terminal_notifier(message)
148
+ return unless RUBY_PLATFORM.downcase.include?("darwin")
149
+
150
+ command_path = `which terminal-notifier`
151
+ if command_path && !command_path.empty?
152
+ system("terminal-notifier -message '#{message}' -title Necro")
153
+ end
154
+ end
155
+
156
+ end
157
+ end
@@ -0,0 +1,19 @@
1
+ require "yaml"
2
+ require 'iniparse'
3
+
4
+ module Necro
5
+ class Config
6
+ attr_accessor :processes
7
+ def initialize(filename)
8
+ @ini_content = File.read(filename)
9
+ @processes = process_ini(@ini_content)
10
+ end
11
+
12
+ def process_ini(ini_content)
13
+ document = IniParse.parse(ini_content)
14
+ document.map do |section|
15
+ OpenStruct.new(label: section.key, dir: section["directory"], cmd: section["command"])
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ module Necro
2
+ module Errors
3
+ class ToomanyOpenConnections < StandardError; end
4
+ class ProcessTerminated < StandardError
5
+ attr_accessor :message, :ready_fd
6
+ def initialize(ready_fd, message)
7
+ @ready_fd = ready_fd
8
+ @message = message
9
+ end
10
+ end
11
+
12
+ class InvalidConfig < StandardError; end
13
+ end
14
+ end
@@ -0,0 +1,61 @@
1
+ module Necro
2
+ class Reactor
3
+ attr_accessor :monitored_fds
4
+ def initialize
5
+ @monitored_fds = []
6
+ end
7
+
8
+ def add_to_monitor(fd)
9
+ @monitored_fds << fd
10
+ end
11
+
12
+ def remove_from_monitoring(fd)
13
+ @monitored_fds.delete(fd)
14
+ end
15
+
16
+ def start
17
+ loop do
18
+ watch_on_pipe
19
+ end
20
+ end
21
+
22
+ def watch_on_pipe
23
+ ready_read_fds,ready_write_fds,read_error_fds = select(monitored_fds,[],[],0.05)
24
+
25
+ if ready_read_fds && !ready_read_fds.empty?
26
+ handle_read_event(ready_read_fds)
27
+ end
28
+ end
29
+
30
+ def handle_read_event(ready_read_fds)
31
+ ready_fds = ready_read_fds.flatten.compact
32
+ ready_fds.each {|ready_fd| process_read(ready_fd) }
33
+ end
34
+
35
+ def process_read(ready_fd)
36
+ command_worker = Necro::COMMANDER.get_worker_from_fd(ready_fd)
37
+ begin
38
+ data = read_data(ready_fd)
39
+ command_worker.receive_data(data)
40
+ rescue Necro::Errors::ProcessTerminated
41
+ command_worker.unbind()
42
+ end
43
+ end
44
+
45
+ def read_data(ready_fd)
46
+ sock_data = []
47
+ begin
48
+ while(t_data = ready_fd.read_nonblock(64))
49
+ sock_data << t_data
50
+ end
51
+ rescue Errno::EAGAIN
52
+ return sock_data.join
53
+ rescue Errno::EWOULDBLOCK
54
+ return sock_data.join
55
+ rescue
56
+ raise Necro::Errors::ProcessTerminated.new(ready_fd,sock_data.join)
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,101 @@
1
+ require "slop"
2
+ require "ostruct"
3
+ require "socket"
4
+
5
+ module Necro
6
+ class Runner
7
+ def self.run(args)
8
+
9
+ selected_command = nil
10
+
11
+ Slop.parse(args, help: true) do
12
+ on :v, "Print the version" do
13
+ $stdout.puts Necro::VERSION
14
+ end
15
+
16
+ command 'start' do
17
+ banner "Usage : necro start config.ini \n Start Necro Process Manager"
18
+ run do |cmd_opts, cmd_args|
19
+ selected_command = OpenStruct.new(:command => 'start', :file => cmd_args.first)
20
+ end
21
+ end
22
+
23
+ command 'add' do
24
+ banner "Usage : necro add process_label \n Start the process with given process_label"
25
+ run do |cmd_opts, cmd_args|
26
+ selected_command = OpenStruct.new(:command => 'add', :command_key => cmd_args.first)
27
+ end
28
+ end
29
+
30
+ command 'remove' do
31
+ banner "Usage : necro remove process_label \n Stop the process with given label"
32
+ on :s, :signal=, "Signal to send for killing the process, default is SIGINT", as: String
33
+
34
+ run do |cmd_opts, cmd_args|
35
+ signal_to_use = cmd_opts.to_hash[:signal] || 'INT'
36
+ selected_command = OpenStruct.new(
37
+ :command => 'remove',
38
+ :command_key => cmd_args.first,
39
+ :signal => signal_to_use
40
+ )
41
+ end
42
+ end
43
+ end
44
+ run_command(selected_command)
45
+ end
46
+
47
+ def self.run_command(selected_command)
48
+ return unless selected_command
49
+ case selected_command.command
50
+ when 'start'
51
+ start_server(selected_command)
52
+ when 'add'
53
+ add_command(selected_command)
54
+ when 'remove'
55
+ remove_command(selected_command)
56
+ else
57
+ $stdout.puts "Invalid command"
58
+ end
59
+ end
60
+
61
+ def self.start_server(selected_command)
62
+ config = Necro::Config.new(selected_command.file)
63
+ Necro.const_set(:CONFIG, config)
64
+ warn_about_terminal_notifier()
65
+ commander = Necro::Commander.new()
66
+ Necro.const_set(:COMMANDER, commander)
67
+ commander.start_manager()
68
+ end
69
+
70
+ def self.add_command(selected_command)
71
+ socket = UNIXSocket.open(Necro::CommandListener::Server::SOCKET_PATH)
72
+ socket.puts("add #{selected_command.command_key}")
73
+ socket.flush()
74
+ socket.close()
75
+ end
76
+
77
+ def self.remove_command(selected_command)
78
+ socket = UNIXSocket.open(Necro::CommandListener::Server::SOCKET_PATH)
79
+ socket.puts("remove #{selected_command.command_key} #{selected_command.signal}")
80
+ socket.flush()
81
+ socket.close()
82
+ end
83
+
84
+ def self.refresh_command(selected_command)
85
+ socket = UNIXSocket.open(Necro::CommandListener::Server::SOCKET_PATH)
86
+ socket.puts("reload #{selected_command.command_key}")
87
+ socket.flush()
88
+ socket.close()
89
+ end
90
+
91
+ def self.warn_about_terminal_notifier
92
+ if RUBY_PLATFORM.downcase.include?("darwin")
93
+ command_path = `which terminal-notifier`
94
+ if !command_path || command_path.empty?
95
+ $stdout.puts("You can enable OSX notification for processes by installing terminal-notification gem".red)
96
+ end
97
+ end
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{necro}
5
+ s.version = "0.0.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Hemant Kumar"]
9
+ s.date = %q{2013-05-04}
10
+ s.description = %q{Something small for process management}
11
+ s.email = %q{hemant@codemancers.com}
12
+
13
+ s.files = `git ls-files`.split("\n")
14
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
15
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
+ s.require_paths = ["lib"]
17
+
18
+ s.homepage = %q{http://github.com/code-mancers/necro}
19
+ s.licenses = ["MIT"]
20
+ s.require_paths = ["lib"]
21
+ s.summary = %q{Something small for Process management}
22
+ s.add_dependency("slop")
23
+ s.add_dependency("iniparse")
24
+ s.add_dependency("colored")
25
+ s.add_development_dependency("bacon")
26
+ s.add_development_dependency("mocha")
27
+ s.add_development_dependency("mocha-on-bacon")
28
+ s.add_development_dependency("rake")
29
+ end
30
+
@@ -0,0 +1,13 @@
1
+ [rails]
2
+ directory = /home/gnufied/god_particle
3
+ command = zsh -c 'bundle exec rails s -p 5000'
4
+
5
+ [dj]
6
+ directory = /home/gnufied/god_particle
7
+ command = zsh -c 'bundle exec ruby script/delayed_job'
8
+
9
+
10
+ [events]
11
+ directory = /home/gnufied/god_particle
12
+ command = zsh -c 'bundle exec ruby script/event_server'
13
+
@@ -0,0 +1,47 @@
1
+ Necro is a gem for managing processes in development environment.
2
+
3
+ [![Build Status](https://travis-ci.org/code-mancers/necro.png)](https://travis-ci.org/code-mancers/necro)
4
+
5
+
6
+ ## Usage ##
7
+
8
+ You need to start by creating a `ini` file which will define processes you want to manage using necro. An example
9
+ `ini` file is included in the repo.
10
+
11
+ [rails]
12
+ directory = /home/gnufied/god_particle
13
+ command = zsh -c 'bundle exec rails s -p 5000'
14
+
15
+ [dj]
16
+ directory = /home/gnufied/god_particle
17
+ command = zsh -c 'bundle exec ruby script/delayed_job'
18
+
19
+
20
+ [events]
21
+ directory = /home/gnufied/god_particle
22
+ command = zsh -c 'bundle exec ruby script/event_server'
23
+
24
+ After that you can start process manager via:
25
+
26
+ ~> necro start necro.ini
27
+
28
+ Above command will start all your processes in one terminal with their stdout/stderr merged and labelled.
29
+
30
+ Now additionally you can control individual process by,
31
+
32
+ # Will try to stop running delayed job by sending SIGINT to the process
33
+ ~> necro remove dj
34
+
35
+ # If Process can't be killed by SIGINT send a custom signal
36
+ ~> necro remove dj -s 9
37
+
38
+ # add and start running
39
+ ~> necro add dj
40
+
41
+ You can also enable OSX notifications for crashed processes by installing `terminal-notification` gem. It is not a dependency, but can be useful if something crashed and you weren't paying attention.
42
+
43
+
44
+
45
+
46
+
47
+
@@ -0,0 +1,57 @@
1
+ require "spec_helper"
2
+
3
+ describe Necro::CommandListener::Client do
4
+ describe "add command" do
5
+ before do
6
+ @client_socket = mock()
7
+ @client = Necro::CommandListener::Client.new(@client_socket)
8
+ end
9
+
10
+ it "should run if read from socket" do
11
+ necro_commander.expects(:add_command_by_label).with("foo")
12
+ @client_socket.expects(:read).returns("add foo\n")
13
+ @client_socket.expects(:close)
14
+
15
+ @client.read_and_execute()
16
+ end
17
+ end
18
+
19
+ describe "remove command" do
20
+ before do
21
+ @client_socket = mock()
22
+ @client = Necro::CommandListener::Client.new(@client_socket)
23
+ end
24
+
25
+ it "with specific signal" do
26
+ necro_commander.expects(:remove_command).with("foo", "9")
27
+ @client_socket.expects(:read).returns("remove foo 9\n")
28
+ @client_socket.expects(:close)
29
+
30
+ @client.read_and_execute()
31
+ end
32
+
33
+ it "with default signal" do
34
+ necro_commander.expects(:remove_command).with("foo",nil)
35
+ @client_socket.expects(:read).returns("remove foo\n")
36
+ @client_socket.expects(:close)
37
+
38
+ @client.read_and_execute()
39
+ end
40
+ end
41
+
42
+ describe "invalid command" do
43
+ before do
44
+ @client_socket = mock()
45
+ @client = Necro::CommandListener::Client.new(@client_socket)
46
+ end
47
+
48
+ it "should print error if read from socket" do
49
+ necro_commander.expects(:remove_command).never()
50
+ necro_commander.expects(:add_command_by_label).never()
51
+ @client_socket.expects(:read).returns("eugh foo\n")
52
+ @client_socket.expects(:close)
53
+
54
+ @client.read_and_execute
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,4 @@
1
+ require "spec_helper"
2
+
3
+ describe "Command Worker" do
4
+ end
@@ -0,0 +1,92 @@
1
+ require "spec_helper"
2
+
3
+ describe "Necro::Commander" do
4
+
5
+ describe "With no processes configured" do
6
+ before do
7
+ @commander = Necro::Commander.new()
8
+ end
9
+
10
+ it "should throw error" do
11
+ necro_config.stubs(:processes).returns([])
12
+
13
+ lambda {
14
+ @commander.start_manager()
15
+ }.should.raise(Necro::Errors::InvalidConfig)
16
+ end
17
+ end
18
+
19
+ describe "#add_command_by_label" do
20
+ before do
21
+ @commander = Necro::Commander.new()
22
+ end
23
+
24
+ it "should find command by label and start it, if found" do
25
+ necro_config.stubs(:processes).returns([OpenStruct.new(:label => "resque", :cmd => "foo", :dir => "bar")])
26
+ @commander.expects(:add_command).returns(true)
27
+
28
+ @commander.add_command_by_label("resque")
29
+ end
30
+ end
31
+
32
+ describe "#remove_command" do
33
+ describe "when a worker is found" do
34
+ before do
35
+ @commander = Necro::Commander.new()
36
+ @commander.workers.expects(:[]).returns(OpenStruct.new(:pid => "bogus"))
37
+ end
38
+
39
+ describe "if a signal is specified" do
40
+ it "should use that signal to kill the worker" do
41
+ @commander.expects(:process_kill).with("bogus", "HUP").returns(true)
42
+ @commander.remove_command("resque", "HUP")
43
+ end
44
+ end
45
+
46
+ describe "if no signal is specified" do
47
+ it "should use INT signal" do
48
+ @commander.expects(:process_kill).with("bogus", "INT").returns(true)
49
+ @commander.remove_command("resque", nil)
50
+ end
51
+ end
52
+ end
53
+
54
+ describe "when no worker is found" do
55
+ before do
56
+ @commander = Necro::Commander.new()
57
+ @commander.workers.expects(:[]).returns(nil)
58
+ end
59
+
60
+ it "should not kill anything" do
61
+ @commander.expects(:process_kill).never()
62
+ @commander.remove_command("resque", "HUP")
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ describe "#add_command" do
69
+ before do
70
+ necro_config.stubs(:processes).returns([OpenStruct.new(:label => "sleep", :cmd => "sleep 4", :dir => ENV['HOME'])])
71
+ @commander = Necro::Commander.new()
72
+ end
73
+
74
+ it "should populate workers and open_pipes" do
75
+ @commander.reactor.expects(:start).returns(true)
76
+ @commander.start_manager()
77
+ @commander.open_pipes.should.not.be.empty
78
+ @commander.workers.should.not.be.empty
79
+
80
+ worker = @commander.workers['sleep']
81
+
82
+ worker.should.not.equal nil
83
+ worker.command_label.should.equal "sleep"
84
+ worker.color.should.equal "green"
85
+
86
+
87
+ pipe_end_worker = @commander.open_pipes[worker.pipe_end.fileno]
88
+ pipe_end_worker.should.not.equal nil
89
+ end
90
+ end
91
+
92
+ end
@@ -0,0 +1,29 @@
1
+ require "bacon"
2
+ require "mocha-on-bacon"
3
+
4
+ __LIB_PATH__ = File.join(File.dirname(__FILE__), "..")
5
+ $: << __LIB_PATH__
6
+
7
+ require "pry"
8
+ require "necro"
9
+
10
+
11
+ def necro_config
12
+ if Necro.const_defined?(:CONFIG)
13
+ Necro::CONFIG
14
+ else
15
+ Necro.const_set(:CONFIG, mock())
16
+ Necro::CONFIG
17
+ end
18
+ end
19
+
20
+ def necro_commander
21
+ if Necro.const_defined?(:COMMANDER)
22
+ Necro::COMMANDER
23
+ else
24
+ Necro.const_set(:COMMANDER, mock())
25
+ Necro::COMMANDER
26
+ end
27
+ end
28
+
29
+
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: necro
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Hemant Kumar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ version_requirements: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ! '>='
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ name: slop
22
+ requirement: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ version_requirements: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ name: iniparse
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :runtime
48
+ prerelease: false
49
+ name: colored
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ name: bacon
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ name: mocha
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :development
90
+ prerelease: false
91
+ name: mocha-on-bacon
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ name: rake
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Something small for process management
112
+ email: hemant@codemancers.com
113
+ executables:
114
+ - necro
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .travis.yml
120
+ - Gemfile
121
+ - Rakefile
122
+ - bin/necro
123
+ - lib/necro.rb
124
+ - lib/necro/command_listener.rb
125
+ - lib/necro/command_listener/client.rb
126
+ - lib/necro/command_listener/server.rb
127
+ - lib/necro/command_worker.rb
128
+ - lib/necro/commander.rb
129
+ - lib/necro/config.rb
130
+ - lib/necro/errors.rb
131
+ - lib/necro/reactor.rb
132
+ - lib/necro/runner.rb
133
+ - necro.gemspec
134
+ - necro.ini.example
135
+ - readme.md
136
+ - spec/necro/command_listener/client_spec.rb
137
+ - spec/necro/command_worker_spec.rb
138
+ - spec/necro/commander_spec.rb
139
+ - spec/spec_helper.rb
140
+ homepage: http://github.com/code-mancers/necro
141
+ licenses:
142
+ - MIT
143
+ metadata: {}
144
+ post_install_message:
145
+ rdoc_options: []
146
+ require_paths:
147
+ - lib
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ! '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 2.0.3
161
+ signing_key:
162
+ specification_version: 4
163
+ summary: Something small for Process management
164
+ test_files:
165
+ - spec/necro/command_listener/client_spec.rb
166
+ - spec/necro/command_worker_spec.rb
167
+ - spec/necro/commander_spec.rb
168
+ - spec/spec_helper.rb
169
+ has_rdoc: