zeus 0.4.6 → 0.10.0.pre
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/Gemfile +0 -4
- data/Rakefile +52 -8
- data/bin/zeus +14 -6
- data/build/fsevents-wrapper +0 -0
- data/build/zeus-darwin-amd64 +0 -0
- data/build/zeus-linux-386 +0 -0
- data/build/zeus-linux-amd64 +0 -0
- data/examples/zeus.json +22 -0
- data/ext/fsevents-wrapper/fsevents-wrapper +0 -0
- data/ext/inotify-wrapper/extconf.rb +24 -0
- data/ext/inotify-wrapper/inotify-wrapper.cpp +86 -0
- data/lib/zeus.rb +123 -35
- data/lib/zeus/{server/load_tracking.rb → load_tracking.rb} +1 -3
- data/lib/zeus/rails.rb +141 -0
- data/man/build/zeus +49 -0
- data/man/build/zeus-init +13 -0
- data/man/build/zeus-init.txt +17 -0
- data/man/build/zeus-start +16 -0
- data/man/build/zeus-start.txt +18 -0
- data/man/build/zeus.txt +50 -0
- data/zeus.gemspec +17 -6
- metadata +27 -58
- data/.gitignore +0 -17
- data/.travis.yml +0 -5
- data/.zeus.rb +0 -11
- data/README.md +0 -73
- data/docs/acceptor_registration.md +0 -14
- data/docs/client_server_handshake.md +0 -25
- data/ext/fsevents-wrapper/main.m +0 -118
- data/lib/thrud.rb +0 -97
- data/lib/zeus/cli.rb +0 -80
- data/lib/zeus/client.rb +0 -114
- data/lib/zeus/client/winsize.rb +0 -28
- data/lib/zeus/error_printer.rb +0 -16
- data/lib/zeus/plan.rb +0 -18
- data/lib/zeus/plan/acceptor.rb +0 -38
- data/lib/zeus/plan/node.rb +0 -66
- data/lib/zeus/plan/stage.rb +0 -50
- data/lib/zeus/server.rb +0 -103
- data/lib/zeus/server/acceptor.rb +0 -79
- data/lib/zeus/server/acceptor_registration_monitor.rb +0 -75
- data/lib/zeus/server/client_handler.rb +0 -106
- data/lib/zeus/server/command_runner.rb +0 -70
- data/lib/zeus/server/file_monitor.rb +0 -8
- data/lib/zeus/server/file_monitor/fsevent.rb +0 -102
- data/lib/zeus/server/process_tree_monitor.rb +0 -89
- data/lib/zeus/server/stage.rb +0 -88
- data/lib/zeus/server/stage/error_state.rb +0 -42
- data/lib/zeus/server/stage/feature_notifier.rb +0 -38
- data/lib/zeus/templates/rails.rb +0 -133
- data/lib/zeus/ui.rb +0 -57
- data/lib/zeus/version.rb +0 -3
- data/spec/cli_spec.rb +0 -95
- data/spec/error_printer_spec.rb +0 -27
- data/spec/integration_spec.rb +0 -106
- data/spec/server/file_monitor/fsevent_spec.rb +0 -88
- data/spec/server/load_tracking_spec.rb +0 -67
- data/spec/server/process_tree_monitor_spec.rb +0 -50
- data/spec/spec_helper.rb +0 -38
- data/spec/ui_spec.rb +0 -54
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -1,13 +1,57 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
require "bundler/gem_tasks"
|
3
|
+
require 'fileutils'
|
4
|
+
require 'pathname'
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
ROOT_PATH = Pathname.new(File.expand_path("../../", __FILE__))
|
7
|
+
RUBYGEM_PATH = Pathname.new(File.expand_path("../", __FILE__))
|
8
|
+
|
9
|
+
task build: [:import_externals, :version, :manifest]
|
10
|
+
task default: :build
|
11
|
+
|
12
|
+
task :import_externals do
|
13
|
+
puts "building rubygem"
|
14
|
+
|
15
|
+
Rake::Task[:clean].invoke
|
16
|
+
|
17
|
+
FileUtils.rm_r(RUBYGEM_PATH + "man") rescue nil
|
18
|
+
FileUtils.rm_r(RUBYGEM_PATH + "build") rescue nil
|
19
|
+
|
20
|
+
# manpages
|
21
|
+
FileUtils.mkdir(RUBYGEM_PATH + "man")
|
22
|
+
FileUtils.cp_r(ROOT_PATH + "man/build", RUBYGEM_PATH + "man")
|
23
|
+
|
24
|
+
# multi-arch binaries
|
25
|
+
FileUtils.cp_r(ROOT_PATH + "build", RUBYGEM_PATH + "build")
|
26
|
+
|
27
|
+
Rake::Task[:manifest].invoke
|
28
|
+
Rake::Task[:build].invoke
|
29
|
+
end
|
30
|
+
|
31
|
+
task :version do
|
32
|
+
version = File.read('../VERSION').chomp
|
33
|
+
File.open('lib/zeus/version.rb', 'w') { |f| f.puts <<END
|
34
|
+
module Zeus
|
35
|
+
VERSION = "#{version}"
|
36
|
+
end
|
37
|
+
END
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
task :manifest do
|
42
|
+
files = `find . -type file | sed 's|^\./||'`.lines.map(&:chomp)
|
43
|
+
exceptions = [
|
44
|
+
/.gitignore$/,
|
45
|
+
/^MANIFEST$/,
|
46
|
+
/^pkg\//,
|
47
|
+
]
|
48
|
+
files.reject! { |f| exceptions.any? {|ex| f =~ ex }}
|
49
|
+
File.open('MANIFEST', 'w') {|f| f.puts files.join("\n") }
|
50
|
+
end
|
51
|
+
|
52
|
+
task :clean do
|
53
|
+
FileUtils.rm(RUBYGEM_PATH + "lib/zeus/version.rb") rescue nil
|
54
|
+
FileUtils.rm_r(RUBYGEM_PATH + "man") rescue nil
|
55
|
+
FileUtils.rm_r(RUBYGEM_PATH + "build") rescue nil
|
11
56
|
end
|
12
57
|
|
13
|
-
task default: :spec
|
data/bin/zeus
CHANGED
@@ -1,8 +1,16 @@
|
|
1
|
-
|
1
|
+
platform = `uname -sm`
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
exe = case platform
|
4
|
+
when /^Darwin/ ; "zeus-darwin-amd64"
|
5
|
+
when /^Linux.*64/ ; "zeus-linux-amd64"
|
6
|
+
when /^Linux.*/ ; "zeus-linux-386"
|
7
|
+
else
|
8
|
+
puts "Zeus is not supported on your platform."
|
9
|
+
puts "It's not likely to ever be possible on Windows."
|
10
|
+
puts "If you're using another platform that you think should work easily, open an issue at:"
|
11
|
+
puts "https://github.com/burke/zeus/issues"
|
12
|
+
exit 1
|
13
|
+
end
|
6
14
|
|
7
|
-
|
8
|
-
|
15
|
+
zeusgemdir = File.expand_path("../../", __FILE__)
|
16
|
+
exec "#{zeusgemdir}/build/#{exe}", *ARGV
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/examples/zeus.json
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"command": "ruby -rzeus/rails -eZeus.go",
|
3
|
+
|
4
|
+
"plan": {
|
5
|
+
"boot": {
|
6
|
+
"default_bundle": {
|
7
|
+
"development_environment": {
|
8
|
+
"prerake": {"rake": []},
|
9
|
+
"runner": ["r"],
|
10
|
+
"console": ["c"],
|
11
|
+
"server": ["s"],
|
12
|
+
"generate": ["g"]
|
13
|
+
},
|
14
|
+
"test_environment": {
|
15
|
+
"testtask": [],
|
16
|
+
"test_helper": {"testrb": []},
|
17
|
+
"spec_helper": {"rspec": []}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
if /linux/ =~ RUBY_PLATFORM
|
2
|
+
open("Makefile", "wb") do |f|
|
3
|
+
f.write <<-EOF
|
4
|
+
CXX = g++
|
5
|
+
CXXFLAGS = -O3 -g -Wall
|
6
|
+
|
7
|
+
inotify-wrapper: inotify-wrapper.o
|
8
|
+
$(CXX) $(CXXFLAGS) $< -o $@
|
9
|
+
|
10
|
+
%.o: %.cpp
|
11
|
+
$(CXX) $(CXXFLAGS) -c $< -o $@
|
12
|
+
|
13
|
+
install:
|
14
|
+
# do nothing
|
15
|
+
EOF
|
16
|
+
end
|
17
|
+
else
|
18
|
+
open("Makefile", "wb") do |f|
|
19
|
+
f.write <<-EOF
|
20
|
+
install:
|
21
|
+
# do nothing
|
22
|
+
EOF
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
#include <map>
|
2
|
+
#include <string>
|
3
|
+
|
4
|
+
#include <stdio.h>
|
5
|
+
#include <stdlib.h>
|
6
|
+
#include <string.h>
|
7
|
+
#include <errno.h>
|
8
|
+
#include <unistd.h>
|
9
|
+
#include <sys/types.h>
|
10
|
+
#include <sys/inotify.h>
|
11
|
+
|
12
|
+
#define EVENT_SIZE (sizeof (struct inotify_event))
|
13
|
+
#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
|
14
|
+
|
15
|
+
using namespace std;
|
16
|
+
|
17
|
+
static int _inotify_fd;
|
18
|
+
static map<int, char*> _WatchedFiles;
|
19
|
+
static map<char*, bool> _FileIsWatched;
|
20
|
+
|
21
|
+
static int inotifyFlags = IN_ATTRIB | IN_MODIFY | IN_MOVE_SELF | IN_DELETE_SELF;
|
22
|
+
|
23
|
+
void maybeAddFileToWatchList(char *file)
|
24
|
+
{
|
25
|
+
if (_FileIsWatched[file]) return;
|
26
|
+
|
27
|
+
_FileIsWatched[file] = true;
|
28
|
+
int wd = inotify_add_watch(_inotify_fd, file, inotifyFlags);
|
29
|
+
_WatchedFiles[wd] = file;
|
30
|
+
}
|
31
|
+
|
32
|
+
void handleStdin()
|
33
|
+
{
|
34
|
+
char line[2048];
|
35
|
+
if (fgets(line, sizeof(line), stdin) == NULL) return;
|
36
|
+
line[strlen(line)-1] = 0;
|
37
|
+
|
38
|
+
maybeAddFileToWatchList(line);
|
39
|
+
}
|
40
|
+
|
41
|
+
void handleInotify()
|
42
|
+
{
|
43
|
+
int length;
|
44
|
+
int i = 0;
|
45
|
+
char buffer[EVENT_BUF_LEN];
|
46
|
+
string filename;
|
47
|
+
|
48
|
+
length = read(_inotify_fd, buffer, EVENT_BUF_LEN);
|
49
|
+
if (length < 0) return;
|
50
|
+
|
51
|
+
while (i < length) {
|
52
|
+
struct inotify_event *event = (struct inotify_event *) &buffer[i];
|
53
|
+
printf("%s\n", _WatchedFiles[event->wd]);
|
54
|
+
fflush(stdout);
|
55
|
+
|
56
|
+
i += EVENT_SIZE + event->len;
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
void go()
|
61
|
+
{
|
62
|
+
fd_set rfds;
|
63
|
+
int retval;
|
64
|
+
|
65
|
+
for (;;) {
|
66
|
+
FD_ZERO(&rfds);
|
67
|
+
FD_SET(0, &rfds);
|
68
|
+
FD_SET(_inotify_fd, &rfds);
|
69
|
+
|
70
|
+
retval = select(_inotify_fd+1, &rfds, NULL, NULL, NULL);
|
71
|
+
|
72
|
+
if (retval == -1) {
|
73
|
+
// perror("select");
|
74
|
+
} else if (retval) {
|
75
|
+
if (FD_ISSET(0, &rfds)) handleStdin();
|
76
|
+
if (FD_ISSET(_inotify_fd, &rfds)) handleInotify();
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
|
82
|
+
int main(int argc, const char *argv[])
|
83
|
+
{
|
84
|
+
_inotify_fd = inotify_init();
|
85
|
+
go();
|
86
|
+
}
|
data/lib/zeus.rb
CHANGED
@@ -1,47 +1,135 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
|
4
|
-
require 'zeus/
|
5
|
-
require 'zeus/client'
|
6
|
-
require 'zeus/error_printer'
|
7
|
-
require 'zeus/cli'
|
1
|
+
require 'socket'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'zeus/load_tracking'
|
8
5
|
|
9
6
|
module Zeus
|
10
|
-
|
7
|
+
class << self
|
11
8
|
|
12
|
-
|
13
|
-
|
14
|
-
|
9
|
+
def add_extra_feature(path)
|
10
|
+
$untracked_features ||= []
|
11
|
+
$untracked_features << path
|
15
12
|
end
|
16
|
-
end
|
17
13
|
|
18
|
-
|
19
|
-
@ui ||= UI.new
|
20
|
-
end
|
14
|
+
attr_accessor :plan
|
21
15
|
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
def report_error_to_master(local, error)
|
17
|
+
str = "R:"
|
18
|
+
str << "#{error.backtrace[0]}: #{error.message} (#{error.class})\n"
|
19
|
+
error.backtrace[1..-1].each do |line|
|
20
|
+
str << "\tfrom #{line}\n"
|
21
|
+
end
|
22
|
+
str << "\0"
|
23
|
+
local.write str
|
24
|
+
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
def run_action(socket, identifier)
|
27
|
+
plan.send(identifier)
|
28
|
+
socket.write "R:OK\0"
|
29
|
+
rescue Exception => e
|
30
|
+
report_error_to_master(socket, e)
|
31
|
+
end
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
def notify_features(sock, features)
|
34
|
+
features.each do |t|
|
35
|
+
begin
|
36
|
+
sock.write "F:#{t}\0"
|
37
|
+
rescue Errno::ENOBUFS
|
38
|
+
sleep 0.2
|
39
|
+
retry
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
35
43
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
44
|
+
def handle_dead_children(sock)
|
45
|
+
# TODO: It would be nice if it were impossible for this
|
46
|
+
# to interfere with the identifer -> IO thing.
|
47
|
+
loop do
|
48
|
+
pid = Process.wait(-1, Process::WNOHANG)
|
49
|
+
break if pid.nil?
|
50
|
+
# sock.send("D:#{pid}")
|
42
51
|
end
|
43
|
-
|
44
|
-
|
52
|
+
rescue Errno::ECHILD
|
53
|
+
end
|
45
54
|
|
46
|
-
|
55
|
+
def go(identifier=:boot)
|
56
|
+
identifier = identifier.to_sym
|
57
|
+
$0 = "zeus slave: #{identifier}"
|
58
|
+
# okay, so I ahve this FD that I can use to send data to the master.
|
59
|
+
fd = ENV['ZEUS_MASTER_FD'].to_i
|
60
|
+
master = UNIXSocket.for_fd(fd)
|
61
|
+
|
62
|
+
# I need to give the master a way to talk to me exclusively
|
63
|
+
local, remote = UNIXSocket.pair(:DGRAM)
|
64
|
+
master.send_io(remote)
|
65
|
+
|
66
|
+
# Now I need to tell the master about my PID and ID
|
67
|
+
local.write "P:#{Process.pid}:#{identifier}\0"
|
68
|
+
|
69
|
+
# Now we run the action and report its success/fail status to the master.
|
70
|
+
features = features_loaded_by {
|
71
|
+
run_action(local, identifier)
|
72
|
+
}
|
73
|
+
|
74
|
+
# the master wants to know about the files that running the action caused us to load.
|
75
|
+
Thread.new { notify_features(local, features) }
|
47
76
|
|
77
|
+
# We are now 'connected'. From this point, we may receive requests to fork.
|
78
|
+
loop do
|
79
|
+
new_identifier = local.recv(1024)
|
80
|
+
new_identifier.chomp!("\0")
|
81
|
+
if new_identifier =~ /^S:/
|
82
|
+
fork { plan.after_fork ; go(new_identifier.sub(/^S:/,'')) }
|
83
|
+
else
|
84
|
+
fork { plan.after_fork ; command(new_identifier.sub(/^C:/,''), local) }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def all_features
|
90
|
+
untracked = defined?($untracked_features) ? $untracked_features : []
|
91
|
+
$LOADED_FEATURES + untracked
|
92
|
+
end
|
93
|
+
|
94
|
+
def features_loaded_by(&block)
|
95
|
+
old_features = all_features()
|
96
|
+
yield
|
97
|
+
new_features = all_features() - old_features
|
98
|
+
return new_features
|
99
|
+
end
|
100
|
+
|
101
|
+
def command(identifier, sock)
|
102
|
+
$0 = "zeus runner: #{identifier}"
|
103
|
+
Process.setsid
|
104
|
+
|
105
|
+
local, remote = UNIXSocket.pair(:DGRAM)
|
106
|
+
sock.send_io(remote)
|
107
|
+
remote.close
|
108
|
+
sock.close
|
109
|
+
|
110
|
+
arguments = local.recv(1024)
|
111
|
+
arguments.chomp!("\0")
|
112
|
+
|
113
|
+
pid = fork {
|
114
|
+
plan.after_fork
|
115
|
+
client_terminal = local.recv_io
|
116
|
+
local.write "P:#{Process.pid}:\0"
|
117
|
+
local.close
|
118
|
+
|
119
|
+
$stdin.reopen(client_terminal)
|
120
|
+
$stdout.reopen(client_terminal)
|
121
|
+
$stderr.reopen(client_terminal)
|
122
|
+
ARGV.replace(JSON.parse(arguments))
|
123
|
+
|
124
|
+
plan.send(identifier)
|
125
|
+
}
|
126
|
+
|
127
|
+
Process.wait(pid)
|
128
|
+
code = $?.exitstatus
|
129
|
+
|
130
|
+
local.write "#{code}\0"
|
131
|
+
local.close
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
@@ -2,16 +2,14 @@ module Zeus
|
|
2
2
|
class Server
|
3
3
|
class LoadTracking
|
4
4
|
class << self
|
5
|
-
attr_accessor :server
|
6
5
|
|
7
6
|
def add_feature(file)
|
8
|
-
return unless server
|
9
7
|
path = if File.exist?(File.expand_path(file))
|
10
8
|
File.expand_path(file)
|
11
9
|
else
|
12
10
|
find_in_load_path(file)
|
13
11
|
end
|
14
|
-
|
12
|
+
Zeus.add_extra_feature(path) if path
|
15
13
|
end
|
16
14
|
|
17
15
|
private
|
data/lib/zeus/rails.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
ROOT_PATH = File.expand_path(Dir.pwd)
|
2
|
+
ENV_PATH = File.expand_path('config/environment', ROOT_PATH)
|
3
|
+
BOOT_PATH = File.expand_path('config/boot', ROOT_PATH)
|
4
|
+
APP_PATH = File.expand_path('config/application', ROOT_PATH)
|
5
|
+
|
6
|
+
require 'zeus'
|
7
|
+
|
8
|
+
module Zeus ; module Rails ; end ; end
|
9
|
+
Zeus.plan ||= Zeus::Rails
|
10
|
+
|
11
|
+
module Zeus
|
12
|
+
module Rails
|
13
|
+
class << self
|
14
|
+
|
15
|
+
def after_fork
|
16
|
+
reconnect_activerecord
|
17
|
+
restart_girl_friday
|
18
|
+
end
|
19
|
+
|
20
|
+
def boot
|
21
|
+
require BOOT_PATH
|
22
|
+
require 'rails/all'
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_bundle
|
26
|
+
Bundler.require(:default)
|
27
|
+
end
|
28
|
+
|
29
|
+
def development_environment
|
30
|
+
Bundler.require(:development)
|
31
|
+
::Rails.env = ENV['RAILS_ENV'] = "development"
|
32
|
+
require APP_PATH
|
33
|
+
::Rails.application.require_environment!
|
34
|
+
end
|
35
|
+
|
36
|
+
def prerake
|
37
|
+
require 'rake'
|
38
|
+
load 'Rakefile'
|
39
|
+
end
|
40
|
+
|
41
|
+
def rake
|
42
|
+
Rake.application.run
|
43
|
+
end
|
44
|
+
|
45
|
+
def generate
|
46
|
+
begin
|
47
|
+
require 'rails/generators'
|
48
|
+
::Rails.application.load_generators
|
49
|
+
rescue LoadError # Rails 3.0 doesn't require this block to be run, but 3.2+ does
|
50
|
+
end
|
51
|
+
require 'rails/commands/generate'
|
52
|
+
end
|
53
|
+
|
54
|
+
def runner
|
55
|
+
require 'rails/commands/runner'
|
56
|
+
end
|
57
|
+
|
58
|
+
def console
|
59
|
+
require 'rails/commands/console'
|
60
|
+
::Rails::Console.start(::Rails.application)
|
61
|
+
end
|
62
|
+
|
63
|
+
def server
|
64
|
+
require 'rails/commands/server'
|
65
|
+
server = ::Rails::Server.new
|
66
|
+
Dir.chdir(::Rails.application.root)
|
67
|
+
server.start
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_environment
|
71
|
+
Bundler.require(:test)
|
72
|
+
|
73
|
+
::Rails.env = ENV['RAILS_ENV'] = 'test'
|
74
|
+
require APP_PATH
|
75
|
+
|
76
|
+
$rails_rake_task = 'yup' # lie to skip eager loading
|
77
|
+
::Rails.application.require_environment!
|
78
|
+
$rails_rake_task = nil
|
79
|
+
$LOAD_PATH.unshift(ROOT_PATH) unless $LOAD_PATH.include?(ROOT_PATH)
|
80
|
+
|
81
|
+
if Dir.exist?(ROOT_PATH + "/test")
|
82
|
+
test = File.join(ROOT_PATH, 'test')
|
83
|
+
$LOAD_PATH.unshift(test) unless $LOAD_PATH.include?(test)
|
84
|
+
end
|
85
|
+
|
86
|
+
if Dir.exist?(ROOT_PATH + "/spec")
|
87
|
+
spec = File.join(ROOT_PATH, 'spec')
|
88
|
+
$LOAD_PATH.unshift(spec) unless $LOAD_PATH.include?(spec)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_helper
|
93
|
+
require 'test_helper'
|
94
|
+
end
|
95
|
+
|
96
|
+
def testrb
|
97
|
+
argv = ARGV
|
98
|
+
|
99
|
+
# try to find pattern by line using testrbl
|
100
|
+
if defined?(Testrbl) && argv.size == 1 and argv.first =~ /^\S+:\d+$/
|
101
|
+
file, line = argv.first.split(':')
|
102
|
+
argv = [file, '-n', "/#{Testrbl.send(:pattern_from_file, File.readlines(file), line)}/"]
|
103
|
+
puts "using -n '#{argv[2]}'" # let users copy/paste or adjust the pattern
|
104
|
+
end
|
105
|
+
|
106
|
+
runner = Test::Unit::AutoRunner.new(true)
|
107
|
+
if runner.process_args(argv)
|
108
|
+
exit runner.run
|
109
|
+
else
|
110
|
+
abort runner.options.banner + " tests..."
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def spec_helper
|
115
|
+
require 'spec_helper'
|
116
|
+
end
|
117
|
+
|
118
|
+
def rspec
|
119
|
+
exit RSpec::Core::Runner.run(ARGV)
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def restart_girl_friday
|
126
|
+
return unless defined?(GirlFriday::WorkQueue)
|
127
|
+
# The Actor is run in a thread, and threads don't persist post-fork.
|
128
|
+
# We just need to restart each one in the newly-forked process.
|
129
|
+
ObjectSpace.each_object(GirlFriday::WorkQueue) do |obj|
|
130
|
+
obj.send(:start)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def reconnect_activerecord
|
135
|
+
ActiveRecord::Base.clear_all_connections! rescue nil
|
136
|
+
ActiveRecord::Base.establish_connection rescue nil
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|