zeus 0.0.1 → 0.1.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 +40 -9
- data/bin/zeus +13 -0
- data/examples/rails.rb +78 -0
- data/lib/zeus/client.rb +78 -0
- data/lib/zeus/process.rb +20 -0
- data/lib/zeus/server.rb +298 -0
- data/lib/zeus/version.rb +1 -1
- data/zeus.gemspec +4 -2
- metadata +23 -6
data/README.md
CHANGED
@@ -1,24 +1,55 @@
|
|
1
1
|
# Zeus
|
2
2
|
|
3
|
-
|
3
|
+
## What?
|
4
4
|
|
5
|
-
|
5
|
+
Zeus preloads your app so that your normal development tasks such as `console`, `server`, `generate`, and tests are faster.
|
6
|
+
|
7
|
+
## Why?
|
8
|
+
|
9
|
+
Because waiting 25 seconds sucks, but waiting 0.4 seconds doesn't.
|
6
10
|
|
7
|
-
|
11
|
+
## When?
|
8
12
|
|
9
|
-
|
13
|
+
Not yet. Zeus is nowhere near production-ready yet. Use only if you really like broken things.
|
10
14
|
|
11
|
-
|
15
|
+
## Ugly bits
|
16
|
+
|
17
|
+
* Probably crashes a lot
|
18
|
+
* Creates a bunch of sockets
|
19
|
+
* Uses an obscene number of file descriptors
|
20
|
+
|
21
|
+
## Installation
|
12
22
|
|
13
|
-
|
23
|
+
Install the gem.
|
14
24
|
|
15
|
-
|
25
|
+
gem install zeus
|
16
26
|
|
17
|
-
|
27
|
+
Copy `examples/rails.rb` to `{your app}/.zeus.rb`
|
18
28
|
|
19
29
|
## Usage
|
20
30
|
|
21
|
-
|
31
|
+
Start the server:
|
32
|
+
|
33
|
+
zeus start
|
34
|
+
|
35
|
+
Run some commands:
|
36
|
+
|
37
|
+
zeus console
|
38
|
+
zeus server
|
39
|
+
zeus testrb -Itest -I. test/unit/omg_test.rb
|
40
|
+
zeus generate model omg
|
41
|
+
zeus rake -T
|
42
|
+
zeus runner omg.rb
|
43
|
+
|
44
|
+
## TODO (roughly prioritized)
|
45
|
+
|
46
|
+
* Kill process when files are detected to have changed
|
47
|
+
* Handle client/server without requiring a unix socket for each acceptor (1 shared socket)
|
48
|
+
* Make the code less terrible
|
49
|
+
* Figure out how to run full test suites without multiple env loads
|
50
|
+
* Support other frameworks?
|
51
|
+
* Use fsevents instead of kqueue to reduce the obscene number of file descriptors.
|
52
|
+
* Support epoll on linux
|
22
53
|
|
23
54
|
## Contributing
|
24
55
|
|
data/bin/zeus
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
zeus = File.expand_path("../../lib/", __FILE__)
|
4
|
+
$:.unshift(zeus) unless $:.include?(zeus)
|
5
|
+
|
6
|
+
if ARGV[0] == "start"
|
7
|
+
require 'zeus/server'
|
8
|
+
require './.zeus.rb'
|
9
|
+
Zeus::Server.run
|
10
|
+
else
|
11
|
+
require 'zeus/client'
|
12
|
+
Zeus::Client.run
|
13
|
+
end
|
data/examples/rails.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'socket'
|
2
|
+
|
3
|
+
Zeus::Server.define! do
|
4
|
+
stage :boot do
|
5
|
+
|
6
|
+
action do
|
7
|
+
ENV_PATH = File.expand_path('../config/environment', __FILE__)
|
8
|
+
BOOT_PATH = File.expand_path('../config/boot', __FILE__)
|
9
|
+
APP_PATH = File.expand_path('../config/application', __FILE__)
|
10
|
+
ROOT_PATH = File.expand_path('..', __FILE__)
|
11
|
+
|
12
|
+
require BOOT_PATH
|
13
|
+
require 'rails/all'
|
14
|
+
end
|
15
|
+
|
16
|
+
stage :default_bundle do
|
17
|
+
action { Bundler.require(:default) }
|
18
|
+
|
19
|
+
stage :dev do
|
20
|
+
action do
|
21
|
+
Bundler.require(:development)
|
22
|
+
ENV['RAILS_ENV'] = "development"
|
23
|
+
require APP_PATH
|
24
|
+
Rails.application.require_environment!
|
25
|
+
end
|
26
|
+
|
27
|
+
acceptor :generate, ".zeus.dev_generate.sock" do
|
28
|
+
require 'rails/commands/generate'
|
29
|
+
end
|
30
|
+
acceptor :runner, ".zeus.dev_runner.sock" do
|
31
|
+
require 'rails/commands/runner'
|
32
|
+
end
|
33
|
+
acceptor :console, ".zeus.dev_console.sock" do
|
34
|
+
require 'rails/commands/console'
|
35
|
+
Rails::Console.start(Rails.application)
|
36
|
+
end
|
37
|
+
|
38
|
+
acceptor :server, ".zeus.dev_server.sock" do
|
39
|
+
require 'rails/commands/server'
|
40
|
+
server = Rails::Server.new
|
41
|
+
Dir.chdir(Rails.application.root)
|
42
|
+
server.start
|
43
|
+
end
|
44
|
+
|
45
|
+
stage :prerake do
|
46
|
+
action do
|
47
|
+
require 'rake'
|
48
|
+
load 'Rakefile'
|
49
|
+
end
|
50
|
+
|
51
|
+
acceptor :rake, ".zeus.dev_rake.sock" do
|
52
|
+
Rake.application.run
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
stage :test do
|
59
|
+
action do
|
60
|
+
ENV['RAILS_ENV'] = "test"
|
61
|
+
Bundler.require(:test)
|
62
|
+
require APP_PATH
|
63
|
+
Rails.application.require_environment!
|
64
|
+
end
|
65
|
+
|
66
|
+
acceptor :testrb, ".zeus.test_testrb.sock" do
|
67
|
+
forkpoint testrb: acceptor(".zeus.test_testrb.sock") {
|
68
|
+
(r = Test::Unit::AutoRunner.new(true)).process_args(ARGV) or
|
69
|
+
abort r.options.banner + " tests..."
|
70
|
+
exit r.run
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/zeus/client.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require "io/console"
|
2
|
+
require "json"
|
3
|
+
require "pty"
|
4
|
+
require "socket"
|
5
|
+
|
6
|
+
module Zeus
|
7
|
+
class Client
|
8
|
+
|
9
|
+
SIGNALS = {
|
10
|
+
"\x03" => "TERM",
|
11
|
+
"\x1C" => "QUIT"
|
12
|
+
}
|
13
|
+
SIGNAL_REGEX = Regexp.union(SIGNALS.keys)
|
14
|
+
|
15
|
+
def self.maybe_raw(&b)
|
16
|
+
if $stdout.tty?
|
17
|
+
$stdout.raw(&b)
|
18
|
+
else
|
19
|
+
b.call
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.run
|
24
|
+
maybe_raw do
|
25
|
+
PTY.open do |master, slave|
|
26
|
+
$stdout.tty? and master.winsize = $stdout.winsize
|
27
|
+
winch, winch_ = IO.pipe
|
28
|
+
trap("WINCH") { winch_ << "\0" }
|
29
|
+
|
30
|
+
case ARGV.shift
|
31
|
+
when 'testrb', 't'
|
32
|
+
socket = UNIXSocket.new(".zeus.test_testrb.sock")
|
33
|
+
when 'console', 'c'
|
34
|
+
socket = UNIXSocket.new(".zeus.dev_console.sock")
|
35
|
+
when 'server', 's'
|
36
|
+
socket = UNIXSocket.new(".zeus.dev_server.sock")
|
37
|
+
when 'rake'
|
38
|
+
socket = UNIXSocket.new(".zeus.dev_rake.sock")
|
39
|
+
when 'runner', 'r'
|
40
|
+
socket = UNIXSocket.new(".zeus.dev_runner.sock")
|
41
|
+
when 'generate', 'g'
|
42
|
+
socket = UNIXSocket.new(".zeus.dev_generate.sock")
|
43
|
+
end
|
44
|
+
socket.send_io(slave)
|
45
|
+
socket << ARGV.to_json << "\n"
|
46
|
+
slave.close
|
47
|
+
|
48
|
+
pid = socket.gets.strip.to_i
|
49
|
+
|
50
|
+
begin
|
51
|
+
buffer = ""
|
52
|
+
|
53
|
+
while ready = select([winch, master, $stdin])[0]
|
54
|
+
if ready.include?(winch)
|
55
|
+
winch.read(1)
|
56
|
+
$stdout.tty? and master.winsize = $stdout.winsize
|
57
|
+
Process.kill("WINCH", pid)
|
58
|
+
end
|
59
|
+
|
60
|
+
if ready.include?($stdin)
|
61
|
+
input = $stdin.readpartial(4096, buffer)
|
62
|
+
input.scan(SIGNAL_REGEX).each { |signal|
|
63
|
+
Process.kill(SIGNALS[signal], pid)
|
64
|
+
}
|
65
|
+
master << input
|
66
|
+
end
|
67
|
+
|
68
|
+
if ready.include?(master)
|
69
|
+
$stdout << master.readpartial(4096, buffer)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
rescue EOFError
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/zeus/process.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Process
|
2
|
+
|
3
|
+
def self.killall_descendants(sig, base=Process.pid)
|
4
|
+
descendants(base).each do |pid|
|
5
|
+
begin
|
6
|
+
Process.kill(sig, pid)
|
7
|
+
rescue Errno::ESRCH
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.descendants(base=Process.pid)
|
13
|
+
descendants = Hash.new{|ht,k| ht[k]=[k]}
|
14
|
+
Hash[*`ps -eo pid,ppid`.scan(/\d+/).map{|x|x.to_i}].each{|pid,ppid|
|
15
|
+
descendants[ppid] << descendants[pid]
|
16
|
+
}
|
17
|
+
descendants[base].flatten - [base]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
data/lib/zeus/server.rb
ADDED
@@ -0,0 +1,298 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
require 'rb-kqueue'
|
5
|
+
require 'zeus/process'
|
6
|
+
|
7
|
+
module Zeus
|
8
|
+
module Server
|
9
|
+
def self.define!(&b)
|
10
|
+
@@root = Stage.new("(root)")
|
11
|
+
@@root.instance_eval(&b)
|
12
|
+
@@files = {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.pid_has_file(pid, file)
|
16
|
+
@@files[file] ||= []
|
17
|
+
@@files[file] << pid
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.killall_with_file(file)
|
21
|
+
pids = @@files[file]
|
22
|
+
@@process_tree.kill_nodes_with_feature(file)
|
23
|
+
end
|
24
|
+
|
25
|
+
TARGET_FD_LIMIT = 8192
|
26
|
+
|
27
|
+
def self.configure_number_of_file_descriptors
|
28
|
+
limit = Process.getrlimit(Process::RLIMIT_NOFILE)
|
29
|
+
if limit[0] < TARGET_FD_LIMIT && limit[1] >= TARGET_FD_LIMIT
|
30
|
+
Process.setrlimit(Process::RLIMIT_NOFILE, TARGET_FD_LIMIT)
|
31
|
+
else
|
32
|
+
puts "\x1b[33m[zeus] Warning: increase the max number of file descriptors. If you have a large project, this max cause a crash in about 10 seconds.\x1b[0m"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.notify(event)
|
37
|
+
if event.flags.include?(:delete)
|
38
|
+
# file was deleted, so we need to close and reopen it.
|
39
|
+
event.watcher.disable!
|
40
|
+
begin
|
41
|
+
@@queue.watch_file(event.watcher.path, :write, :extend, :rename, :delete, &method(:notify))
|
42
|
+
rescue Errno::ENOENT
|
43
|
+
lost_files << event.watcher.path
|
44
|
+
end
|
45
|
+
end
|
46
|
+
puts "\x1b[37m[zeus] dependency change: #{event.watcher.path}\x1b[0m"
|
47
|
+
killall_with_file(event.watcher.path)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.run
|
51
|
+
$0 = "zeus master"
|
52
|
+
configure_number_of_file_descriptors
|
53
|
+
trap("INT") { exit 0 }
|
54
|
+
at_exit { Process.killall_descendants(9) }
|
55
|
+
|
56
|
+
$r_features, $w_features = IO.pipe
|
57
|
+
$w_features.sync = true
|
58
|
+
|
59
|
+
$r_pids, $w_pids = IO.pipe
|
60
|
+
$w_pids.sync = true
|
61
|
+
|
62
|
+
@@process_tree = ProcessTree.new
|
63
|
+
@@root_stage_pid = @@root.run
|
64
|
+
|
65
|
+
@@queue = KQueue::Queue.new
|
66
|
+
|
67
|
+
lost_files = []
|
68
|
+
|
69
|
+
@@file_watchers = {}
|
70
|
+
loop do
|
71
|
+
@@queue.poll
|
72
|
+
|
73
|
+
# TODO: It would be really nice if we could put the queue poller in the select somehow.
|
74
|
+
# --investigate kqueue. Is this possible?
|
75
|
+
rs, _, _ = IO.select([$r_features, $r_pids], [], [], 1)
|
76
|
+
rs.each do |r|
|
77
|
+
case r
|
78
|
+
when $r_pids ; handle_pid_message(r.readline)
|
79
|
+
when $r_features ; handle_feature_message(r.readline)
|
80
|
+
end
|
81
|
+
end if rs
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
class ProcessTree
|
87
|
+
class Node
|
88
|
+
attr_accessor :pid, :children, :features
|
89
|
+
def initialize(pid)
|
90
|
+
@pid, @children, @features = pid, [], {}
|
91
|
+
end
|
92
|
+
|
93
|
+
def add_child(node)
|
94
|
+
self.children << node
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_feature(feature)
|
98
|
+
self.features[feature] = true
|
99
|
+
end
|
100
|
+
|
101
|
+
def has_feature?(feature)
|
102
|
+
self.features[feature] == true
|
103
|
+
end
|
104
|
+
|
105
|
+
def inspect
|
106
|
+
"(#{pid}:#{features.size}:[#{children.map(&:inspect).join(",")}])"
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def inspect
|
112
|
+
@root.inspect
|
113
|
+
end
|
114
|
+
|
115
|
+
def initialize
|
116
|
+
@root = Node.new(Process.pid)
|
117
|
+
@nodes_by_pid = {Process.pid => @root}
|
118
|
+
end
|
119
|
+
|
120
|
+
def node_for_pid(pid)
|
121
|
+
@nodes_by_pid[pid.to_i] ||= Node.new(pid.to_i)
|
122
|
+
end
|
123
|
+
|
124
|
+
def process_has_parent(pid, ppid)
|
125
|
+
curr = node_for_pid(pid)
|
126
|
+
base = node_for_pid(ppid)
|
127
|
+
base.add_child(curr)
|
128
|
+
end
|
129
|
+
|
130
|
+
def process_has_feature(pid, feature)
|
131
|
+
node = node_for_pid(pid)
|
132
|
+
node.add_feature(feature)
|
133
|
+
end
|
134
|
+
|
135
|
+
def kill_node(node)
|
136
|
+
@nodes_by_pid.delete(node.pid)
|
137
|
+
# recall that this process explicitly traps INT -> exit 0
|
138
|
+
Process.kill("INT", node.pid)
|
139
|
+
end
|
140
|
+
|
141
|
+
def kill_nodes_with_feature(file, base = @root)
|
142
|
+
if base.has_feature?(file)
|
143
|
+
if base == @root.children[0] || base == @root
|
144
|
+
puts "\x1b[31mOne of zeus's dependencies changed. Not killing zeus. You may have to restart the server.\x1b[0m"
|
145
|
+
return false
|
146
|
+
end
|
147
|
+
kill_node(base)
|
148
|
+
return true
|
149
|
+
else
|
150
|
+
base.children.dup.each do |node|
|
151
|
+
if kill_nodes_with_feature(file, node)
|
152
|
+
base.children.delete(node)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
return false
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.handle_pid_message(data)
|
162
|
+
data =~ /(\d+):(\d+)/
|
163
|
+
pid, ppid = $1.to_i, $2.to_i
|
164
|
+
@@process_tree.process_has_parent(pid, ppid)
|
165
|
+
end
|
166
|
+
|
167
|
+
def self.handle_feature_message(data)
|
168
|
+
data =~ /(\d+):(.*)/
|
169
|
+
pid, file = $1.to_i, $2
|
170
|
+
@@process_tree.process_has_feature(pid, file)
|
171
|
+
return if @@file_watchers[file]
|
172
|
+
begin
|
173
|
+
@@file_watchers[file] = true
|
174
|
+
@@queue.watch_file(file.chomp, :write, :extend, :rename, :delete, &method(:notify))
|
175
|
+
# rescue Errno::EMFILE
|
176
|
+
# exit 1
|
177
|
+
rescue Errno::ENOENT
|
178
|
+
puts "No file found at #{file.chomp}"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class Stage
|
183
|
+
attr_reader :pid
|
184
|
+
def initialize(name)
|
185
|
+
@name = name
|
186
|
+
@stages, @actions = [], []
|
187
|
+
end
|
188
|
+
|
189
|
+
def action(&b)
|
190
|
+
@actions << b
|
191
|
+
end
|
192
|
+
|
193
|
+
def stage(name, &b)
|
194
|
+
@stages << Stage.new(name).tap { |s| s.instance_eval(&b) }
|
195
|
+
end
|
196
|
+
|
197
|
+
def acceptor(name, socket, &b)
|
198
|
+
@stages << Acceptor.new(name, socket, &b)
|
199
|
+
end
|
200
|
+
|
201
|
+
# There are a few things we want to accomplish:
|
202
|
+
# 1. Running all the actions (each time this stage is killed and restarted)
|
203
|
+
# 2. Starting all the substages (and restarting them when necessary)
|
204
|
+
# 3. Starting all the acceptors (and restarting them when necessary)
|
205
|
+
def run
|
206
|
+
@pid = fork {
|
207
|
+
$0 = "zeus spawner: #{@name}"
|
208
|
+
pid = Process.pid
|
209
|
+
$w_pids.puts "#{pid}:#{Process.ppid}\n"
|
210
|
+
puts "\x1b[35m[zeus] starting spawner `#{@name}`\x1b[0m"
|
211
|
+
trap("INT") {
|
212
|
+
puts "\x1b[35m[zeus] killing spawner `#{@name}`\x1b[0m"
|
213
|
+
exit 0
|
214
|
+
}
|
215
|
+
|
216
|
+
@actions.each(&:call)
|
217
|
+
|
218
|
+
$LOADED_FEATURES.each do |f|
|
219
|
+
$w_features.puts "#{pid}:#{f}\n"
|
220
|
+
end
|
221
|
+
|
222
|
+
pids = {}
|
223
|
+
@stages.each do |stage|
|
224
|
+
pids[stage.run] = stage
|
225
|
+
end
|
226
|
+
|
227
|
+
loop do
|
228
|
+
begin
|
229
|
+
pid = Process.wait
|
230
|
+
rescue Errno::ECHILD
|
231
|
+
raise "Stage `#{@name}` has no children. All terminal nodes must be acceptors"
|
232
|
+
end
|
233
|
+
if (status = $?.exitstatus) > 0
|
234
|
+
exit status
|
235
|
+
else # restart the stage that died.
|
236
|
+
stage = pids[pid]
|
237
|
+
pids[stage.run] = stage
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
}
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
|
246
|
+
class Acceptor
|
247
|
+
attr_reader :pid
|
248
|
+
def initialize(name, socket, &b)
|
249
|
+
@name = name
|
250
|
+
@socket = socket
|
251
|
+
@action = b
|
252
|
+
end
|
253
|
+
|
254
|
+
def run
|
255
|
+
@pid = fork {
|
256
|
+
$0 = "zeus acceptor: #{@name}"
|
257
|
+
pid = Process.pid
|
258
|
+
$w_pids.puts "#{pid}:#{Process.ppid}\n"
|
259
|
+
$LOADED_FEATURES.each do |f|
|
260
|
+
$w_features.puts "#{pid}:#{f}\n"
|
261
|
+
end
|
262
|
+
puts "\x1b[35m[zeus] starting acceptor `#{@name}`\x1b[0m"
|
263
|
+
trap("INT") {
|
264
|
+
puts "\x1b[35m[zeus] killing acceptor `#{@name}`\x1b[0m"
|
265
|
+
exit 0
|
266
|
+
}
|
267
|
+
|
268
|
+
File.unlink(@socket) rescue nil
|
269
|
+
server = UNIXServer.new(@socket)
|
270
|
+
loop do
|
271
|
+
ActiveRecord::Base.clear_all_connections! # TODO : refactor
|
272
|
+
client = server.accept
|
273
|
+
child = fork do
|
274
|
+
ActiveRecord::Base.establish_connection # TODO :refactor
|
275
|
+
ActiveSupport::DescendantsTracker.clear
|
276
|
+
ActiveSupport::Dependencies.clear
|
277
|
+
|
278
|
+
terminal = client.recv_io
|
279
|
+
arguments = JSON.load(client.gets.strip)
|
280
|
+
|
281
|
+
client << $$ << "\n"
|
282
|
+
$stdin.reopen(terminal)
|
283
|
+
$stdout.reopen(terminal)
|
284
|
+
$stderr.reopen(terminal)
|
285
|
+
ARGV.replace(arguments)
|
286
|
+
|
287
|
+
@action.call
|
288
|
+
end
|
289
|
+
Process.detach(child)
|
290
|
+
client.close
|
291
|
+
end
|
292
|
+
}
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
end
|
data/lib/zeus/version.rb
CHANGED
data/zeus.gemspec
CHANGED
@@ -4,8 +4,8 @@ require File.expand_path('../lib/zeus/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Burke Libbey"]
|
6
6
|
gem.email = ["burke@libbey.me"]
|
7
|
-
gem.description = %q{
|
8
|
-
gem.summary = %q{
|
7
|
+
gem.description = %q{Zeus preloads pretty much everything you'll ever want to use in development.}
|
8
|
+
gem.summary = %q{Zeus is an alpha-quality application preloader with terrible documentation.}
|
9
9
|
gem.homepage = ""
|
10
10
|
|
11
11
|
gem.files = `git ls-files`.split($\)
|
@@ -14,4 +14,6 @@ Gem::Specification.new do |gem|
|
|
14
14
|
gem.name = "zeus"
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Zeus::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency "rb-kqueue-burke", "~> 0.1.0"
|
17
19
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zeus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-07-
|
13
|
-
dependencies:
|
14
|
-
|
12
|
+
date: 2012-07-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rb-kqueue-burke
|
16
|
+
requirement: &70349438039760 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.1.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70349438039760
|
25
|
+
description: Zeus preloads pretty much everything you'll ever want to use in development.
|
15
26
|
email:
|
16
27
|
- burke@libbey.me
|
17
|
-
executables:
|
28
|
+
executables:
|
29
|
+
- zeus
|
18
30
|
extensions: []
|
19
31
|
extra_rdoc_files: []
|
20
32
|
files:
|
@@ -23,7 +35,12 @@ files:
|
|
23
35
|
- LICENSE
|
24
36
|
- README.md
|
25
37
|
- Rakefile
|
38
|
+
- bin/zeus
|
39
|
+
- examples/rails.rb
|
26
40
|
- lib/zeus.rb
|
41
|
+
- lib/zeus/client.rb
|
42
|
+
- lib/zeus/process.rb
|
43
|
+
- lib/zeus/server.rb
|
27
44
|
- lib/zeus/version.rb
|
28
45
|
- zeus.gemspec
|
29
46
|
homepage: ''
|
@@ -49,5 +66,5 @@ rubyforge_project:
|
|
49
66
|
rubygems_version: 1.8.11
|
50
67
|
signing_key:
|
51
68
|
specification_version: 3
|
52
|
-
summary:
|
69
|
+
summary: Zeus is an alpha-quality application preloader with terrible documentation.
|
53
70
|
test_files: []
|