zeusd 0.2.5 → 0.3.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.
- data/README.md +6 -2
- data/bin/zeusd +11 -3
- data/lib/zeusd.rb +13 -1
- data/lib/zeusd/daemon.rb +31 -36
- data/lib/zeusd/{daemon_logging.rb → daemon_tracker.rb} +1 -4
- data/lib/zeusd/log.rb +28 -0
- data/lib/zeusd/log/last_line_array.rb +21 -0
- data/lib/zeusd/log/line.rb +25 -0
- data/lib/zeusd/log/line/base.rb +72 -0
- data/lib/zeusd/log/line/command.rb +26 -0
- data/lib/zeusd/log/line/error.rb +22 -0
- data/lib/zeusd/log/line/process.rb +26 -0
- data/lib/zeusd/log/line/update.rb +21 -0
- data/lib/zeusd/log/status.rb +99 -0
- data/lib/zeusd/log/tailer.rb +49 -0
- data/lib/zeusd/version.rb +1 -1
- data/spec/spec_helper.rb +7 -3
- data/spec/support/constants.rb +45 -0
- data/spec/support/helpers.rb +12 -0
- data/spec/zeusd/daemon_spec.rb +5 -5
- data/spec/zeusd/log/line/base_spec.rb +59 -0
- data/spec/zeusd/log/line/command_spec.rb +33 -0
- data/spec/zeusd/log/line/error_spec.rb +16 -0
- data/spec/zeusd/log/line/process_spec.rb +48 -0
- data/spec/zeusd/log/line/update_spec.rb +15 -0
- data/spec/zeusd/log/line_spec.rb +37 -0
- data/spec/zeusd/log/status_spec.rb +52 -0
- data/spec/zeusd/log/tailer_spec.rb +22 -0
- data/zeusd.gemspec +0 -1
- metadata +35 -22
- data/lib/zeusd/interpreter.rb +0 -93
data/README.md
CHANGED
@@ -2,11 +2,12 @@
|
|
2
2
|
|
3
3
|
Zeusd aims to provide greater control and easier scripting of the [Zeus Gem](https://github.com/burke/zeus) via daemonization.
|
4
4
|
|
5
|
-
##
|
5
|
+
## Features
|
6
6
|
|
7
7
|
* Run the [Zeus Gem](https://github.com/burke/zeus) as a daemon.
|
8
|
-
*
|
8
|
+
* Block execution until after Zeus has loaded using the `--block` flag.
|
9
9
|
* Manage multiple zeusd daemons using the `--cwd` flag.
|
10
|
+
* Show or follow the live Status Shart using the `zeusd status` command.
|
10
11
|
|
11
12
|
## Usage
|
12
13
|
|
@@ -23,6 +24,9 @@ $ zeusd restart [--cwd=/path/to/rails/root]
|
|
23
24
|
|
24
25
|
$ zeusd stop [--cwd=/path/to/rails/root]
|
25
26
|
[--verbose | -v]
|
27
|
+
|
28
|
+
$ zeusd status [--cwd=/path/to/rails/root]
|
29
|
+
[--follow | -f]
|
26
30
|
```
|
27
31
|
|
28
32
|
### Utility Commands
|
data/bin/zeusd
CHANGED
@@ -21,12 +21,20 @@ class ZeusdCLI < Thor
|
|
21
21
|
daemon.stop!
|
22
22
|
end
|
23
23
|
|
24
|
+
desc "status", "Get the current status."
|
25
|
+
method_option :follow, :type => :boolean, :aliases => :f
|
26
|
+
def status
|
27
|
+
trap("SIGINT") { exit! }
|
28
|
+
queue = daemon.status_queue
|
29
|
+
while output = queue.shift
|
30
|
+
puts output
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
24
34
|
desc "tail", "Tail the daemon's log."
|
25
35
|
method_option :follow, :type => :boolean, :aliases => :f
|
26
36
|
def tail
|
27
|
-
|
28
|
-
puts "\n\n[Zeusd] exec(#{cmd})\n\n"
|
29
|
-
exec(cmd)
|
37
|
+
exec "tail#{options[:follow] ? ' -f' : ''} -n 25 #{daemon.log_file.to_path}"
|
30
38
|
end
|
31
39
|
|
32
40
|
protected
|
data/lib/zeusd.rb
CHANGED
@@ -1,6 +1,18 @@
|
|
1
|
+
# Standard Lib
|
2
|
+
require 'thread'
|
3
|
+
require 'pathname'
|
4
|
+
require 'logger'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
# 3rd Party Gems
|
8
|
+
require 'childprocess'
|
9
|
+
require 'file-tail'
|
10
|
+
|
11
|
+
# Components
|
1
12
|
require 'zeusd/version'
|
2
13
|
require 'zeusd/process'
|
3
|
-
require 'zeusd/
|
14
|
+
require 'zeusd/log'
|
15
|
+
require 'zeusd/daemon_tracker'
|
4
16
|
require 'zeusd/daemon'
|
5
17
|
|
6
18
|
module Zeusd
|
data/lib/zeusd/daemon.rb
CHANGED
@@ -1,18 +1,10 @@
|
|
1
|
-
require 'thread'
|
2
|
-
require 'childprocess'
|
3
|
-
require 'pathname'
|
4
|
-
require 'file-tail'
|
5
|
-
|
6
|
-
require 'zeusd/daemon_logging'
|
7
|
-
|
8
1
|
module Zeusd
|
9
2
|
class Daemon
|
10
|
-
attr_reader :cwd, :verbose, :
|
3
|
+
attr_reader :cwd, :verbose, :child_process, :status
|
11
4
|
|
12
5
|
def initialize(options = {})
|
13
|
-
@cwd
|
14
|
-
@verbose
|
15
|
-
@interpreter = Interpreter.new
|
6
|
+
@cwd = Pathname.new(options[:cwd] || Dir.pwd).realpath
|
7
|
+
@verbose = !!options[:verbose]
|
16
8
|
end
|
17
9
|
|
18
10
|
def start!(options = {})
|
@@ -21,7 +13,7 @@ module Zeusd
|
|
21
13
|
@process = Zeusd::Process.find(child_process.pid)
|
22
14
|
|
23
15
|
if options.fetch(:block, false)
|
24
|
-
sleep(
|
16
|
+
sleep(3) until status.finished?
|
25
17
|
end
|
26
18
|
|
27
19
|
self
|
@@ -38,35 +30,46 @@ module Zeusd
|
|
38
30
|
process.kill!(:recursive => true, :signal => "KILL", :wait => true)
|
39
31
|
|
40
32
|
# Clean up socket file if stil exists
|
41
|
-
(
|
33
|
+
(zeus_socket.delete rescue nil) if zeus_socket.exist?
|
42
34
|
|
43
35
|
@process = nil
|
44
36
|
|
45
37
|
self
|
46
38
|
end
|
47
39
|
|
48
|
-
def
|
49
|
-
|
40
|
+
def status_queue
|
41
|
+
queue = Queue.new
|
42
|
+
status = Log::Status.new(File.new(zeus_log.to_path, 'r'))
|
43
|
+
|
44
|
+
queue << status.to_cli
|
45
|
+
status.on_update {|x| queue << x.to_cli }
|
46
|
+
status.record!
|
47
|
+
|
48
|
+
queue
|
50
49
|
end
|
51
50
|
|
52
51
|
def process
|
53
52
|
@process ||= Process.all.find {|p| !!p.command[/zeus.*start$/] && p.cwd == cwd }
|
54
53
|
end
|
55
54
|
|
56
|
-
def
|
57
|
-
|
55
|
+
def finished?
|
56
|
+
status.finished?
|
58
57
|
end
|
59
58
|
|
60
|
-
def
|
59
|
+
def zeus_socket
|
61
60
|
cwd.join('.zeus.sock')
|
62
61
|
end
|
63
62
|
|
64
|
-
def
|
63
|
+
def zeus_log
|
65
64
|
cwd.join('log', 'zeus.log').tap do |path|
|
66
65
|
FileUtils.touch(path.to_path)
|
67
66
|
end
|
68
67
|
end
|
69
68
|
|
69
|
+
def verbose?
|
70
|
+
!!verbose
|
71
|
+
end
|
72
|
+
|
70
73
|
def to_json(*args)
|
71
74
|
{
|
72
75
|
:class => self.class.name,
|
@@ -79,9 +82,9 @@ module Zeusd
|
|
79
82
|
protected
|
80
83
|
|
81
84
|
def start_child_process!
|
82
|
-
|
83
|
-
|
84
|
-
std_file = File.new(
|
85
|
+
# Truncate and cast to File instance
|
86
|
+
zeus_log.open("w") {}
|
87
|
+
std_file = File.new(zeus_log.to_path, 'w+')
|
85
88
|
std_file.sync = true
|
86
89
|
|
87
90
|
# Prep and Start child process
|
@@ -93,25 +96,17 @@ module Zeusd
|
|
93
96
|
@child_process.detach = true
|
94
97
|
@child_process.start
|
95
98
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
log.extend(File::Tail)
|
100
|
-
log.interval = 0.1
|
101
|
-
log.backward(100)
|
102
|
-
log.tail do |line|
|
103
|
-
interpreter.translate(line)
|
104
|
-
puts line if verbose
|
105
|
-
end
|
106
|
-
end
|
99
|
+
@status = Log::Status.new(std_file)
|
100
|
+
@status.on_update do |status, line|
|
101
|
+
puts status.to_cli if verbose?
|
107
102
|
end
|
103
|
+
@status.record!
|
108
104
|
|
109
|
-
|
110
|
-
sleep 0.1 until interpreter.commands.any?
|
105
|
+
sleep 0.1 until @status.started?
|
111
106
|
|
112
107
|
@child_process
|
113
108
|
end
|
114
109
|
|
115
|
-
include Zeusd::
|
110
|
+
include Zeusd::DaemonTracker
|
116
111
|
end
|
117
112
|
end
|
data/lib/zeusd/log.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'zeusd/log/last_line_array'
|
2
|
+
require 'zeusd/log/line'
|
3
|
+
require 'zeusd/log/status'
|
4
|
+
require 'zeusd/log/tailer'
|
5
|
+
|
6
|
+
module Zeusd
|
7
|
+
module Log
|
8
|
+
|
9
|
+
COLOR_TO_ANSI = {
|
10
|
+
:red => "\e[31m",
|
11
|
+
:green => "\e[32m",
|
12
|
+
:yellow => "\e[33m",
|
13
|
+
:blue => "\e[34m",
|
14
|
+
:magenta => "\e[35m"
|
15
|
+
}
|
16
|
+
|
17
|
+
STATUS_TO_COLOR = {
|
18
|
+
:ready => :green,
|
19
|
+
:crashed => :red,
|
20
|
+
:waiting => :yellow,
|
21
|
+
:running => :blue,
|
22
|
+
:connecting => :magenta
|
23
|
+
}
|
24
|
+
|
25
|
+
STATUS_TO_ANSI = Hash[STATUS_TO_COLOR.map{|status, color| [status, COLOR_TO_ANSI[color]]}]
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module Zeusd
|
3
|
+
class LastLineArray
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
def_delegators *[:to_a].concat(Array.instance_methods.select{|x| x[/^[a-z]+.*?[^!]{1}$/]} - instance_methods(true))
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
@hash = Hash[args.zip(args)]
|
10
|
+
end
|
11
|
+
|
12
|
+
def <<(line)
|
13
|
+
@hash[line.id] = line
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_a
|
17
|
+
@hash.values
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'zeusd/log/line/base'
|
4
|
+
require 'zeusd/log/line/command'
|
5
|
+
require 'zeusd/log/line/process'
|
6
|
+
require 'zeusd/log/line/update'
|
7
|
+
require 'zeusd/log/line/error'
|
8
|
+
|
9
|
+
module Zeusd
|
10
|
+
module Log
|
11
|
+
module Line
|
12
|
+
|
13
|
+
class << self
|
14
|
+
|
15
|
+
def create(line)
|
16
|
+
[Command, Process, Update, Error, Base].each do |klass|
|
17
|
+
return klass.new(line) if klass.matches_line?(line)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Zeusd
|
3
|
+
module Log
|
4
|
+
module Line
|
5
|
+
|
6
|
+
class Base < String
|
7
|
+
|
8
|
+
def self.matches_line?(line)
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def status_substring
|
13
|
+
ansi_color
|
14
|
+
end
|
15
|
+
|
16
|
+
def id
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def status?(status)
|
21
|
+
ansi_color_of(status_substring) == Log::STATUS_TO_ANSI[status]
|
22
|
+
end
|
23
|
+
|
24
|
+
def ready?
|
25
|
+
status? :ready
|
26
|
+
end
|
27
|
+
|
28
|
+
def crashed?
|
29
|
+
status? :crashed
|
30
|
+
end
|
31
|
+
|
32
|
+
def waiting?
|
33
|
+
status? :waiting
|
34
|
+
end
|
35
|
+
|
36
|
+
def running?
|
37
|
+
status? :running
|
38
|
+
end
|
39
|
+
|
40
|
+
def connecting?
|
41
|
+
status? :connecting
|
42
|
+
end
|
43
|
+
|
44
|
+
def loading?
|
45
|
+
[:waiting, :connecting, :running].any? {|x| status? x}
|
46
|
+
end
|
47
|
+
|
48
|
+
def done?
|
49
|
+
[:crashed, :ready].any? {|x| status? x}
|
50
|
+
end
|
51
|
+
|
52
|
+
def ansi_color_of(substring)
|
53
|
+
if stop_point = index(substring) + (substring.length - 1)
|
54
|
+
if color_start = rindex(/\e/, stop_point)
|
55
|
+
color_end = index('m', color_start)
|
56
|
+
self[color_start..color_end]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def ansi_color
|
62
|
+
if self[0] == "\e" && !self.index('m').nil?
|
63
|
+
self[0..self.index('m')]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Zeusd
|
3
|
+
module Log
|
4
|
+
module Line
|
5
|
+
|
6
|
+
class Command < Base
|
7
|
+
def self.matches_line?(line)
|
8
|
+
line[/^\e.*?zeus\s(.*?)(\s|\e)/]
|
9
|
+
end
|
10
|
+
|
11
|
+
def id
|
12
|
+
name
|
13
|
+
end
|
14
|
+
|
15
|
+
def name
|
16
|
+
self[/^\e.*?zeus\s(.*?)(\s|\e)/, 1]
|
17
|
+
end
|
18
|
+
|
19
|
+
def status_substring
|
20
|
+
name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Zeusd
|
3
|
+
module Log
|
4
|
+
module Line
|
5
|
+
|
6
|
+
class Error < Base
|
7
|
+
|
8
|
+
def self.matches_line?(line)
|
9
|
+
!!line[0..5]["\e[31m"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def id
|
13
|
+
message
|
14
|
+
end
|
15
|
+
|
16
|
+
alias_method :message, :to_s
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Zeusd
|
3
|
+
module Log
|
4
|
+
module Line
|
5
|
+
|
6
|
+
class Process < Base
|
7
|
+
def self.matches_line?(line)
|
8
|
+
!!line[/(boot|─)/]
|
9
|
+
end
|
10
|
+
|
11
|
+
def id
|
12
|
+
name
|
13
|
+
end
|
14
|
+
|
15
|
+
def name
|
16
|
+
self[/(\e\[[0-9]{1,2}m)([a-z_]+)/, 2]
|
17
|
+
end
|
18
|
+
|
19
|
+
def status_substring
|
20
|
+
name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Zeusd
|
3
|
+
module Log
|
4
|
+
module Line
|
5
|
+
|
6
|
+
class Update < Base
|
7
|
+
|
8
|
+
attr_reader :time
|
9
|
+
|
10
|
+
def self.matches_line?(line)
|
11
|
+
!!line[/\s=====$/]
|
12
|
+
end
|
13
|
+
|
14
|
+
def time
|
15
|
+
@time ||= Time.parse(self[/UPDATED\s(.*?)\s=/, 1])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Zeusd
|
2
|
+
module Log
|
3
|
+
|
4
|
+
class Status
|
5
|
+
|
6
|
+
attr_reader :file, :tailer, :updated_at, :line_print_count
|
7
|
+
attr_reader :errors
|
8
|
+
attr_reader :commands
|
9
|
+
attr_reader :processes
|
10
|
+
|
11
|
+
def initialize(file)
|
12
|
+
@line_print_count = 0
|
13
|
+
@file = File.new(file)
|
14
|
+
@updated_at = Time.now
|
15
|
+
@errors = LastLineArray.new
|
16
|
+
@commands = LastLineArray.new
|
17
|
+
@processes = LastLineArray.new
|
18
|
+
@tailer = Tailer.new(file)
|
19
|
+
|
20
|
+
file.each {|line| process(line)} unless file.size.zero?
|
21
|
+
end
|
22
|
+
|
23
|
+
def record!
|
24
|
+
tailer.on_update {|line| process(line)}
|
25
|
+
tailer.start!
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def pause!
|
30
|
+
tailer.stop!
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def paused?
|
35
|
+
!tailer.following?
|
36
|
+
end
|
37
|
+
|
38
|
+
def recording?
|
39
|
+
tailer.following?
|
40
|
+
end
|
41
|
+
|
42
|
+
def process(line)
|
43
|
+
line = Line.create(line)
|
44
|
+
case line
|
45
|
+
when Line::Command then @commands << line
|
46
|
+
when Line::Process then @processes << line
|
47
|
+
when Line::Error then @errors << line
|
48
|
+
end
|
49
|
+
@updated_at = Time.now
|
50
|
+
on_update.call(self, line) if on_update
|
51
|
+
end
|
52
|
+
|
53
|
+
def on_update(&block)
|
54
|
+
@on_update = block if block_given?
|
55
|
+
@on_update
|
56
|
+
end
|
57
|
+
|
58
|
+
def started?
|
59
|
+
commands.any?
|
60
|
+
end
|
61
|
+
|
62
|
+
def finished?
|
63
|
+
return true if errors.any?
|
64
|
+
return true if [commands, processes].map(&:to_a).flatten.all?(&:done?)
|
65
|
+
false
|
66
|
+
end
|
67
|
+
|
68
|
+
def empty?
|
69
|
+
[errors, commands, processes].all?(&:empty?)
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_cli
|
73
|
+
output = [
|
74
|
+
"\e[36mZeusd Status\e[0m - Updated: #{updated_at.to_s}\e[K\e[0m\n",
|
75
|
+
"\e[K\e[0m\n",
|
76
|
+
"Legend: \e[32m[ready] \e[31m[crashed] \e[34m[running] \e[35m[connecting] \e[33m[waiting]\e[K\e[0m\n",
|
77
|
+
"\e[K\e[0m\n",
|
78
|
+
"\e[4mProcess Tree\e[K\e[0m\n",
|
79
|
+
[processes.map(&:to_s)],
|
80
|
+
"\e[K\e[0m\n",
|
81
|
+
"\e[4mCommands\e[K\e[0m\n",
|
82
|
+
[commands.map(&:to_s)],
|
83
|
+
].tap do |x|
|
84
|
+
if errors.any?
|
85
|
+
x << "\e[K"
|
86
|
+
x << "\e[4mErrors\e[K\e[0m\n"
|
87
|
+
x << errors.map(&:to_s)
|
88
|
+
end
|
89
|
+
end.flatten
|
90
|
+
if line_print_count > 0
|
91
|
+
output = output.unshift("\e[#{line_print_count}A\e[K\e[0m\n")
|
92
|
+
end
|
93
|
+
@line_print_count = output.length
|
94
|
+
output
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Zeusd
|
2
|
+
module Log
|
3
|
+
class Tailer
|
4
|
+
attr_reader :file, :lines
|
5
|
+
|
6
|
+
def initialize(file)
|
7
|
+
@file = file
|
8
|
+
@lines = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_update(&block)
|
12
|
+
@on_update = block if block_given?
|
13
|
+
@on_update
|
14
|
+
end
|
15
|
+
|
16
|
+
def following?
|
17
|
+
!!@thread
|
18
|
+
end
|
19
|
+
|
20
|
+
def restart!
|
21
|
+
stop!.start!
|
22
|
+
end
|
23
|
+
|
24
|
+
def start!
|
25
|
+
@thread = Thread.new do
|
26
|
+
File.open(file) do |log|
|
27
|
+
log.extend(File::Tail)
|
28
|
+
log.interval = 0.1
|
29
|
+
log.backward(0)
|
30
|
+
log.tail do |line|
|
31
|
+
@lines << line
|
32
|
+
on_update.call(line) if on_update
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def stop!
|
40
|
+
if @thread
|
41
|
+
@thread.terminate
|
42
|
+
@thread = nil
|
43
|
+
end
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/zeusd/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require 'simplecov'
|
2
3
|
SimpleCov.start
|
3
4
|
|
4
|
-
require '
|
5
|
+
require 'tempfile'
|
5
6
|
|
6
|
-
|
7
|
+
require File.expand_path('../support/helpers.rb', __FILE__)
|
8
|
+
require File.expand_path('../support/constants.rb', __FILE__)
|
7
9
|
|
8
|
-
|
10
|
+
require 'zeusd'
|
9
11
|
|
12
|
+
RSpec.configure do |c|
|
13
|
+
c.include Helpers
|
10
14
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
DUMMY_APP_PATH = File.expand_path('../../dummy', __FILE__)
|
4
|
+
|
5
|
+
DUMMY_ZEUS_LOG_PATH = File.expand_path('../dummy_zeus.log', __FILE__)
|
6
|
+
|
7
|
+
ZEUS_LOG_LINES = {
|
8
|
+
:commands => [
|
9
|
+
"\e[32mzeus destroy (alias: d)\e[K\e[0m\n",
|
10
|
+
"\e[32mzeus server (alias: s)\e[K\e[0m\n",
|
11
|
+
"\e[32mzeus console (alias: c)\e[K\e[0m\n",
|
12
|
+
"\e[32mzeus dbconsole\e[K\e[0m\n",
|
13
|
+
"\e[32mzeus runner (alias: r)\e[K\e[0m\n",
|
14
|
+
"\e[32mzeus generate (alias: g)\e[K\e[0m\n",
|
15
|
+
"\e[32mzeus rake\e[K\e[0m\n",
|
16
|
+
"\e[32mzeus test (alias: rspec, testrb)\e[K\e[0m\n"
|
17
|
+
],
|
18
|
+
:processes => [
|
19
|
+
"\e[32mboot\e[K\e[0m\n",
|
20
|
+
"\e[33m└── \e[32mdefault_bundle\e[K\e[0m\n",
|
21
|
+
"\e[33m \e[33m├── \e[32mdevelopment_environment\e[K\e[0m\n",
|
22
|
+
"\e[33m \e[33m│ \e[33m└── \e[32mprerake\e[K\e[0m\n",
|
23
|
+
"\e[33m \e[33m└── \e[32mtest_environment\e[K\e[0m\n",
|
24
|
+
"\e[33m \e[33m \e[33m└── \e[32mtest_helper\e[K\e[0m\n"
|
25
|
+
],
|
26
|
+
:all => [
|
27
|
+
"\e[4m\e[32m[ready] \e[31m[crashed] \e[34m[running] \e[35m[connecting] \e[33m[waiting]\e[K\e[0m\n",
|
28
|
+
"\e[32mboot\e[K\e[0m\n",
|
29
|
+
"\e[33m└── \e[32mdefault_bundle\e[K\e[0m\n",
|
30
|
+
"\e[33m \e[33m├── \e[32mdevelopment_environment\e[K\e[0m\n",
|
31
|
+
"\e[33m \e[33m│ \e[33m└── \e[32mprerake\e[K\e[0m\n",
|
32
|
+
"\e[33m \e[33m└── \e[32mtest_environment\e[K\e[0m\n",
|
33
|
+
"\e[33m \e[33m \e[33m└── \e[32mtest_helper\e[K\e[0m\n",
|
34
|
+
"\e[K\n",
|
35
|
+
"\e[4mAvailable Commands: \e[33m[waiting] \e[31m[crashed] \e[32m[ready]\e[K\e[0m\n",
|
36
|
+
"\e[32mzeus destroy (alias: d)\e[K\e[0m\n",
|
37
|
+
"\e[32mzeus server (alias: s)\e[K\e[0m\n",
|
38
|
+
"\e[32mzeus console (alias: c)\e[K\e[0m\n",
|
39
|
+
"\e[32mzeus dbconsole\e[K\e[0m\n",
|
40
|
+
"\e[32mzeus runner (alias: r)\e[K\e[0m\n",
|
41
|
+
"\e[32mzeus generate (alias: g)\e[K\e[0m\n",
|
42
|
+
"\e[32mzeus rake\e[K\e[0m\n",
|
43
|
+
"\e[32mzeus test (alias: rspec, testrb)\e[K\e[0m\n"
|
44
|
+
]
|
45
|
+
}
|
data/spec/zeusd/daemon_spec.rb
CHANGED
@@ -5,27 +5,27 @@ describe Zeusd::Daemon do
|
|
5
5
|
after(:each) { daemon.stop! }
|
6
6
|
|
7
7
|
describe ".start!" do
|
8
|
-
subject { daemon.start!
|
8
|
+
subject { daemon.start! }
|
9
9
|
it { should be daemon }
|
10
|
-
it { should_not
|
10
|
+
it { should_not be_finished }
|
11
11
|
|
12
12
|
describe ":block option" do
|
13
13
|
subject { daemon.start!(:block => true) }
|
14
|
-
it { should
|
14
|
+
it { should be_finished }
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
describe ".stop!" do
|
19
19
|
subject { daemon.start!.stop! }
|
20
20
|
it { should be daemon }
|
21
|
-
it { should_not
|
21
|
+
it { should_not be_finished }
|
22
22
|
end
|
23
23
|
|
24
24
|
describe ".restart!" do
|
25
25
|
subject { daemon }
|
26
26
|
context "when daemon is already running" do
|
27
27
|
before { subject.start!.restart!(:block => true) }
|
28
|
-
it { should
|
28
|
+
it { should be_finished }
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'zeusd'
|
5
|
+
|
6
|
+
|
7
|
+
describe Zeusd::Log::Line::Base do
|
8
|
+
|
9
|
+
class ExampleLine < Zeusd::Log::Line::Base
|
10
|
+
def status_substring
|
11
|
+
"example"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
RED = "\e[31m"
|
16
|
+
GREEN = "\e[32m"
|
17
|
+
YELLOW = "\e[33m"
|
18
|
+
|
19
|
+
let(:line) { Zeusd::Log::Line::Base.new("#{RED}This line starts with red but then#{GREEN}changes to green after a bit") }
|
20
|
+
|
21
|
+
|
22
|
+
describe ".ansi_color" do
|
23
|
+
subject { line.ansi_color }
|
24
|
+
it { should eq RED }
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
describe ".ansi_color_of" do
|
29
|
+
context "far from setting of color" do
|
30
|
+
subject { line.ansi_color_of("bit") }
|
31
|
+
it { should eq GREEN }
|
32
|
+
end
|
33
|
+
|
34
|
+
context "near setting of color" do
|
35
|
+
subject { line.ansi_color_of("This") }
|
36
|
+
it { should eq RED }
|
37
|
+
end
|
38
|
+
|
39
|
+
context "color itself" do
|
40
|
+
subject { line.ansi_color_of(GREEN) }
|
41
|
+
it { should eq GREEN }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe ".status_substring" do
|
46
|
+
subject { line }
|
47
|
+
it { should be_crashed }
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "checking status of substring" do
|
51
|
+
Zeusd::Log::STATUS_TO_ANSI.each do |status, color|
|
52
|
+
context "when in a #{status} state" do
|
53
|
+
subject { ExampleLine.new "#{color}zeus example\e[K\e[0m" }
|
54
|
+
it { should send("be_#{status}") }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'zeusd'
|
5
|
+
|
6
|
+
describe Zeusd::Log::Line::Command do
|
7
|
+
|
8
|
+
NAME = "dbconsole"
|
9
|
+
let(:crashed) { Zeusd::Log::Line::Command.new "\e[31mzeus #{NAME}\e[K\e[0m" }
|
10
|
+
let(:ready) { Zeusd::Log::Line::Command.new "\e[32mzeus #{NAME}\e[K\e[0m" }
|
11
|
+
let(:waiting) { Zeusd::Log::Line::Command.new "\e[33mzeus #{NAME}\e[K\e[0m" }
|
12
|
+
|
13
|
+
describe ".name" do
|
14
|
+
subject { ready.name }
|
15
|
+
it { should eq NAME }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "checking status of command" do
|
19
|
+
context ".ready?" do
|
20
|
+
subject { ready }
|
21
|
+
it { should be_ready }
|
22
|
+
end
|
23
|
+
context ".waiting?" do
|
24
|
+
subject { waiting }
|
25
|
+
it { should be_waiting }
|
26
|
+
end
|
27
|
+
context ".crashed?" do
|
28
|
+
subject { crashed }
|
29
|
+
it { should be_crashed }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'zeusd'
|
5
|
+
|
6
|
+
describe Zeusd::Log::Line::Error do
|
7
|
+
|
8
|
+
ERROR_STRING = "\e[31This would be a typical \e[33mZeus\e[31 error to see.\e[0m"
|
9
|
+
|
10
|
+
let(:error) { Zeusd::Log::Line::Error.new ERROR_STRING }
|
11
|
+
describe ".message" do
|
12
|
+
subject { error.message }
|
13
|
+
it { should eq ERROR_STRING }
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'zeusd'
|
5
|
+
|
6
|
+
describe Zeusd::Log::Line::Process do
|
7
|
+
|
8
|
+
let(:crashed) { Zeusd::Log::Line::Process.new "\e[31mboot\e[K\e[0m" }
|
9
|
+
let(:ready) { Zeusd::Log::Line::Process.new "\e[32m└── \e[32mdefault_bundle\e[K\e[0m" }
|
10
|
+
let(:waiting) { Zeusd::Log::Line::Process.new "\e[33m \e[33m├── \e[33mdevelopment_environment\e[K\e[0m" }
|
11
|
+
let(:running) { Zeusd::Log::Line::Process.new "\e[34m \e[34m└── \e[34mtest_environment\e[K\e[0m" }
|
12
|
+
let(:connecting) { Zeusd::Log::Line::Process.new "\e[35m \e[35m \e[35m└── \e[35mtest_helper\e[K\e[0m" }
|
13
|
+
|
14
|
+
describe ".name" do
|
15
|
+
context "when deeply nested" do
|
16
|
+
subject { waiting.name }
|
17
|
+
it { should eq "development_environment" }
|
18
|
+
end
|
19
|
+
context "when boot" do
|
20
|
+
subject { crashed.name }
|
21
|
+
it { should eq "boot" }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "checking status of command" do
|
26
|
+
context ".ready?" do
|
27
|
+
subject { ready }
|
28
|
+
it { should be_ready }
|
29
|
+
end
|
30
|
+
context ".waiting?" do
|
31
|
+
subject { waiting }
|
32
|
+
it { should be_waiting }
|
33
|
+
end
|
34
|
+
context ".crashed?" do
|
35
|
+
subject { crashed }
|
36
|
+
it { should be_crashed }
|
37
|
+
end
|
38
|
+
context ".running?" do
|
39
|
+
subject { running }
|
40
|
+
it { should be_running }
|
41
|
+
end
|
42
|
+
context ".connecting?" do
|
43
|
+
subject { connecting }
|
44
|
+
it { should be_connecting }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'zeusd'
|
5
|
+
|
6
|
+
describe Zeusd::Log::Line::Update do
|
7
|
+
|
8
|
+
let(:update) { Zeusd::Log::Line::Update.new "==== UPDATED Sat Mar 1 00:07:24 EST 2014 =====" }
|
9
|
+
|
10
|
+
describe ".time" do
|
11
|
+
subject { update.time }
|
12
|
+
it { should eq Time.parse("1/3/2014 00:07:24 EST") }
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'zeusd'
|
5
|
+
|
6
|
+
describe Zeusd::Log::Line do
|
7
|
+
|
8
|
+
describe "determining line type" do
|
9
|
+
|
10
|
+
context "update" do
|
11
|
+
subject { Zeusd::Log::Line.create("==== UPDATED Sat Mar 1 00:07:24 EST 2014 =====") }
|
12
|
+
it { should be_a Zeusd::Log::Line::Update }
|
13
|
+
end
|
14
|
+
|
15
|
+
context "error" do
|
16
|
+
subject { Zeusd::Log::Line.create("\e[31mThis would be a typical zeus error") }
|
17
|
+
it { should be_a Zeusd::Log::Line::Error }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "process" do
|
21
|
+
subject { Zeusd::Log::Line.create("\e[33m \e[33m└── \e[33mtest_environment\e[K\e[0m") }
|
22
|
+
it { should be_a Zeusd::Log::Line::Process }
|
23
|
+
end
|
24
|
+
|
25
|
+
context "command" do
|
26
|
+
subject { Zeusd::Log::Line.create("\e[33mzeus generate (alias: g)\e[K\e[0m") }
|
27
|
+
it { should be_a Zeusd::Log::Line::Command }
|
28
|
+
end
|
29
|
+
|
30
|
+
context "unknown" do
|
31
|
+
subject { Zeusd::Log::Line.create("!#!@$$@#%$#%%!$43154}") }
|
32
|
+
it { should be_a Zeusd::Log::Line::Base }
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'zeusd'
|
5
|
+
|
6
|
+
describe Zeusd::Log::Status do
|
7
|
+
|
8
|
+
let(:log_file) { Tempfile.new("Zeusd_Log_Status").tap {|f| f.sync = true} }
|
9
|
+
let(:status) { Zeusd::Log::Status.new(log_file) }
|
10
|
+
|
11
|
+
describe "after initialization" do
|
12
|
+
subject { status }
|
13
|
+
it { should be_paused }
|
14
|
+
its(:tailer) { should be_a Zeusd::Log::Tailer }
|
15
|
+
its(:errors) { should be_empty }
|
16
|
+
|
17
|
+
context "when the log file is empty" do
|
18
|
+
its(:commands) { should be_empty }
|
19
|
+
its(:processes) { should be_empty }
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when log file has data" do
|
23
|
+
before(:each) { file_write(log_file, ZEUS_LOG_LINES[:all].join, :rewind => true) }
|
24
|
+
its(:commands) { should_not be_empty }
|
25
|
+
its(:processes) { should_not be_empty }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe ".process" do
|
30
|
+
subject do
|
31
|
+
lines.each {|line| status.process(line)}
|
32
|
+
status
|
33
|
+
end
|
34
|
+
|
35
|
+
context "command" do
|
36
|
+
let(:lines) { ZEUS_LOG_LINES[:commands] }
|
37
|
+
its(:commands) { should have(lines.length).items }
|
38
|
+
end
|
39
|
+
|
40
|
+
context "process" do
|
41
|
+
let(:lines) { ZEUS_LOG_LINES[:processes] }
|
42
|
+
its(:processes) { have(lines.length).items }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "recording" do
|
47
|
+
subject { status.record! }
|
48
|
+
it { should be status }
|
49
|
+
it { should be_recording }
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
require 'zeusd'
|
5
|
+
|
6
|
+
describe Zeusd::Log::Tailer do
|
7
|
+
|
8
|
+
let(:log_file) { Tempfile.new("Zeusd_Log_Tailer") }
|
9
|
+
let(:tailer) { Zeusd::Log::Tailer.new(log_file) }
|
10
|
+
|
11
|
+
describe "after initialization" do
|
12
|
+
subject { tailer }
|
13
|
+
it { should_not be_following }
|
14
|
+
it { should respond_to :start! }
|
15
|
+
it { should respond_to :stop! }
|
16
|
+
it { should respond_to :restart! }
|
17
|
+
it { should respond_to :following? }
|
18
|
+
it { should respond_to :lines }
|
19
|
+
it { should respond_to :file }
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/zeusd.gemspec
CHANGED
@@ -21,7 +21,6 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_runtime_dependency "thor" , "~> 0.18.1"
|
22
22
|
spec.add_runtime_dependency "childprocess" , ">= 0.5.1"
|
23
23
|
spec.add_runtime_dependency "file-tail" , "~> 1.0.12"
|
24
|
-
spec.add_runtime_dependency "hooks" , "~> 0.3.3"
|
25
24
|
spec.add_runtime_dependency "zeus" , "~> 0.13.3"
|
26
25
|
|
27
26
|
spec.add_development_dependency "bundler", "~> 1.3"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zeusd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-03-
|
12
|
+
date: 2014-03-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
@@ -59,22 +59,6 @@ dependencies:
|
|
59
59
|
- - ~>
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 1.0.12
|
62
|
-
- !ruby/object:Gem::Dependency
|
63
|
-
name: hooks
|
64
|
-
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
|
-
requirements:
|
67
|
-
- - ~>
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: 0.3.3
|
70
|
-
type: :runtime
|
71
|
-
prerelease: false
|
72
|
-
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
|
-
requirements:
|
75
|
-
- - ~>
|
76
|
-
- !ruby/object:Gem::Version
|
77
|
-
version: 0.3.3
|
78
62
|
- !ruby/object:Gem::Dependency
|
79
63
|
name: zeus
|
80
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -158,8 +142,17 @@ files:
|
|
158
142
|
- bin/zeusd
|
159
143
|
- lib/zeusd.rb
|
160
144
|
- lib/zeusd/daemon.rb
|
161
|
-
- lib/zeusd/
|
162
|
-
- lib/zeusd/
|
145
|
+
- lib/zeusd/daemon_tracker.rb
|
146
|
+
- lib/zeusd/log.rb
|
147
|
+
- lib/zeusd/log/last_line_array.rb
|
148
|
+
- lib/zeusd/log/line.rb
|
149
|
+
- lib/zeusd/log/line/base.rb
|
150
|
+
- lib/zeusd/log/line/command.rb
|
151
|
+
- lib/zeusd/log/line/error.rb
|
152
|
+
- lib/zeusd/log/line/process.rb
|
153
|
+
- lib/zeusd/log/line/update.rb
|
154
|
+
- lib/zeusd/log/status.rb
|
155
|
+
- lib/zeusd/log/tailer.rb
|
163
156
|
- lib/zeusd/process.rb
|
164
157
|
- lib/zeusd/version.rb
|
165
158
|
- spec/dummy/.gitignore
|
@@ -213,8 +206,18 @@ files:
|
|
213
206
|
- spec/dummy/vendor/plugins/.gitkeep
|
214
207
|
- spec/dummy/zeus.json
|
215
208
|
- spec/spec_helper.rb
|
209
|
+
- spec/support/constants.rb
|
216
210
|
- spec/support/dummy_process.rb
|
211
|
+
- spec/support/helpers.rb
|
217
212
|
- spec/zeusd/daemon_spec.rb
|
213
|
+
- spec/zeusd/log/line/base_spec.rb
|
214
|
+
- spec/zeusd/log/line/command_spec.rb
|
215
|
+
- spec/zeusd/log/line/error_spec.rb
|
216
|
+
- spec/zeusd/log/line/process_spec.rb
|
217
|
+
- spec/zeusd/log/line/update_spec.rb
|
218
|
+
- spec/zeusd/log/line_spec.rb
|
219
|
+
- spec/zeusd/log/status_spec.rb
|
220
|
+
- spec/zeusd/log/tailer_spec.rb
|
218
221
|
- spec/zeusd/process_spec.rb
|
219
222
|
- zeusd.gemspec
|
220
223
|
homepage: https://github.com/veloper/zeusd
|
@@ -232,7 +235,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
232
235
|
version: '0'
|
233
236
|
segments:
|
234
237
|
- 0
|
235
|
-
hash: -
|
238
|
+
hash: -4218968737058463992
|
236
239
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
237
240
|
none: false
|
238
241
|
requirements:
|
@@ -241,7 +244,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
241
244
|
version: '0'
|
242
245
|
segments:
|
243
246
|
- 0
|
244
|
-
hash: -
|
247
|
+
hash: -4218968737058463992
|
245
248
|
requirements: []
|
246
249
|
rubyforge_project:
|
247
250
|
rubygems_version: 1.8.25
|
@@ -300,6 +303,16 @@ test_files:
|
|
300
303
|
- spec/dummy/vendor/plugins/.gitkeep
|
301
304
|
- spec/dummy/zeus.json
|
302
305
|
- spec/spec_helper.rb
|
306
|
+
- spec/support/constants.rb
|
303
307
|
- spec/support/dummy_process.rb
|
308
|
+
- spec/support/helpers.rb
|
304
309
|
- spec/zeusd/daemon_spec.rb
|
310
|
+
- spec/zeusd/log/line/base_spec.rb
|
311
|
+
- spec/zeusd/log/line/command_spec.rb
|
312
|
+
- spec/zeusd/log/line/error_spec.rb
|
313
|
+
- spec/zeusd/log/line/process_spec.rb
|
314
|
+
- spec/zeusd/log/line/update_spec.rb
|
315
|
+
- spec/zeusd/log/line_spec.rb
|
316
|
+
- spec/zeusd/log/status_spec.rb
|
317
|
+
- spec/zeusd/log/tailer_spec.rb
|
305
318
|
- spec/zeusd/process_spec.rb
|
data/lib/zeusd/interpreter.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
module Zeusd
|
2
|
-
class Interpreter
|
3
|
-
STATES = %w[ready crashed running connecting waiting]
|
4
|
-
|
5
|
-
attr_reader :lines
|
6
|
-
attr_reader :state_colors, :commands, :errors
|
7
|
-
attr_reader :last_status
|
8
|
-
|
9
|
-
def initialize(*args)
|
10
|
-
@state_colors = Hash[STATES.zip([nil]*STATES.length)]
|
11
|
-
@commands = {}
|
12
|
-
@errors = []
|
13
|
-
@lines = []
|
14
|
-
end
|
15
|
-
|
16
|
-
def translate(zeus_output)
|
17
|
-
zeus_output.split("\n").map{|x| Line.new(x) }.each do |line|
|
18
|
-
# State Colors
|
19
|
-
if @state_colors.values.any?(&:nil?) && line.state_legend?
|
20
|
-
STATES.each do |state|
|
21
|
-
state_colors[state] = line.color_of(state)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# Errors
|
26
|
-
@errors << line if line.color == state_colors["crashed"]
|
27
|
-
|
28
|
-
# Commands
|
29
|
-
@commands[line.command[:name]] = state_colors.invert[line.command[:color]] if line.command?
|
30
|
-
|
31
|
-
# Add Line
|
32
|
-
@lines << line
|
33
|
-
end
|
34
|
-
|
35
|
-
# Garbage Collection
|
36
|
-
if @lines.length > 100
|
37
|
-
@lines = @lines.last(100)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def complete?
|
42
|
-
return false if errors.any?
|
43
|
-
return true if commands.all? {|command, status| %[crashed ready].include?(status)}
|
44
|
-
false
|
45
|
-
end
|
46
|
-
|
47
|
-
def last_update
|
48
|
-
@lines[@lines.rindex(&:update?)..-1].join("\n").to_s
|
49
|
-
end
|
50
|
-
|
51
|
-
class Line < String
|
52
|
-
|
53
|
-
def update?
|
54
|
-
self =~ /\=\=\=\=$/
|
55
|
-
end
|
56
|
-
|
57
|
-
def command?
|
58
|
-
!!command
|
59
|
-
end
|
60
|
-
|
61
|
-
def command
|
62
|
-
if @match ||= self.match(/^(\e.*?)zeus\s(.*?)(\s|\e)/)
|
63
|
-
{ :name => @match[2], :color => @match[1] }
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def state_legend?
|
68
|
-
STATES.all?{|state| !!self[state]}
|
69
|
-
end
|
70
|
-
|
71
|
-
def color_of(substring)
|
72
|
-
if stop_point = index(substring) + substring.length
|
73
|
-
if color_start = rindex(/\e/, stop_point)
|
74
|
-
color_end = index('m', color_start)
|
75
|
-
self[color_start..color_end]
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def color
|
81
|
-
if self[0] == "\e" && !self.index('m').nil?
|
82
|
-
self[0..self.index('m')]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def color?
|
87
|
-
!!color
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
end
|
93
|
-
end
|