zeus 0.4.6 → 0.10.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|