specjour 0.4.1 → 0.5.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/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
|