specjour 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.markdown +35 -0
- data/README.markdown +9 -0
- data/Rakefile +4 -5
- data/lib/specjour/cli.rb +54 -30
- data/lib/specjour/configuration.rb +20 -8
- data/lib/specjour/connection.rb +4 -5
- data/lib/specjour/cpu.rb +5 -1
- data/lib/specjour/cucumber/preloader.rb +2 -1
- data/lib/specjour/cucumber.rb +0 -9
- data/lib/specjour/db_scrub.rb +8 -22
- data/lib/specjour/dispatcher.rb +33 -49
- data/lib/specjour/fork.rb +26 -0
- data/lib/specjour/loader.rb +129 -0
- data/lib/specjour/manager.rb +49 -33
- data/lib/specjour/printer.rb +70 -73
- data/lib/specjour/rspec/distributed_formatter.rb +1 -1
- data/lib/specjour/rspec/final_report.rb +2 -2
- data/lib/specjour/rspec/marshalable_exception.rb +4 -0
- data/lib/specjour/rspec/preloader.rb +10 -5
- data/lib/specjour/rspec/runner.rb +8 -7
- data/lib/specjour/rspec.rb +1 -6
- data/lib/specjour/rsync_daemon.rb +10 -7
- data/lib/specjour/worker.rb +5 -27
- data/lib/specjour.rb +15 -5
- metadata +70 -78
- data/lib/specjour/cucumber/main_ext.rb +0 -3
- data/lib/specjour/quiet_fork.rb +0 -11
@@ -0,0 +1,129 @@
|
|
1
|
+
module Specjour
|
2
|
+
class Loader
|
3
|
+
include Protocol
|
4
|
+
include Fork
|
5
|
+
|
6
|
+
attr_reader :test_paths, :printer_uri, :project_path, :task, :worker_size, :worker_pids, :quiet
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@options = options
|
10
|
+
@printer_uri = options[:printer_uri]
|
11
|
+
@test_paths = options[:test_paths]
|
12
|
+
@worker_size = options[:worker_size]
|
13
|
+
@task = options[:task]
|
14
|
+
@quiet = options[:quiet]
|
15
|
+
@project_path = options[:project_path]
|
16
|
+
@worker_pids = []
|
17
|
+
Dir.chdir project_path
|
18
|
+
Specjour.load_custom_hooks
|
19
|
+
end
|
20
|
+
|
21
|
+
def start
|
22
|
+
load_app
|
23
|
+
Configuration.after_load.call
|
24
|
+
(1..worker_size).each do |index|
|
25
|
+
worker_pids << fork do
|
26
|
+
w = Worker.new(
|
27
|
+
:number => index,
|
28
|
+
:printer_uri => printer_uri,
|
29
|
+
:quiet => quiet
|
30
|
+
).send(task)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
Process.waitall
|
34
|
+
ensure
|
35
|
+
kill_worker_processes
|
36
|
+
end
|
37
|
+
|
38
|
+
def spec_files
|
39
|
+
@spec_files ||= file_collector(spec_paths) do |path|
|
40
|
+
if path == project_path
|
41
|
+
Dir["#{path}/spec/**/*_spec.rb"]
|
42
|
+
else
|
43
|
+
Dir["#{path}/**/*_spec.rb"]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def feature_files
|
49
|
+
@feature_files ||= file_collector(feature_paths) do |path|
|
50
|
+
if path == project_path
|
51
|
+
Dir["#{path}/features/**/*.feature"]
|
52
|
+
else
|
53
|
+
Dir["#{path}/**/*.feature"]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def spec_paths
|
61
|
+
@spec_paths ||= test_paths.select {|p| p =~ /spec.*$/}
|
62
|
+
end
|
63
|
+
|
64
|
+
def feature_paths
|
65
|
+
@feature_paths ||= test_paths.select {|p| p =~ /features.*$/}
|
66
|
+
end
|
67
|
+
|
68
|
+
def file_collector(paths, &globber)
|
69
|
+
if spec_paths.empty? && feature_paths.empty?
|
70
|
+
globber[project_path]
|
71
|
+
else
|
72
|
+
paths.map do |path|
|
73
|
+
path = File.expand_path(path, project_path)
|
74
|
+
if File.directory?(path)
|
75
|
+
globber[path]
|
76
|
+
else
|
77
|
+
path
|
78
|
+
end
|
79
|
+
end.flatten.uniq
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def load_app
|
84
|
+
share_examples if spec_files.any?
|
85
|
+
share_features if feature_files.any?
|
86
|
+
end
|
87
|
+
|
88
|
+
def share_examples
|
89
|
+
RSpec::Preloader.load spec_files
|
90
|
+
connection.send_message :tests=, filtered_examples
|
91
|
+
ensure
|
92
|
+
::RSpec.reset
|
93
|
+
end
|
94
|
+
|
95
|
+
def share_features
|
96
|
+
Cucumber::Preloader.load
|
97
|
+
connection.send_message :tests=, feature_files
|
98
|
+
end
|
99
|
+
|
100
|
+
def filtered_examples
|
101
|
+
::RSpec.world.example_groups.map do |g|
|
102
|
+
g.descendants.map do |gs|
|
103
|
+
gs.examples
|
104
|
+
end.flatten.map do |e|
|
105
|
+
"#{e.file_path}:#{e.metadata[:line_number]}"
|
106
|
+
end
|
107
|
+
end.flatten.uniq
|
108
|
+
end
|
109
|
+
|
110
|
+
def kill_worker_processes
|
111
|
+
if Specjour.interrupted?
|
112
|
+
Process.kill('INT', *worker_pids) rescue Errno::ESRCH
|
113
|
+
else
|
114
|
+
Process.kill('TERM', *worker_pids) rescue Errno::ESRCH
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def connection
|
119
|
+
@connection ||= begin
|
120
|
+
at_exit { connection.disconnect }
|
121
|
+
printer_connection
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def printer_connection
|
126
|
+
Connection.new URI.parse(printer_uri)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/lib/specjour/manager.rb
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
module Specjour
|
2
2
|
class Manager
|
3
3
|
require 'dnssd'
|
4
|
-
require 'specjour/rspec'
|
5
|
-
require 'specjour/cucumber'
|
6
4
|
|
7
5
|
include DRbUndumped
|
8
6
|
include SocketHelper
|
7
|
+
include Fork
|
9
8
|
|
10
|
-
attr_accessor :
|
11
|
-
attr_reader :worker_size, :dispatcher_uri, :registered_projects, :
|
9
|
+
attr_accessor :test_paths, :project_name, :worker_task, :pid
|
10
|
+
attr_reader :worker_size, :dispatcher_uri, :registered_projects, :loader_pid, :options, :rsync_port
|
12
11
|
|
13
12
|
def self.start_quietly(options)
|
14
13
|
manager = new options.merge(:quiet => true)
|
15
14
|
manager.drb_uri
|
16
|
-
manager.pid =
|
17
|
-
sleep 0.2
|
15
|
+
manager.pid = Fork.fork_quietly { manager.start }
|
18
16
|
manager
|
19
17
|
end
|
20
18
|
|
@@ -23,8 +21,8 @@ module Specjour
|
|
23
21
|
@worker_size = options[:worker_size]
|
24
22
|
@worker_task = options[:worker_task]
|
25
23
|
@registered_projects = options[:registered_projects]
|
26
|
-
@
|
27
|
-
at_exit {
|
24
|
+
@rsync_port = options[:rsync_port]
|
25
|
+
at_exit { kill_loader_process }
|
28
26
|
end
|
29
27
|
|
30
28
|
def available_for?(project_name)
|
@@ -39,8 +37,10 @@ module Specjour
|
|
39
37
|
def dispatch
|
40
38
|
suspend_bonjour do
|
41
39
|
sync
|
42
|
-
|
43
|
-
|
40
|
+
with_clean_env do
|
41
|
+
execute_before_fork
|
42
|
+
dispatch_loader
|
43
|
+
end
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -57,14 +57,21 @@ module Specjour
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
def
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
60
|
+
def dispatch_loader
|
61
|
+
@loader_pid = fork do
|
62
|
+
exec_cmd = "load --printer-uri #{dispatcher_uri} --workers #{worker_size} --task #{worker_task} --project-path #{project_path}"
|
63
|
+
exec_cmd << " --test-paths #{test_paths.join(" ")}" if test_paths.any?
|
64
|
+
exec_cmd << " --log" if Specjour.log?
|
65
|
+
exec_cmd << " --quiet" if quiet?
|
66
|
+
exec_ruby = "Specjour::CLI.start(#{exec_cmd.split(' ').inspect})"
|
67
|
+
load_path = ''
|
68
|
+
$LOAD_PATH.each {|p| load_path << "-I#{p} " if p =~ /specjour/}
|
69
|
+
exec_cmd = "ruby #{load_path} -rspecjour -e '#{exec_ruby}'"
|
70
|
+
exec exec_cmd
|
66
71
|
end
|
67
72
|
Process.waitall
|
73
|
+
ensure
|
74
|
+
kill_loader_process
|
68
75
|
end
|
69
76
|
|
70
77
|
def in_project(&block)
|
@@ -73,13 +80,14 @@ module Specjour
|
|
73
80
|
|
74
81
|
def interrupted=(bool)
|
75
82
|
Specjour.interrupted = bool
|
83
|
+
kill_loader_process
|
76
84
|
end
|
77
85
|
|
78
|
-
def
|
86
|
+
def kill_loader_process
|
79
87
|
if Specjour.interrupted?
|
80
|
-
Process.kill('INT',
|
88
|
+
Process.kill('INT', loader_pid) rescue Errno::ESRCH
|
81
89
|
else
|
82
|
-
Process.kill('TERM',
|
90
|
+
Process.kill('TERM', loader_pid) rescue Errno::ESRCH
|
83
91
|
end
|
84
92
|
end
|
85
93
|
|
@@ -93,9 +101,8 @@ module Specjour
|
|
93
101
|
|
94
102
|
def start
|
95
103
|
drb_start
|
96
|
-
puts "Workers ready: #{worker_size}."
|
97
|
-
puts "Listening for #{registered_projects.join(', ')}"
|
98
104
|
bonjour_announce
|
105
|
+
at_exit { stop_bonjour }
|
99
106
|
DRb.thread.join
|
100
107
|
end
|
101
108
|
|
@@ -104,16 +111,20 @@ module Specjour
|
|
104
111
|
end
|
105
112
|
|
106
113
|
def sync
|
107
|
-
|
108
|
-
|
109
|
-
end
|
114
|
+
cmd "rsync -aL --delete --ignore-errors --port=#{rsync_port} #{dispatcher_uri.host}::#{project_name} #{project_path}"
|
115
|
+
puts "rsync complete"
|
110
116
|
end
|
111
117
|
|
112
118
|
protected
|
113
119
|
|
114
120
|
def bonjour_announce
|
121
|
+
projects = registered_projects.join(", ")
|
122
|
+
puts "Workers ready: #{worker_size}"
|
123
|
+
puts "Listening for #{projects}"
|
115
124
|
unless quiet?
|
116
|
-
|
125
|
+
text = DNSSD::TextRecord.new
|
126
|
+
text['version'] = Specjour::VERSION
|
127
|
+
bonjour_service.register "specjour_manager_#{projects}_#{Process.pid}", "_#{drb_uri.scheme}._tcp", domain=nil, drb_uri.port, host=nil, text
|
117
128
|
end
|
118
129
|
end
|
119
130
|
|
@@ -134,7 +145,7 @@ module Specjour
|
|
134
145
|
end
|
135
146
|
|
136
147
|
def stop_bonjour
|
137
|
-
bonjour_service.stop
|
148
|
+
bonjour_service.stop if bonjour_service && !bonjour_service.stopped?
|
138
149
|
@bonjour_service = nil
|
139
150
|
end
|
140
151
|
|
@@ -144,13 +155,18 @@ module Specjour
|
|
144
155
|
bonjour_announce
|
145
156
|
end
|
146
157
|
|
147
|
-
def
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
158
|
+
def with_clean_env
|
159
|
+
if defined?(Bundler)
|
160
|
+
Bundler.with_clean_env do
|
161
|
+
if ENV['RUBYOPT']
|
162
|
+
opts = ENV['RUBYOPT'].split(" ").delete_if {|opt| opt =~ /bundler/}
|
163
|
+
ENV['RUBYOPT'] = opts.join(" ")
|
164
|
+
end
|
165
|
+
yield
|
166
|
+
end
|
167
|
+
else
|
168
|
+
yield
|
169
|
+
end
|
154
170
|
end
|
155
171
|
end
|
156
172
|
end
|
data/lib/specjour/printer.rb
CHANGED
@@ -1,52 +1,78 @@
|
|
1
1
|
module Specjour
|
2
|
-
require 'specjour/rspec'
|
3
|
-
require 'specjour/cucumber'
|
4
2
|
|
5
|
-
class Printer
|
3
|
+
class Printer
|
6
4
|
include Protocol
|
7
5
|
RANDOM_PORT = 0
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
attr_accessor :worker_size, :specs_to_run, :completed_workers, :disconnections, :profiler
|
7
|
+
attr_reader :port, :clients
|
8
|
+
attr_accessor :tests_to_run, :example_size, :examples_complete, :profiler
|
14
9
|
|
15
|
-
def initialize
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
max_connections = 100,
|
20
|
-
stdlog = $stderr,
|
21
|
-
audit = true,
|
22
|
-
debug = true
|
23
|
-
)
|
24
|
-
@completed_workers = 0
|
25
|
-
@disconnections = 0
|
10
|
+
def initialize
|
11
|
+
@host = "0.0.0.0"
|
12
|
+
@server_socket = TCPServer.new(@host, RANDOM_PORT)
|
13
|
+
@port = @server_socket.addr[1]
|
26
14
|
@profiler = {}
|
27
|
-
|
15
|
+
@clients = {}
|
16
|
+
@tests_to_run = []
|
17
|
+
@example_size = 0
|
18
|
+
self.examples_complete = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def start
|
22
|
+
fds = [@server_socket]
|
23
|
+
catch(:stop) do
|
24
|
+
while true
|
25
|
+
reads = select(fds).first
|
26
|
+
reads.each do |socket_being_read|
|
27
|
+
if socket_being_read == @server_socket
|
28
|
+
client_socket = @server_socket.accept
|
29
|
+
fds << client_socket
|
30
|
+
clients[client_socket] = Connection.wrap(client_socket)
|
31
|
+
elsif socket_being_read.eof?
|
32
|
+
socket_being_read.close
|
33
|
+
fds.delete(socket_being_read)
|
34
|
+
clients.delete(socket_being_read)
|
35
|
+
disconnecting
|
36
|
+
else
|
37
|
+
serve(clients[socket_being_read])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
ensure
|
43
|
+
stopping
|
44
|
+
fds.each {|c| c.close}
|
45
|
+
end
|
46
|
+
|
47
|
+
def exit_status
|
48
|
+
reporters.all? {|r| r.exit_status == true}
|
28
49
|
end
|
29
50
|
|
51
|
+
protected
|
52
|
+
|
30
53
|
def serve(client)
|
31
|
-
|
32
|
-
|
33
|
-
|
54
|
+
data = load_object(client.gets(TERMINATOR))
|
55
|
+
case data
|
56
|
+
when String
|
57
|
+
$stdout.print data
|
58
|
+
$stdout.flush
|
59
|
+
when Array
|
60
|
+
send data.first, *(data[1..-1].unshift(client))
|
34
61
|
end
|
35
62
|
end
|
36
63
|
|
37
64
|
def ready(client)
|
38
|
-
|
39
|
-
|
40
|
-
client.flush
|
41
|
-
end
|
65
|
+
client.print tests_to_run.shift
|
66
|
+
client.flush
|
42
67
|
end
|
43
68
|
|
44
69
|
def done(client)
|
45
|
-
self.
|
70
|
+
self.examples_complete += 1
|
46
71
|
end
|
47
72
|
|
48
|
-
def
|
49
|
-
|
73
|
+
def tests=(client, tests)
|
74
|
+
self.tests_to_run = run_order(tests_to_run | tests)
|
75
|
+
self.example_size = tests_to_run.size
|
50
76
|
end
|
51
77
|
|
52
78
|
def rspec_summary=(client, summary)
|
@@ -62,39 +88,18 @@ module Specjour
|
|
62
88
|
self.profiler[test] = time
|
63
89
|
end
|
64
90
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
synchronize { self.disconnections += 1 }
|
69
|
-
if disconnections == worker_size
|
70
|
-
shutdown
|
71
|
-
stop unless Specjour.interrupted?
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def log(msg)
|
76
|
-
# noop
|
77
|
-
end
|
78
|
-
|
79
|
-
def error(exception)
|
80
|
-
Specjour.logger.debug "#{exception.inspect}\n#{exception.backtrace.join("\n")}"
|
81
|
-
end
|
82
|
-
|
83
|
-
def process(message, client)
|
84
|
-
if message.is_a?(String)
|
85
|
-
$stdout.print message
|
86
|
-
$stdout.flush
|
87
|
-
elsif message.is_a?(Array)
|
88
|
-
send(message.first, client, *message[1..-1])
|
91
|
+
def disconnecting
|
92
|
+
if (examples_complete == example_size || clients.empty?)
|
93
|
+
throw(:stop)
|
89
94
|
end
|
90
95
|
end
|
91
96
|
|
92
|
-
def run_order(
|
97
|
+
def run_order(tests)
|
93
98
|
if File.exist?('.specjour/performance')
|
94
|
-
|
95
|
-
(
|
99
|
+
ordered_tests = File.readlines('.specjour/performance').map {|l| l.chop.split(':', 2)[1]}
|
100
|
+
(tests - ordered_tests) | (ordered_tests & tests)
|
96
101
|
else
|
97
|
-
|
102
|
+
tests
|
98
103
|
end
|
99
104
|
end
|
100
105
|
|
@@ -120,29 +125,21 @@ module Specjour
|
|
120
125
|
|
121
126
|
def stopping
|
122
127
|
summarize_reports
|
123
|
-
warn_if_workers_deserted
|
124
128
|
record_performance unless Specjour.interrupted?
|
129
|
+
print_missing_tests if tests_to_run.any?
|
125
130
|
end
|
126
131
|
|
127
132
|
def summarize_reports
|
128
133
|
reporters.each {|r| r.summarize}
|
129
134
|
end
|
130
135
|
|
131
|
-
def
|
132
|
-
|
136
|
+
def print_missing_tests
|
137
|
+
puts "*" * 60
|
138
|
+
puts "Oops! The following tests were not run:"
|
139
|
+
puts "*" * 60
|
140
|
+
puts tests_to_run
|
141
|
+
puts "*" * 60
|
133
142
|
end
|
134
143
|
|
135
|
-
def warn_if_workers_deserted
|
136
|
-
if disconnections != completed_workers && !Specjour.interrupted?
|
137
|
-
puts
|
138
|
-
puts workers_deserted_message
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def workers_deserted_message
|
143
|
-
data = "* ERROR: NOT ALL WORKERS COMPLETED PROPERLY *"
|
144
|
-
filler = "*" * data.size
|
145
|
-
[filler, data, filler].join "\n"
|
146
|
-
end
|
147
144
|
end
|
148
145
|
end
|
@@ -42,11 +42,11 @@ module Specjour::RSpec
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def pending_examples
|
45
|
-
|
45
|
+
examples.select {|e| e.execution_result[:status] == 'pending'}
|
46
46
|
end
|
47
47
|
|
48
48
|
def failed_examples
|
49
|
-
|
49
|
+
examples.select {|e| e.execution_result[:status] == 'failed'}
|
50
50
|
end
|
51
51
|
|
52
52
|
def formatter
|
@@ -1,8 +1,13 @@
|
|
1
1
|
class Specjour::RSpec::Preloader
|
2
|
-
def self.load(
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
2
|
+
def self.load(paths=[])
|
3
|
+
require './spec/spec_helper'
|
4
|
+
load_spec_files paths
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.load_spec_files(paths)
|
8
|
+
options = ::RSpec::Core::ConfigurationOptions.new(paths)
|
9
|
+
options.parse_options
|
10
|
+
options.configure ::RSpec.configuration
|
11
|
+
::RSpec.configuration.load_spec_files
|
7
12
|
end
|
8
13
|
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
module Specjour::RSpec::Runner
|
2
|
+
::RSpec::Core::Runner::AT_EXIT_HOOK_BACKTRACE_LINE.replace "#{__FILE__}:#{__LINE__ + 3}:in `run'"
|
2
3
|
def self.run(spec, output)
|
3
|
-
reset
|
4
4
|
args = ['--format=Specjour::RSpec::DistributedFormatter', spec]
|
5
|
-
::RSpec::Core::Runner.
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
::RSpec.world.
|
10
|
-
::RSpec.
|
5
|
+
::RSpec::Core::Runner.run args, $stderr, output
|
6
|
+
ensure
|
7
|
+
::RSpec.configuration.filter_manager = ::RSpec::Core::FilterManager.new
|
8
|
+
::RSpec.world.filtered_examples.clear
|
9
|
+
::RSpec.world.inclusion_filter.clear
|
10
|
+
::RSpec.world.exclusion_filter.clear
|
11
|
+
::RSpec.world.send(:instance_variable_set, :@line_numbers, nil)
|
11
12
|
end
|
12
13
|
end
|
data/lib/specjour/rspec.rb
CHANGED
@@ -11,11 +11,6 @@ module Specjour
|
|
11
11
|
require 'specjour/rspec/shared_example_group_ext'
|
12
12
|
|
13
13
|
::RSpec::Core::Runner.disable_autorun!
|
14
|
-
|
15
|
-
def self.wants_to_quit
|
16
|
-
if defined?(::RSpec) && ::RSpec.respond_to?(:wants_to_quit=)
|
17
|
-
::RSpec.wants_to_quit = true
|
18
|
-
end
|
19
|
-
end
|
14
|
+
::RSpec::Core::Runner.class_eval "def self.trap_interrupt;end"
|
20
15
|
end
|
21
16
|
end
|
@@ -5,15 +5,16 @@ module Specjour
|
|
5
5
|
|
6
6
|
# Corresponds to the version of specjour that changed the configuration
|
7
7
|
# file.
|
8
|
-
CONFIG_VERSION = "0.
|
8
|
+
CONFIG_VERSION = "0.5.0".freeze
|
9
9
|
CONFIG_FILE_NAME = "rsyncd.conf"
|
10
10
|
PID_FILE_NAME = "rsyncd.pid"
|
11
11
|
|
12
|
-
attr_reader :project_path, :project_name
|
12
|
+
attr_reader :project_path, :project_name, :port
|
13
13
|
|
14
|
-
def initialize(project_path, project_name)
|
14
|
+
def initialize(project_path, project_name, port)
|
15
15
|
@project_path = project_path
|
16
16
|
@project_name = project_name
|
17
|
+
@port = port
|
17
18
|
end
|
18
19
|
|
19
20
|
def config_directory
|
@@ -35,11 +36,12 @@ module Specjour
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def start
|
39
|
+
Kernel.at_exit { stop }
|
38
40
|
write_config
|
39
41
|
Dir.chdir(project_path) do
|
40
42
|
Kernel.system *command
|
43
|
+
sleep 0.1
|
41
44
|
end
|
42
|
-
Kernel.at_exit { stop }
|
43
45
|
end
|
44
46
|
|
45
47
|
def stop
|
@@ -52,7 +54,7 @@ module Specjour
|
|
52
54
|
protected
|
53
55
|
|
54
56
|
def command
|
55
|
-
["rsync", "--daemon", "--config=#{config_file}", "--port
|
57
|
+
["rsync", "--daemon", "--config=#{config_file}", "--port=#{port}"]
|
56
58
|
end
|
57
59
|
|
58
60
|
def check_config_version
|
@@ -92,7 +94,7 @@ remove it, and re-run the dispatcher to generate the new config file.
|
|
92
94
|
# $ #{(command | ['--no-detach']).join(' ')}
|
93
95
|
#
|
94
96
|
# Rsync with the following command:
|
95
|
-
# $ rsync -a --port
|
97
|
+
# $ rsync -a --port=#{port} #{hostname}::#{project_name} /tmp/#{project_name}
|
96
98
|
#
|
97
99
|
use chroot = no
|
98
100
|
timeout = 20
|
@@ -101,7 +103,8 @@ pid file = ./.specjour/#{PID_FILE_NAME}
|
|
101
103
|
|
102
104
|
[#{project_name}]
|
103
105
|
path = .
|
104
|
-
|
106
|
+
include = tmp/cache/
|
107
|
+
exclude = .git* .specjour/rsync* doc/* tmp/* log/*
|
105
108
|
CONFIG
|
106
109
|
end
|
107
110
|
end
|