oop_rails_server 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/lib/oop_rails_server/helpers.rb +163 -0
- data/lib/oop_rails_server/rails_server.rb +378 -0
- data/lib/oop_rails_server/version.rb +3 -0
- data/lib/oop_rails_server.rb +3 -0
- data/oop_rails_server.gemspec +22 -0
- metadata +83 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b764225db8990e99a3727eec3d2252c3c9b857d9
|
4
|
+
data.tar.gz: 2ba96b68047a98c91fa77f39a050870cff565f59
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 86b2cfed985bf6457e069d085bb97e00a01cc52e3ae4d4331d737ba7d982a41e668797c0c926bf174061de04d7e80ea50d7e7846639ad4ce0be6ca0b8ebb8375
|
7
|
+
data.tar.gz: 02c1ed8ee642d24224e90e358576fb8184922f06797a029b357052bd5856dc5ea4f4d72e25400610c414593ea12758ca5535618512226cc1a569a1ac8c4beba6
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Andrew Geweke
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# OopRailsServer
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'oop_rails_server'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install oop_rails_server
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( https://github.com/[my-github-username]/oop_rails_server/fork )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'json'
|
3
|
+
require 'oop_rails_server/rails_server'
|
4
|
+
|
5
|
+
module OopRailsServer
|
6
|
+
module Helpers
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
attr_reader :rails_server
|
10
|
+
|
11
|
+
|
12
|
+
def full_path(subpath)
|
13
|
+
"#{rails_template_name}/#{subpath}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(subpath, options = { })
|
17
|
+
rails_server.get(full_path(subpath), options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_response(subpath, options = { })
|
21
|
+
rails_server.get_response(full_path(subpath), options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_success(subpath, options = { })
|
25
|
+
data = get(subpath, options)
|
26
|
+
data.should match(/rails_spec_application/i) unless options[:no_layout]
|
27
|
+
data
|
28
|
+
end
|
29
|
+
|
30
|
+
def expect_match(subpath, *args)
|
31
|
+
options = args.extract_options!
|
32
|
+
regexes = args
|
33
|
+
|
34
|
+
data = get_success(subpath, options)
|
35
|
+
regexes.each do |regex|
|
36
|
+
data.should match(regex)
|
37
|
+
end
|
38
|
+
|
39
|
+
data
|
40
|
+
end
|
41
|
+
|
42
|
+
def expect_exception(subpath, class_name, message)
|
43
|
+
data = get(subpath)
|
44
|
+
|
45
|
+
json = begin
|
46
|
+
JSON.parse(data)
|
47
|
+
rescue => e
|
48
|
+
raise %{Expected a JSON response from '#{subpath}' (because we expected an exception),
|
49
|
+
but we couldn't parse it as JSON; when we tried, we got:
|
50
|
+
|
51
|
+
(#{e.class.name}) #{e.message}
|
52
|
+
|
53
|
+
The data is:
|
54
|
+
|
55
|
+
#{data.inspect}}
|
56
|
+
end
|
57
|
+
|
58
|
+
json['exception'].should be
|
59
|
+
json['exception']['class'].should == class_name.to_s
|
60
|
+
json['exception']['message'].should match(message)
|
61
|
+
end
|
62
|
+
|
63
|
+
def rails_template_name
|
64
|
+
rails_server.name
|
65
|
+
end
|
66
|
+
|
67
|
+
def rails_server_project_root
|
68
|
+
raise %{You must override #rails_server_project_root in this class (#{self.class.name}) to use OopRailsServer::Helpers;
|
69
|
+
it should return the fully-qualified path to the root of your project (gem, application, or whatever).}
|
70
|
+
end
|
71
|
+
|
72
|
+
def rails_server_templates_root
|
73
|
+
@rails_server_templates_root ||= File.join(rails_server_project_root, "spec/rails/templates")
|
74
|
+
end
|
75
|
+
|
76
|
+
def rails_server_runtime_base_directory
|
77
|
+
@rails_server_runtime_base_directory ||= File.join(rails_server_project_root, "tmp/spec/rails")
|
78
|
+
end
|
79
|
+
|
80
|
+
def rails_server_additional_gemfile_lines
|
81
|
+
[
|
82
|
+
"gem 'fortitude', :path => '#{rails_server_project_root}'"
|
83
|
+
]
|
84
|
+
end
|
85
|
+
|
86
|
+
def rails_server_default_version
|
87
|
+
ENV['FORTITUDE_SPECS_RAILS_VERSION']
|
88
|
+
end
|
89
|
+
|
90
|
+
def rails_servers
|
91
|
+
@rails_servers ||= { }
|
92
|
+
end
|
93
|
+
|
94
|
+
def rails_server
|
95
|
+
if rails_servers.size == 1
|
96
|
+
rails_servers[rails_servers.keys.first]
|
97
|
+
elsif rails_servers.size == 0
|
98
|
+
raise "No Rails servers have been started!"
|
99
|
+
else
|
100
|
+
raise "Multiple Rails servers have been started; you must specify which one you want: #{rails_servers.keys.join(", ")}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def start_rails_server!(options = { })
|
105
|
+
templates = Array(options[:templates] || options[:name] || [ ])
|
106
|
+
raise "You must specify a template" unless templates.length >= 1
|
107
|
+
|
108
|
+
name = options[:name]
|
109
|
+
name ||= templates[0] if templates.length == 1
|
110
|
+
name = name.to_s.strip
|
111
|
+
raise "You must specify a name" unless name && name.to_s.strip.length > 0
|
112
|
+
|
113
|
+
server = rails_servers[name]
|
114
|
+
server ||= begin
|
115
|
+
templates = [ 'base' ] + templates unless options[:skip_base_template]
|
116
|
+
|
117
|
+
template_paths = templates.map do |t|
|
118
|
+
File.join(rails_server_templates_root, t.to_s)
|
119
|
+
end
|
120
|
+
|
121
|
+
additional_gemfile_lines = Array(rails_server_additional_gemfile_lines || [ ])
|
122
|
+
additional_gemfile_lines += Array(options[:additional_gemfile_lines] || [ ])
|
123
|
+
|
124
|
+
server = ::OopRailsServer::RailsServer.new(
|
125
|
+
:name => name, :template_paths => template_paths,
|
126
|
+
:runtime_base_directory => rails_server_runtime_base_directory,
|
127
|
+
:rails_version => (options[:rails_version] || rails_server_default_version),
|
128
|
+
:rails_env => options[:rails_env], :additional_gemfile_lines => additional_gemfile_lines)
|
129
|
+
|
130
|
+
rails_servers[name] = server
|
131
|
+
|
132
|
+
server
|
133
|
+
end
|
134
|
+
|
135
|
+
server.start!
|
136
|
+
end
|
137
|
+
|
138
|
+
def stop_rails_servers!
|
139
|
+
exceptions = [ ]
|
140
|
+
rails_servers.each do |name, server|
|
141
|
+
begin
|
142
|
+
server.stop!
|
143
|
+
rescue => e
|
144
|
+
exceptions << [ name, e ]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
raise "Unable to stop all Rails servers! Got:\n#{exceptions.join("\n")}" if exceptions.length > 0
|
149
|
+
end
|
150
|
+
|
151
|
+
module ClassMethods
|
152
|
+
def uses_rails_with_template(template_name, options = { })
|
153
|
+
before :all do
|
154
|
+
start_rails_server!({ :templates => [ template_name ] }.merge(options))
|
155
|
+
end
|
156
|
+
|
157
|
+
after :all do
|
158
|
+
stop_rails_servers!
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,378 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'find'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module OopRailsServer
|
7
|
+
class RailsServer
|
8
|
+
attr_reader :rails_root, :rails_version, :name
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
options.assert_valid_keys(
|
12
|
+
:name, :template_paths, :runtime_base_directory,
|
13
|
+
:rails_version, :rails_env, :additional_gemfile_lines
|
14
|
+
)
|
15
|
+
|
16
|
+
@name = options[:name] || raise(ArgumentError, "You must specify a name for the Rails server")
|
17
|
+
|
18
|
+
@template_paths = options[:template_paths] || raise(ArgumentError, "You must specify one or more template paths")
|
19
|
+
@template_paths = Array(@template_paths).map { |t| File.expand_path(t) }
|
20
|
+
|
21
|
+
@runtime_base_directory = options[:runtime_base_directory] || raise(ArgumentError, "You must specify a runtime_base_directory")
|
22
|
+
@runtime_base_directory = File.expand_path(@runtime_base_directory)
|
23
|
+
|
24
|
+
@rails_version = options[:rails_version] || :default
|
25
|
+
@rails_env = (options[:rails_env] || 'production').to_s
|
26
|
+
|
27
|
+
@additional_gemfile_lines = Array(options[:additional_gemfile_lines] || [ ])
|
28
|
+
|
29
|
+
|
30
|
+
@rails_root = File.join(@runtime_base_directory, rails_version.to_s, name.to_s)
|
31
|
+
@port = 20_000 + rand(10_000)
|
32
|
+
@server_pid = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
def start!
|
36
|
+
do_start! unless server_pid
|
37
|
+
end
|
38
|
+
|
39
|
+
def stop!
|
40
|
+
stop_server! if server_pid
|
41
|
+
end
|
42
|
+
|
43
|
+
def get(path, options = { })
|
44
|
+
get_response(path, options).body.strip
|
45
|
+
end
|
46
|
+
|
47
|
+
def uri_for(path)
|
48
|
+
uri_string = "http://localhost:#{@port}/#{path}"
|
49
|
+
URI.parse(uri_string)
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_response(path, options = { })
|
53
|
+
uri = uri_for(path)
|
54
|
+
data = Net::HTTP.get_response(uri)
|
55
|
+
unless data.code.to_s == '200' || options[:ignore_status_code]
|
56
|
+
raise "'#{uri}' returned #{data.code.inspect}, not 200; body was: #{data.body.strip}"
|
57
|
+
end
|
58
|
+
data
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
attr_reader :template_paths, :runtime_base_directory, :rails_env, :additional_gemfile_lines, :port, :server_pid
|
63
|
+
|
64
|
+
def do_start!
|
65
|
+
Bundler.with_clean_env do
|
66
|
+
with_rails_env do
|
67
|
+
setup_directories!
|
68
|
+
|
69
|
+
in_rails_root_parent do
|
70
|
+
splat_bootstrap_gemfile!
|
71
|
+
rails_new!
|
72
|
+
update_gemfile!
|
73
|
+
end
|
74
|
+
|
75
|
+
in_rails_root do
|
76
|
+
run_bundle_install!(:primary)
|
77
|
+
splat_template_files!
|
78
|
+
start_server!
|
79
|
+
verify_server!
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def with_rails_env
|
86
|
+
old_rails_env = ENV['RAILS_ENV']
|
87
|
+
begin
|
88
|
+
ENV['RAILS_ENV'] = rails_env
|
89
|
+
yield
|
90
|
+
ensure
|
91
|
+
ENV['RAILS_ENV'] = old_rails_env
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
def setup_directories!
|
97
|
+
return if @directories_setup
|
98
|
+
|
99
|
+
template_paths.each do |template_path|
|
100
|
+
raise Errno::ENOENT, "You must specify template paths that exist; this doesn't: '#{template_path}'" unless File.directory?(template_path)
|
101
|
+
end
|
102
|
+
FileUtils.rm_rf(rails_root) if File.exist?(rails_root)
|
103
|
+
FileUtils.mkdir_p(rails_root)
|
104
|
+
|
105
|
+
@directories_setup = true
|
106
|
+
end
|
107
|
+
|
108
|
+
def in_rails_root(&block)
|
109
|
+
Dir.chdir(rails_root, &block)
|
110
|
+
end
|
111
|
+
|
112
|
+
def in_rails_root_parent(&block)
|
113
|
+
Dir.chdir(File.dirname(rails_root), &block)
|
114
|
+
end
|
115
|
+
|
116
|
+
def splat_bootstrap_gemfile!
|
117
|
+
File.open("Gemfile", "w") do |f|
|
118
|
+
rails_version_spec = if rails_version == :default then "" else ", \"= #{rails_version}\"" end
|
119
|
+
f << <<-EOS
|
120
|
+
source 'https://rubygems.org'
|
121
|
+
|
122
|
+
gem 'rails'#{rails_version_spec}
|
123
|
+
EOS
|
124
|
+
end
|
125
|
+
|
126
|
+
run_bundle_install!(:bootstrap)
|
127
|
+
end
|
128
|
+
|
129
|
+
def rails_new!
|
130
|
+
# This is a little trick to specify the exact version of Rails you want to create it with...
|
131
|
+
# http://stackoverflow.com/questions/379141/specifying-rails-version-to-use-when-creating-a-new-application
|
132
|
+
rails_version_spec = rails_version == :default ? "" : "_#{rails_version}_"
|
133
|
+
cmd = "bundle exec rails #{rails_version_spec} new #{File.basename(rails_root)} -d sqlite3 -f -B"
|
134
|
+
safe_system(cmd, "creating a new Rails installation for '#{name}'")
|
135
|
+
end
|
136
|
+
|
137
|
+
def update_gemfile!
|
138
|
+
gemfile = File.join(rails_root, 'Gemfile')
|
139
|
+
gemfile_contents = File.read(gemfile)
|
140
|
+
|
141
|
+
# Since Rails 3.0.20 was released, a new version of the I18n gem, 0.5.2, was released that moves a constant
|
142
|
+
# into a different namespace. (See https://github.com/mislav/will_paginate/issues/347 for more details.)
|
143
|
+
# So, if we're running Rails 3.0.x, we lock the 'i18n' gem to an earlier version.
|
144
|
+
gemfile_contents << "\ngem 'i18n', '= 0.5.0'\n" if rails_version && rails_version =~ /^3\.0\./
|
145
|
+
|
146
|
+
# Apparently execjs released a version 2.2.0 that will happily install on Ruby 1.8.7, but which contains some
|
147
|
+
# new-style hash syntax. As a result, we pin the version backwards in this one specific case.
|
148
|
+
gemfile_contents << "\ngem 'execjs', '~> 2.0.0'\n" if RUBY_VERSION =~ /^1\.8\./
|
149
|
+
|
150
|
+
gemfile_contents << additional_gemfile_lines.join("\n")
|
151
|
+
|
152
|
+
File.open(gemfile, 'w') { |f| f << gemfile_contents }
|
153
|
+
end
|
154
|
+
|
155
|
+
def with_env(new_env)
|
156
|
+
old_env = { }
|
157
|
+
new_env.keys.each { |k| old_env[k] = ENV[k] }
|
158
|
+
|
159
|
+
begin
|
160
|
+
set_env(new_env)
|
161
|
+
yield
|
162
|
+
ensure
|
163
|
+
set_env(old_env)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def set_env(new_env)
|
168
|
+
new_env.each do |k,v|
|
169
|
+
if v
|
170
|
+
ENV[k] = v
|
171
|
+
else
|
172
|
+
ENV.delete(k)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def splat_template_files!
|
178
|
+
@template_paths.each do |template_path|
|
179
|
+
Find.find(template_path) do |file|
|
180
|
+
next unless File.file?(file)
|
181
|
+
|
182
|
+
if file[0..(template_path.length)] == "#{template_path}/"
|
183
|
+
subpath = file[(template_path.length + 1)..-1]
|
184
|
+
else
|
185
|
+
raise "#{file} isn't under #{template_path}?!?"
|
186
|
+
end
|
187
|
+
dest_file = File.join(rails_root, subpath)
|
188
|
+
|
189
|
+
FileUtils.mkdir_p(File.dirname(dest_file))
|
190
|
+
FileUtils.cp(file, dest_file)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def start_server!
|
196
|
+
output = File.join(rails_root, 'log', 'rails-server.out')
|
197
|
+
cmd = "rails server -p #{port} > '#{output}'"
|
198
|
+
safe_system(cmd, "starting 'rails server' on port #{port}", :background => true)
|
199
|
+
|
200
|
+
server_pid_file = File.join(rails_root, 'tmp', 'pids', 'server.pid')
|
201
|
+
|
202
|
+
start_time = Time.now
|
203
|
+
while Time.now < start_time + 15
|
204
|
+
if File.exist?(server_pid_file)
|
205
|
+
server_pid = File.read(server_pid_file).strip
|
206
|
+
if server_pid =~ /^(\d{1,10})$/i
|
207
|
+
@server_pid = Integer(server_pid)
|
208
|
+
break
|
209
|
+
end
|
210
|
+
end
|
211
|
+
sleep 0.1
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def verify_server!
|
216
|
+
server_verify_url = "http://localhost:#{port}/working/rails_is_working"
|
217
|
+
uri = URI.parse(server_verify_url)
|
218
|
+
|
219
|
+
data = nil
|
220
|
+
start_time = Time.now
|
221
|
+
while (! data)
|
222
|
+
begin
|
223
|
+
data = Net::HTTP.get_response(uri)
|
224
|
+
rescue Errno::ECONNREFUSED, EOFError
|
225
|
+
raise if Time.now > (start_time + 20)
|
226
|
+
# keep waiting
|
227
|
+
sleep 0.1
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
unless data.code.to_s == '200'
|
232
|
+
raise "'#{server_verify_url}' returned #{data.code.inspect}, not 200"
|
233
|
+
end
|
234
|
+
result = data.body.strip
|
235
|
+
|
236
|
+
unless result =~ /^Rails\s+version\s*:\s*(\d+\.\d+\.\d+)$/
|
237
|
+
raise "'#{server_verify_url}' returned: #{result.inspect}"
|
238
|
+
end
|
239
|
+
actual_version = $1
|
240
|
+
|
241
|
+
if rails_version != :default && (actual_version != rails_version)
|
242
|
+
raise "We seem to have spawned the wrong version of Rails; wanted: #{rails_version.inspect} but got: #{actual_version.inspect}"
|
243
|
+
end
|
244
|
+
|
245
|
+
say "Successfully spawned a server running Rails #{actual_version} on port #{port}."
|
246
|
+
end
|
247
|
+
|
248
|
+
def is_alive?(pid)
|
249
|
+
cmd = "ps -o pid #{pid}"
|
250
|
+
results = `#{cmd}`
|
251
|
+
results.split(/[\r\n]+/).each do |line|
|
252
|
+
line = line.strip.downcase
|
253
|
+
next if line == 'pid'
|
254
|
+
if line =~ /^\d+$/i
|
255
|
+
return true if Integer(line) == pid
|
256
|
+
else
|
257
|
+
raise "Unexpected output from '#{cmd}': #{results}"
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
false
|
262
|
+
end
|
263
|
+
|
264
|
+
def stop_server!
|
265
|
+
# We do this because under 1.8.7 SIGTERM doesn't seem to work, and it's actually fine to slaughter this
|
266
|
+
# process mercilessly -- we don't need anything it has at this point, anyway.
|
267
|
+
Process.kill("KILL", server_pid)
|
268
|
+
|
269
|
+
start_time = Time.now
|
270
|
+
|
271
|
+
while true
|
272
|
+
if is_alive?(server_pid)
|
273
|
+
raise "Unable to kill server at PID #{server_pid}!" if (Time.now - start_time) > 20
|
274
|
+
say "Waiting for server at PID #{server_pid} to die."
|
275
|
+
sleep 0.1
|
276
|
+
else
|
277
|
+
break
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
say "Successfully terminated Rails server at PID #{server_pid}."
|
282
|
+
|
283
|
+
@server_pid = nil
|
284
|
+
end
|
285
|
+
|
286
|
+
class CommandFailedError < StandardError
|
287
|
+
attr_reader :directory, :command, :result, :output
|
288
|
+
|
289
|
+
def initialize(directory, command, result, output)
|
290
|
+
@directory = directory
|
291
|
+
@command = command
|
292
|
+
@result = result
|
293
|
+
@output = output
|
294
|
+
|
295
|
+
super(%{Command failed: in directory '#{directory}', we tried to run:
|
296
|
+
% #{command}
|
297
|
+
but got result: #{result.inspect}
|
298
|
+
and output:
|
299
|
+
#{output}})
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def attempt_bundle_install_cmd!(name, use_local)
|
304
|
+
cmd = "bundle install"
|
305
|
+
cmd << " --local" if use_local
|
306
|
+
|
307
|
+
description = "running 'bundle install' for #{name.inspect}"
|
308
|
+
description << " (with remote fetching allowed)" if (! use_local)
|
309
|
+
|
310
|
+
attempts = 0
|
311
|
+
while true
|
312
|
+
begin
|
313
|
+
safe_system(cmd, description)
|
314
|
+
break
|
315
|
+
rescue CommandFailedError => cfe
|
316
|
+
# Sigh. Travis CI sometimes fails this with the following exception:
|
317
|
+
#
|
318
|
+
# Gem::RemoteFetcher::FetchError: Errno::ETIMEDOUT: Connection timed out - connect(2)
|
319
|
+
#
|
320
|
+
# So, we catch the command failure, look to see if this is the problem, and, if so, retry
|
321
|
+
raise if (! is_travis_remote_fetcher_error?(cfe)) || attempts >= 5
|
322
|
+
attempts += 1
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
def is_travis_remote_fetcher_error?(command_failed_error)
|
328
|
+
command_failed_error.output =~ /Gem::RemoteFetcher::FetchError.*connect/i
|
329
|
+
end
|
330
|
+
|
331
|
+
def is_remote_flag_required_error?(command_failed_error)
|
332
|
+
command_failed_error.output =~ /could\s+not\s+find.*in\s+the\s+gems\s+available\s+on\s+this\s+machine/i
|
333
|
+
end
|
334
|
+
|
335
|
+
def do_bundle_install!(name, allow_remote)
|
336
|
+
begin
|
337
|
+
attempt_bundle_install_cmd!(name, true)
|
338
|
+
rescue CommandFailedError => cfe
|
339
|
+
if is_remote_flag_required_error?(cfe) && allow_remote
|
340
|
+
attempt_bundle_install_cmd!(name, false)
|
341
|
+
else
|
342
|
+
raise
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def run_bundle_install!(name)
|
348
|
+
@bundle_installs_run ||= { }
|
349
|
+
do_bundle_install!(name, ! @bundle_installs_run[name])
|
350
|
+
@bundle_installs_run[name] ||= true
|
351
|
+
end
|
352
|
+
|
353
|
+
def say(s, newline = true)
|
354
|
+
if newline
|
355
|
+
$stdout.puts s
|
356
|
+
else
|
357
|
+
$stdout << s
|
358
|
+
end
|
359
|
+
$stdout.flush
|
360
|
+
end
|
361
|
+
|
362
|
+
def safe_system(cmd, notice = nil, options = { })
|
363
|
+
say("#{notice}...", false) if notice
|
364
|
+
|
365
|
+
total_cmd = if options[:background]
|
366
|
+
"#{cmd} 2>&1 &"
|
367
|
+
else
|
368
|
+
"#{cmd} 2>&1"
|
369
|
+
end
|
370
|
+
|
371
|
+
output = `#{total_cmd}`
|
372
|
+
raise CommandFailedError.new(Dir.pwd, total_cmd, $?, output) unless $?.success?
|
373
|
+
say "OK" if notice
|
374
|
+
|
375
|
+
output
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'oop_rails_server/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "oop_rails_server"
|
8
|
+
spec.version = OopRailsServer::VERSION
|
9
|
+
spec.authors = ["Andrew Geweke"]
|
10
|
+
spec.email = ["andrew@geweke.org"]
|
11
|
+
spec.summary = %q{Reliably runs a Rails server in a separate process, for use in tests, utilities, etc.}
|
12
|
+
spec.homepage = "https://github.com/ageweke/oop_rails_server"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oop_rails_server
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Geweke
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
- andrew@geweke.org
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".gitignore"
|
49
|
+
- Gemfile
|
50
|
+
- LICENSE.txt
|
51
|
+
- README.md
|
52
|
+
- Rakefile
|
53
|
+
- lib/oop_rails_server.rb
|
54
|
+
- lib/oop_rails_server/helpers.rb
|
55
|
+
- lib/oop_rails_server/rails_server.rb
|
56
|
+
- lib/oop_rails_server/version.rb
|
57
|
+
- oop_rails_server.gemspec
|
58
|
+
homepage: https://github.com/ageweke/oop_rails_server
|
59
|
+
licenses:
|
60
|
+
- MIT
|
61
|
+
metadata: {}
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
requirements: []
|
77
|
+
rubyforge_project:
|
78
|
+
rubygems_version: 2.2.2
|
79
|
+
signing_key:
|
80
|
+
specification_version: 4
|
81
|
+
summary: Reliably runs a Rails server in a separate process, for use in tests, utilities,
|
82
|
+
etc.
|
83
|
+
test_files: []
|