necro 0.0.2

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.
@@ -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: