rails_build 1.0.0 → 2.4.2
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 +5 -5
- data/LICENSE +1 -0
- data/README.md +70 -124
- data/Rakefile +437 -22
- data/bin/rails_build +848 -659
- data/config/rails_build.rb +33 -0
- data/lib/rails_build/_lib.rb +87 -0
- data/lib/rails_build.rb +189 -16
- data/rails_build.gemspec +42 -0
- metadata +34 -75
- data/MIT-LICENSE +0 -20
- data/app/assets/config/rails_build_manifest.js +0 -2
- data/app/assets/javascripts/rails_build/application.js +0 -13
- data/app/assets/stylesheets/rails_build/application.css +0 -32
- data/app/controllers/rails_build/application_controller.rb +0 -12
- data/app/helpers/rails_build/application_helper.rb +0 -4
- data/app/jobs/rails_build/application_job.rb +0 -4
- data/app/mailers/rails_build/application_mailer.rb +0 -6
- data/app/models/rails_build/application_record.rb +0 -5
- data/app/views/layouts/rails_build/application.html.erb +0 -14
- data/app/views/rails_build/application/index.html.erb +0 -20
- data/bin/rails +0 -13
- data/config/routes.rb +0 -10
- data/lib/rails_build/engine.rb +0 -50
- data/lib/rails_build/version.rb +0 -3
- data/lib/tasks/rails_build_tasks.rake +0 -31
data/bin/rails_build
CHANGED
@@ -1,197 +1,154 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# file : ./bin/rails_build
|
4
|
-
|
5
|
-
END{
|
6
|
-
|
7
|
-
RailsBuild::CLI.build!
|
8
|
-
|
9
|
-
}
|
10
|
-
|
2
|
+
# encoding: utf-8
|
11
3
|
|
12
4
|
module RailsBuild
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
5
|
+
class CLI
|
6
|
+
def CLI.usage
|
7
|
+
<<~__
|
8
|
+
NAME
|
9
|
+
rails_build
|
18
10
|
|
19
|
-
|
20
|
-
a small, simple, bullet proof, and
|
11
|
+
SYNOPSIS
|
12
|
+
a small, simple, bullet proof, and fast enough static site generator built on top of the rails you already know and love
|
21
13
|
|
22
14
|
USAGE
|
23
|
-
rails_build
|
15
|
+
rails_build *(options)
|
24
16
|
|
25
17
|
options:
|
26
18
|
--help, -h : this message
|
27
|
-
--
|
28
|
-
--parallel,--p : how many requests to make in parallel, default=n_cpus
|
19
|
+
--init, -i : initialize ./config/rails_build.rb
|
20
|
+
--parallel,--p : how many requests to make in parallel, default=n_cpus-1
|
29
21
|
--env,--e : speciify the RAILS_ENV, default=production
|
30
|
-
--
|
22
|
+
--url, -u : provide the url of the build server, do *not* start separate one
|
31
23
|
--log, -l : specify the logfile, default=STDERR
|
32
24
|
--verbose, -v : turn on verbose logging
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
def CLI.opts
|
37
|
-
GetoptLong.new(
|
38
|
-
[ '--help' , '-h' , GetoptLong::NO_ARGUMENT ] ,
|
39
|
-
[ '--server' , '-s' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
40
|
-
[ '--parallel' , '-p' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
41
|
-
[ '--rails_root' , '-r' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
42
|
-
[ '--env' , '-e' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
43
|
-
[ '--log' , '-l' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
44
|
-
[ '--verbose' , '-v' , GetoptLong::NO_ARGUMENT ] ,
|
45
|
-
)
|
46
|
-
end
|
47
|
-
|
48
|
-
def build!
|
49
|
-
prepare!
|
50
|
-
|
51
|
-
mkdir!
|
25
|
+
__
|
26
|
+
end
|
52
27
|
|
53
|
-
|
28
|
+
def CLI.opts
|
29
|
+
GetoptLong.new(
|
30
|
+
[ '--help' , '-h' , GetoptLong::NO_ARGUMENT ] ,
|
31
|
+
[ '--init' , '-i' , GetoptLong::NO_ARGUMENT ] ,
|
32
|
+
[ '--parallel' , '-p' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
33
|
+
[ '--env' , '-e' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
34
|
+
[ '--url' , '-u' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
35
|
+
[ '--server' , '-s' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
36
|
+
[ '--log' , '-l' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
37
|
+
[ '--verbose' , '-v' , GetoptLong::NO_ARGUMENT ] ,
|
38
|
+
)
|
39
|
+
end
|
54
40
|
|
55
|
-
|
41
|
+
def run!
|
42
|
+
@args = parse_args!
|
43
|
+
@opts = parse_opts!
|
56
44
|
|
57
|
-
|
45
|
+
case
|
46
|
+
when @args[0] == 'help' || @opts[:help]
|
47
|
+
usage!
|
58
48
|
|
59
|
-
|
49
|
+
when @args[0] == 'init' || @opts[:init]
|
50
|
+
init!
|
60
51
|
|
61
|
-
|
52
|
+
else
|
53
|
+
if @args.empty?
|
54
|
+
build!
|
55
|
+
else
|
56
|
+
usage!
|
57
|
+
exit(42)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
62
61
|
|
63
|
-
|
62
|
+
def build!
|
63
|
+
prepare!
|
64
64
|
|
65
|
-
|
66
|
-
end
|
65
|
+
load_config!
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
67
|
+
unless url
|
68
|
+
clear_cache!
|
69
|
+
start_server!
|
70
|
+
end
|
72
71
|
|
73
|
-
|
74
|
-
attr_accessor :rails_root
|
75
|
-
attr_accessor :server
|
76
|
-
attr_accessor :directory
|
77
|
-
attr_accessor :uuid
|
78
|
-
attr_accessor :id
|
79
|
-
attr_accessor :env
|
80
|
-
attr_accessor :puma
|
81
|
-
attr_accessor :passenger
|
82
|
-
attr_accessor :url
|
72
|
+
extract_urls!
|
83
73
|
|
84
|
-
|
85
|
-
def initialize(*args, &block)
|
86
|
-
setup!
|
74
|
+
precompile_assets!
|
87
75
|
|
88
|
-
|
76
|
+
rsync_public!
|
89
77
|
|
90
|
-
|
78
|
+
parallel_build!
|
91
79
|
|
92
|
-
|
93
|
-
|
94
|
-
exit(42)
|
95
|
-
end
|
96
|
-
end
|
80
|
+
finalize!
|
81
|
+
end
|
97
82
|
|
98
83
|
#
|
99
|
-
def
|
100
|
-
|
101
|
-
STDOUT.sync = true
|
102
|
-
STDERR.sync = true
|
103
|
-
|
104
|
-
#
|
105
|
-
ENV['SPRING_DISABLE'] = 'true'
|
106
|
-
ENV['DISABLE_SPRING'] = 'true'
|
107
|
-
|
108
|
-
#
|
109
|
-
%w[
|
110
|
-
fileutils pathname thread socket timeout time uri etc open-uri securerandom logger getoptlong rubygems json
|
111
|
-
].each do |stdlib|
|
112
|
-
require(stdlib)
|
113
|
-
end
|
84
|
+
def CLI.run!(*args, &block)
|
85
|
+
new(*args, &block).run!
|
114
86
|
end
|
115
87
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
88
|
+
#
|
89
|
+
attr_accessor :rails_root
|
90
|
+
attr_accessor :url
|
91
|
+
attr_accessor :server
|
92
|
+
attr_accessor :directory
|
93
|
+
attr_accessor :uuid
|
94
|
+
attr_accessor :id
|
95
|
+
attr_accessor :env
|
96
|
+
attr_accessor :parallel
|
120
97
|
|
98
|
+
#
|
99
|
+
def prepare!
|
121
100
|
#
|
122
|
-
|
101
|
+
@rails_root = find_rails_root!
|
123
102
|
|
124
103
|
#
|
125
|
-
|
126
|
-
require 'bundler/setup'
|
127
|
-
Bundler.setup(:require => false)
|
128
|
-
end
|
129
|
-
|
130
|
-
#
|
131
|
-
%w[
|
132
|
-
threadify persistent_http phusion_passenger
|
133
|
-
].each do |gem|
|
134
|
-
begin
|
135
|
-
require(gem)
|
136
|
-
rescue LoadError
|
137
|
-
abort "add gem 'rails_build' to your Gemfile"
|
138
|
-
end
|
139
|
-
end
|
104
|
+
Dir.chdir(@rails_root)
|
140
105
|
|
141
106
|
#
|
142
|
-
|
143
|
-
require('pry')
|
144
|
-
rescue LoadError
|
145
|
-
nil
|
146
|
-
end
|
107
|
+
@logger = Logger.new(@opts[:log] || STDERR)
|
147
108
|
|
148
|
-
|
149
|
-
|
109
|
+
@env = @opts[:env] || ENV['RAILS_BUILD_ENV'] || ENV['RAILS_ENV']
|
110
|
+
@url = @opts[:url] || ENV['RAILS_BUILD_URL']
|
111
|
+
@parallel = @opts[:parallel] || ENV['RAILS_BUILD_PARALLEL']
|
112
|
+
@verbose = @opts[:verbose] || ENV['RAILS_BUILD_VERBOSE']
|
150
113
|
|
151
|
-
|
152
|
-
|
153
|
-
@server = @opts[:server] || ENV['RAILS_BUILD_SERVER']
|
154
|
-
@env = @opts[:env] || ENV['RAILS_BUILD_ENV'] || ENV['RAILS_ENV']
|
155
|
-
@parallel = @opts[:parallel] || ENV['RAILS_BUILD_PARALLEL']
|
156
|
-
@verbose = @opts[:verbose] || ENV['RAILS_BUILD_VERBOSE']
|
114
|
+
@uuid = ENV['RAILS_BUILD_UUID']
|
115
|
+
@time = ENV['RAILS_BUILD_TIME']
|
157
116
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
117
|
+
@env ||= 'production'
|
118
|
+
@parallel ||= (Etc.nprocessors - 1)
|
119
|
+
@uuid ||= SecureRandom.uuid
|
120
|
+
@time ||= Time.now.utc
|
162
121
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
@parallel = @parallel.to_i
|
122
|
+
unless @time.is_a?(Time)
|
123
|
+
@time = Time.parse(@time.to_s).utc
|
124
|
+
end
|
168
125
|
|
126
|
+
@parallel = @parallel.to_i
|
169
127
|
|
170
|
-
|
171
|
-
|
128
|
+
if ENV['RAILS_BUILD_DIRECTORY']
|
129
|
+
@build_directory = File.expand_path(ENV['RAILS_BUILD_DIRECTORY'])
|
130
|
+
else
|
131
|
+
@build_directory = File.join(@rails_root, 'builds')
|
132
|
+
end
|
172
133
|
|
173
|
-
|
134
|
+
@directory = File.join(@build_directory, @uuid)
|
174
135
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
end
|
136
|
+
ENV['RAILS_ENV'] = @env
|
137
|
+
ENV['RAILS_BUILD'] = @uuid
|
138
|
+
ENV['RAILS_BUILD_ENV'] = @env
|
139
|
+
ENV['RAILS_BUILD_TIME'] = @time.httpdate
|
180
140
|
|
181
|
-
|
141
|
+
@urls = []
|
182
142
|
|
183
|
-
|
184
|
-
ENV['RAILS_BUILD'] = @uuid
|
185
|
-
ENV['RAILS_BUILD_ENV'] = @env
|
186
|
-
ENV['RAILS_BUILD_TIME'] = @time.httpdate
|
143
|
+
@started_at = Time.now
|
187
144
|
|
188
|
-
|
145
|
+
mkdir!
|
189
146
|
|
190
|
-
|
191
|
-
|
147
|
+
@server = Server.new(cli: self)
|
148
|
+
end
|
192
149
|
|
193
150
|
#
|
194
|
-
def find_rails_root!(path)
|
151
|
+
def find_rails_root!(path = '.')
|
195
152
|
rails_root = File.expand_path(path.to_s)
|
196
153
|
|
197
154
|
loop do
|
@@ -208,523 +165,755 @@ module RailsBuild
|
|
208
165
|
abort("could not find a rails_root in or above #{ path }!?")
|
209
166
|
end
|
210
167
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
168
|
+
#
|
169
|
+
def parse_args!
|
170
|
+
@args = ARGV.map{|arg| "#{ arg }"}
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
def parse_opts!
|
175
|
+
@opts = Hash.new
|
176
|
+
|
177
|
+
CLI.opts.each do |opt, arg|
|
178
|
+
key, val = opt.split('--').last, arg
|
179
|
+
@opts[key.to_s.to_sym] = (val == '' ? true : val)
|
180
|
+
end
|
181
|
+
|
182
|
+
@opts
|
183
|
+
end
|
184
|
+
|
185
|
+
#
|
186
|
+
def usage!
|
187
|
+
lines = CLI.usage.strip.split(/\n/)
|
188
|
+
n = lines[1].to_s.scan(/^\s+/).size
|
189
|
+
indent = ' ' * n
|
190
|
+
re = /^#{ Regexp.escape(indent) }/
|
191
|
+
usage = lines.map{|line| line.gsub(re, '')}.join("\n")
|
192
|
+
STDERR.puts(usage)
|
193
|
+
end
|
194
|
+
|
195
|
+
#
|
196
|
+
def init!
|
197
|
+
config = DATA.read.strip
|
198
|
+
|
199
|
+
path = './config/rails_build.rb'
|
200
|
+
|
201
|
+
FileUtils.mkdir_p(File.dirname(path))
|
202
|
+
|
203
|
+
IO.binwrite(path, config)
|
204
|
+
|
205
|
+
STDERR.puts("please review #{ path } before running `rails_build`")
|
206
|
+
end
|
207
|
+
|
208
|
+
#
|
209
|
+
def mkdir!
|
210
|
+
FileUtils.rm_rf(@directory)
|
211
|
+
FileUtils.mkdir_p(@directory)
|
212
|
+
|
213
|
+
log(:info, "build: #{ @directory }")
|
214
|
+
end
|
215
|
+
|
216
|
+
#
|
217
|
+
def start_server!
|
218
|
+
@url =
|
219
|
+
nil
|
220
|
+
|
221
|
+
@port =
|
222
|
+
nil
|
223
|
+
|
224
|
+
ports =
|
225
|
+
(2000 .. 9000).to_a
|
226
|
+
|
227
|
+
ports.each do |port|
|
228
|
+
next unless port_open?(port)
|
229
|
+
|
230
|
+
@server.start!(port:)
|
231
|
+
|
232
|
+
timeout = 11
|
233
|
+
t = Time.now.to_f
|
234
|
+
i = 0
|
235
|
+
|
236
|
+
@proto = @config.fetch('force_ssl') ? 'https' : 'http'
|
237
|
+
url = nil
|
238
|
+
|
239
|
+
loop do
|
240
|
+
i += 1
|
241
|
+
sleep(rand(0.42))
|
242
|
+
|
243
|
+
begin
|
244
|
+
raise if port_open?(port)
|
245
|
+
url = "#{ @proto }://0.0.0.0:#{ port }"
|
246
|
+
@url = url
|
247
|
+
@port = port
|
248
|
+
break
|
249
|
+
rescue Object => e
|
250
|
+
if((Time.now.to_f - t) > timeout)
|
251
|
+
abort("could not start server inside of #{ timeout } seconds")
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
break if @url
|
257
|
+
end
|
258
|
+
|
259
|
+
# barf if server could not be started
|
260
|
+
#
|
261
|
+
unless @url
|
262
|
+
abort("could not start server on any of ports #{ ports.first } .. #{ ports.last }")
|
263
|
+
else
|
264
|
+
log(:info, "url: #{ @url }")
|
265
|
+
end
|
266
|
+
|
267
|
+
#
|
268
|
+
@started_at = Time.now
|
269
|
+
@url
|
270
|
+
end
|
271
|
+
|
272
|
+
#
|
273
|
+
def load_config!
|
274
|
+
unless test(?s, RailsBuild.config_path)
|
275
|
+
log(:error, "no config found in #{ RailsBuild.config_path }")
|
276
|
+
abort
|
277
|
+
end
|
278
|
+
|
279
|
+
Tempfile.open do |tmp|
|
280
|
+
env = {RAILS_ENV:@env, RAILS_BUILD_CONFIG_DUMP:tmp.path}
|
281
|
+
spawn('rails', 'runner', 'RailsBuild.dump_config!', env:)
|
282
|
+
json = IO.binread(tmp.path)
|
283
|
+
hash = JSON.parse(json)
|
284
|
+
|
285
|
+
@config = Configuration.new(hash)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
def extract_urls!
|
290
|
+
path = @config.path
|
291
|
+
urls = @config.urls
|
292
|
+
|
293
|
+
if urls.size == 0
|
294
|
+
abort("failed to find any rails_build urls in:\n#{ @config.to_json }")
|
295
|
+
end
|
296
|
+
|
297
|
+
urls.map!{|url| url_for(url)}
|
298
|
+
|
299
|
+
log(:info, "extracted #{ urls.size } url(s) to build from #{ path }")
|
300
|
+
|
301
|
+
@urls = urls
|
302
|
+
end
|
303
|
+
|
304
|
+
#
|
305
|
+
def clear_cache!
|
306
|
+
spawn "rails tmp:cache:clear", error: false
|
307
|
+
spawn "rails runner 'Rails.cache.clear'", error: false
|
308
|
+
end
|
309
|
+
|
310
|
+
#
|
311
|
+
def precompile_assets!
|
312
|
+
@asset_dir = File.join(@rails_root, "public/assets")
|
313
|
+
@asset_tmp = false
|
314
|
+
|
315
|
+
if test(?d, @asset_dir)
|
316
|
+
@asset_tmp = File.join(@rails_root, "tmp/assets-build-#{ @uuid }")
|
317
|
+
FileUtils.mv(@asset_dir, @asset_tmp)
|
318
|
+
end
|
319
|
+
|
320
|
+
spawn "RAILS_ENV=production DISABLE_SPRING=true rake assets:precompile"
|
321
|
+
|
322
|
+
assets = Dir.glob(File.join(@rails_root, 'public/assets/**/**'))
|
323
|
+
|
324
|
+
log(:info, "precompiled #{ assets.size } assets")
|
325
|
+
|
326
|
+
ensure_non_digested_assets_also_exist!(assets)
|
327
|
+
end
|
328
|
+
|
329
|
+
#
|
330
|
+
def rsync_public!
|
331
|
+
commands = [
|
332
|
+
"rsync -avz ./public/ #{ @directory }",
|
333
|
+
"cp -ru ./public/ #{ @directory }",
|
334
|
+
proc{ FileUtils.cp_r('./public', @directory) }
|
335
|
+
]
|
336
|
+
|
337
|
+
rsynced = false
|
338
|
+
|
339
|
+
commands.each do |command|
|
340
|
+
begin
|
341
|
+
spawn(command)
|
342
|
+
rsynced = true
|
343
|
+
break
|
344
|
+
rescue
|
345
|
+
next
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
unless rsynced
|
350
|
+
abort "failed to rsync ./public to `#{ @directory }`"
|
351
|
+
end
|
352
|
+
|
353
|
+
count = 0
|
354
|
+
Dir.glob(File.join(@directory, '**/**')).each{ count += 1 }
|
263
355
|
|
264
|
-
|
356
|
+
log(:info, "rsync'd #{ count } files")
|
265
357
|
|
266
|
-
|
267
|
-
|
358
|
+
if @asset_tmp
|
359
|
+
FileUtils.rm_rf(@asset_dir)
|
360
|
+
FileUtils.mv(@asset_tmp, @asset_dir)
|
361
|
+
end
|
362
|
+
end
|
268
363
|
|
269
|
-
#
|
364
|
+
#
|
270
365
|
=begin
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
366
|
+
def parallel_build!
|
367
|
+
size = @parallel
|
368
|
+
|
369
|
+
stats = {
|
370
|
+
:success => [],
|
371
|
+
:missing => [],
|
372
|
+
:failure => [],
|
373
|
+
}
|
374
|
+
|
375
|
+
times = []
|
376
|
+
|
377
|
+
elapsed = timing do
|
378
|
+
ThreadPool.new(size:) do |tp|
|
379
|
+
tp.run do
|
380
|
+
@urls.each{|url| tp.process!(url:)}
|
381
|
+
end
|
382
|
+
|
383
|
+
tp.process do |url:|
|
384
|
+
uri = uri_for(url)
|
385
|
+
path = path_for(uri)
|
386
|
+
|
387
|
+
upath = uri.path
|
388
|
+
rpath = relative_path(path, :from => @directory)
|
389
|
+
|
390
|
+
code = nil
|
391
|
+
body = nil
|
392
|
+
|
393
|
+
time =
|
394
|
+
timing do
|
395
|
+
code, body = http_get(uri)
|
396
|
+
write_path(path, body) if code == 200
|
397
|
+
end
|
398
|
+
|
399
|
+
tp.success!(url:, rpath:, time:, code:)
|
400
|
+
end
|
401
|
+
|
402
|
+
tp.success do |url:, rpath:, time:, code:|
|
403
|
+
times.push(time)
|
404
|
+
rps = (times.size / times.sum).round(4)
|
405
|
+
msg = "#{ url } -> /#{ rpath } (time:#{ time }, rps:#{ rps }, code:#{ code })"
|
406
|
+
|
407
|
+
case code
|
408
|
+
when 200
|
409
|
+
log(:info, msg)
|
410
|
+
stats[:success].push(url)
|
411
|
+
when 404
|
412
|
+
log(:error, msg)
|
413
|
+
stats[:missing].push(url)
|
414
|
+
else
|
415
|
+
log(:error, msg)
|
416
|
+
stats[:failure].push(url)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
borked = 0
|
423
|
+
|
424
|
+
if stats[:missing].size > 0
|
425
|
+
borked += stats[:missing].size
|
426
|
+
log(:error, "missing on #{ stats[:missing].size } url(s)")
|
427
|
+
end
|
428
|
+
|
429
|
+
if stats[:failure].size > 0
|
430
|
+
borked += stats[:failure].size
|
431
|
+
log(:error, "failure on #{ stats[:failure].size } url(s)")
|
432
|
+
end
|
433
|
+
|
434
|
+
if borked > 0
|
435
|
+
exit(borked)
|
436
|
+
end
|
437
|
+
|
438
|
+
rps = (times.size / times.sum).round(4)
|
439
|
+
|
440
|
+
log(:info, "downloaded #{ @urls.size } urls at ~#{ rps } rps")
|
441
|
+
|
442
|
+
@urls
|
443
|
+
end
|
275
444
|
=end
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
728
|
-
|
729
|
-
|
445
|
+
|
446
|
+
#
|
447
|
+
def parallel_build!
|
448
|
+
size = @parallel
|
449
|
+
|
450
|
+
stats = {
|
451
|
+
:success => [],
|
452
|
+
:missing => [],
|
453
|
+
:failure => [],
|
454
|
+
}
|
455
|
+
|
456
|
+
times = []
|
457
|
+
|
458
|
+
Parallel.each(@urls, in_threads: 8) do |url|
|
459
|
+
uri = uri_for(url)
|
460
|
+
path = path_for(uri)
|
461
|
+
|
462
|
+
rpath = relative_path(path, :from => @directory)
|
463
|
+
|
464
|
+
code = nil
|
465
|
+
body = nil
|
466
|
+
|
467
|
+
time =
|
468
|
+
timing do
|
469
|
+
code, body = http_get(uri)
|
470
|
+
write_path(path, body) if code == 200
|
471
|
+
end
|
472
|
+
|
473
|
+
times.push(time)
|
474
|
+
ts = times.dup
|
475
|
+
rps = (ts.size / ts.sum).round(4)
|
476
|
+
msg = "#{ url } -> /#{ rpath } (time:#{ time }, rps:#{ rps }, code:#{ code })"
|
477
|
+
|
478
|
+
case code
|
479
|
+
when 200
|
480
|
+
log(:info, msg)
|
481
|
+
stats[:success].push(url)
|
482
|
+
when 404
|
483
|
+
log(:error, msg)
|
484
|
+
stats[:missing].push(url)
|
485
|
+
else
|
486
|
+
log(:error, msg)
|
487
|
+
stats[:failure].push(url)
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
borked = 0
|
492
|
+
|
493
|
+
if stats[:missing].size > 0
|
494
|
+
borked += stats[:missing].size
|
495
|
+
log(:error, "missing on #{ stats[:missing].size } url(s)")
|
496
|
+
end
|
497
|
+
|
498
|
+
if stats[:failure].size > 0
|
499
|
+
borked += stats[:failure].size
|
500
|
+
log(:error, "failure on #{ stats[:failure].size } url(s)")
|
501
|
+
end
|
502
|
+
|
503
|
+
if borked > 0
|
504
|
+
exit(borked)
|
505
|
+
end
|
506
|
+
|
507
|
+
rps = (times.size / times.sum).round(4)
|
508
|
+
|
509
|
+
log(:info, "downloaded #{ @urls.size } urls at ~#{ rps } rps")
|
510
|
+
|
511
|
+
@urls
|
512
|
+
end
|
513
|
+
|
514
|
+
#
|
515
|
+
def finalize!
|
516
|
+
@finished_at = Time.now
|
517
|
+
|
518
|
+
elapsed = (@finished_at.to_f - @started_at.to_f)
|
519
|
+
|
520
|
+
log(:info, "build time - #{ hms(elapsed) }")
|
521
|
+
|
522
|
+
# because netlify refuses to deploy from a symlink!
|
523
|
+
on_netlify = ENV['DEPLOY_PRIME_URL'].to_s =~ /netlify/
|
524
|
+
|
525
|
+
cp = on_netlify ? 'cp_r' : 'ln_s'
|
526
|
+
|
527
|
+
build = File.join(@rails_root, 'build')
|
528
|
+
|
529
|
+
FileUtils.rm_rf(build)
|
530
|
+
FileUtils.send(cp, @directory, build)
|
531
|
+
|
532
|
+
#log(:info, "to preview run: ruby -run -ehttpd ./build/ -p4242")
|
533
|
+
end
|
534
|
+
|
535
|
+
def timing(&block)
|
536
|
+
t = Time.now.to_f
|
537
|
+
|
538
|
+
block.call
|
539
|
+
|
540
|
+
(Time.now.to_f - t).round(2)
|
541
|
+
end
|
542
|
+
|
543
|
+
def http_get(url)
|
544
|
+
uri = URI.parse(url.to_s)
|
545
|
+
|
546
|
+
response =
|
547
|
+
begin
|
548
|
+
Net::HTTP.get_response(uri)
|
549
|
+
rescue
|
550
|
+
[code = 500, body = '']
|
551
|
+
end
|
552
|
+
|
553
|
+
if response.is_a?(Net::HTTPRedirection)
|
554
|
+
location = response['Location']
|
555
|
+
|
556
|
+
if location.to_s == url.to_s
|
557
|
+
log(:fatal, "circular redirection on #{ url }")
|
558
|
+
exit(1)
|
559
|
+
end
|
560
|
+
|
561
|
+
return http_get(location)
|
562
|
+
end
|
563
|
+
|
564
|
+
code = response.code.to_i rescue 500
|
565
|
+
body = response.body.to_s rescue ''
|
566
|
+
|
567
|
+
[code, body]
|
568
|
+
end
|
569
|
+
|
570
|
+
#
|
571
|
+
def to_s
|
572
|
+
@directory.to_s
|
573
|
+
end
|
574
|
+
|
575
|
+
#
|
576
|
+
def log(level, *args, &block)
|
577
|
+
@logger.send(level, *args, &block)
|
578
|
+
end
|
579
|
+
|
580
|
+
#
|
581
|
+
def path_for(url)
|
582
|
+
uri = uri_for(url)
|
583
|
+
path = nil
|
584
|
+
|
585
|
+
case
|
586
|
+
when uri.path=='/' || uri.path=='.'
|
587
|
+
path = File.join(@directory, 'index.html')
|
588
|
+
|
589
|
+
else
|
590
|
+
path = File.join(@directory, uri.path)
|
591
|
+
|
592
|
+
dirname, basename = File.split(path)
|
593
|
+
base, ext = basename.split('.', 2)
|
594
|
+
|
595
|
+
case
|
596
|
+
when uri.path.end_with?('/')
|
597
|
+
path =
|
598
|
+
File.join(path, 'index.html')
|
599
|
+
|
600
|
+
when ext.nil?
|
601
|
+
path =
|
602
|
+
if @config.fetch('index_html')
|
603
|
+
File.join(path, 'index.html')
|
604
|
+
else
|
605
|
+
path + '.html'
|
606
|
+
end
|
607
|
+
end
|
608
|
+
end
|
609
|
+
|
610
|
+
path
|
611
|
+
end
|
612
|
+
|
613
|
+
#
|
614
|
+
def write_path(path, body)
|
615
|
+
FileUtils.mkdir_p(File.dirname(path))
|
616
|
+
IO.binwrite(path, body)
|
617
|
+
end
|
618
|
+
|
619
|
+
#
|
620
|
+
def ensure_non_digested_assets_also_exist!(assets)
|
621
|
+
re = /(-{1}[a-z0-9]{32}*\.{1}){1}/
|
622
|
+
|
623
|
+
assets.each do |file|
|
624
|
+
next if File.directory?(file) || file !~ re
|
625
|
+
source = file.split('/')
|
626
|
+
source.push(source.pop.gsub(re, '.'))
|
627
|
+
non_digested = File.join(source)
|
628
|
+
#log(:debug, "asset: #{ file } -> #{ non_digested }")
|
629
|
+
FileUtils.ln(file, non_digested)
|
630
|
+
end
|
631
|
+
end
|
632
|
+
|
633
|
+
#
|
634
|
+
def url_for(url)
|
635
|
+
uri = URI.parse(url.to_s)
|
636
|
+
|
637
|
+
if uri.absolute?
|
638
|
+
uri.path = path
|
639
|
+
uri.to_s
|
640
|
+
else
|
641
|
+
rel = @url ? URI.parse(@url) : URI.parse('')
|
642
|
+
rel.path = absolute_path_for(uri.path)
|
643
|
+
rel.query = uri.query
|
644
|
+
rel.fragment = uri.fragment
|
645
|
+
rel.to_s
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
#
|
650
|
+
def uri_for(url)
|
651
|
+
uri = url.is_a?(URI) ? url : URI.parse(url.to_s)
|
652
|
+
end
|
653
|
+
|
654
|
+
#
|
655
|
+
def hms(seconds)
|
656
|
+
return unless seconds
|
657
|
+
"%02d:%02d:%02d" % hours_minutes_seconds(seconds)
|
658
|
+
end
|
659
|
+
|
660
|
+
#
|
661
|
+
def hours_minutes_seconds(seconds)
|
662
|
+
return unless seconds
|
663
|
+
seconds = Float(seconds).to_i
|
664
|
+
hours, seconds = seconds.divmod(3600)
|
665
|
+
minutes, seconds = seconds.divmod(60)
|
666
|
+
[hours.to_i, minutes.to_s, seconds]
|
667
|
+
end
|
668
|
+
|
669
|
+
#
|
670
|
+
def port_open?(port, options = {})
|
671
|
+
seconds = options[:timeout] || 1
|
672
|
+
ip = options[:ip] || '0.0.0.0'
|
673
|
+
|
674
|
+
Timeout::timeout(seconds) do
|
675
|
+
begin
|
676
|
+
TCPSocket.new(ip, port).close
|
677
|
+
false
|
678
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
679
|
+
true
|
680
|
+
rescue Object
|
681
|
+
false
|
682
|
+
end
|
683
|
+
end
|
684
|
+
rescue Timeout::Error
|
685
|
+
false
|
686
|
+
end
|
687
|
+
|
688
|
+
#
|
689
|
+
def paths_for(*args)
|
690
|
+
path = args.flatten.compact.join('/')
|
691
|
+
path.gsub!(%r|[.]+/|, '/')
|
692
|
+
path.squeeze!('/')
|
693
|
+
path.sub!(%r|^/|, '')
|
694
|
+
path.sub!(%r|/$|, '')
|
695
|
+
paths = path.split('/')
|
696
|
+
end
|
697
|
+
|
698
|
+
#
|
699
|
+
def absolute_path_for(*args)
|
700
|
+
trailing_slash = args.join.end_with?('/') ? '/' : ''
|
701
|
+
path = ('/' + paths_for(*args).join('/') + trailing_slash).squeeze('/')
|
702
|
+
path unless path.strip.empty?
|
703
|
+
end
|
704
|
+
|
705
|
+
#
|
706
|
+
def relative_path_for(*args)
|
707
|
+
path = absolute_path_for(*args).sub(%r{^/+}, '')
|
708
|
+
path unless path.strip.empty?
|
709
|
+
end
|
710
|
+
|
711
|
+
#
|
712
|
+
def relative_path(path, *args)
|
713
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
714
|
+
path = path.to_s
|
715
|
+
relative = args.shift || options[:relative] || options[:to] || options[:from]
|
716
|
+
if relative
|
717
|
+
Pathname.new(path).relative_path_from(Pathname.new(relative.to_s)).to_s
|
718
|
+
else
|
719
|
+
relative_path_for(path)
|
720
|
+
end
|
721
|
+
end
|
722
|
+
|
723
|
+
#
|
724
|
+
def spawn(arg, *args, **kws)
|
725
|
+
command = [arg, *args]
|
726
|
+
|
727
|
+
env = kws.fetch(:env){ {} }
|
728
|
+
error = kws.fetch(:error){ true }
|
729
|
+
quiet = kws.fetch(:quiet){ false }
|
730
|
+
stdin = kws.fetch(:stdin){ '' }
|
731
|
+
|
732
|
+
env.transform_keys!(&:to_s)
|
733
|
+
env.transform_values!(&:to_s)
|
734
|
+
|
735
|
+
pid = nil
|
736
|
+
status = nil
|
737
|
+
stdout = nil
|
738
|
+
stderr = nil
|
739
|
+
|
740
|
+
Tempfile.open do |i|
|
741
|
+
i.write(stdin)
|
742
|
+
i.flush
|
743
|
+
|
744
|
+
Tempfile.open do |o|
|
745
|
+
Tempfile.open do |e|
|
746
|
+
redirects = {:in => i.path, :out => o.path, :err => e.path}
|
747
|
+
|
748
|
+
pid = Process.spawn(env, *command, redirects)
|
749
|
+
|
750
|
+
Process.wait(pid)
|
751
|
+
|
752
|
+
status = $?.exitstatus
|
753
|
+
|
754
|
+
stdout = IO.binread(o.path)
|
755
|
+
stderr = IO.binread(e.path)
|
756
|
+
end
|
757
|
+
end
|
758
|
+
end
|
759
|
+
|
760
|
+
unless status == 0
|
761
|
+
unless kws[:quiet] == true
|
762
|
+
log(:error, "#{ command.join(' ') } ###===>>> #{ status }\nSTDOUT:\n#{ stdout }\n\STDERR:\n#{ stderr }")
|
763
|
+
exit(status)
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
767
|
+
{command:, pid:, env:, status:, stdin:, stdout:, stderr:}
|
768
|
+
end
|
769
|
+
end
|
770
|
+
|
771
|
+
#
|
772
|
+
class Server
|
773
|
+
attr_reader :pid
|
774
|
+
|
775
|
+
def initialize(cli:)
|
776
|
+
@cli = cli
|
777
|
+
|
778
|
+
@env = @cli.env
|
779
|
+
@directory = @cli.directory
|
780
|
+
@rails_root = @cli.rails_root
|
781
|
+
@parallel = @cli.parallel
|
782
|
+
@uuid = @cli.uuid
|
783
|
+
|
784
|
+
@thread = nil
|
785
|
+
@pid = nil
|
786
|
+
end
|
787
|
+
|
788
|
+
def start!(port:)
|
789
|
+
system("#{ version_command } >/dev/null 2>&1") ||
|
790
|
+
abort("app fails to load via: #{ version_command }")
|
791
|
+
|
792
|
+
q = Queue.new
|
793
|
+
|
794
|
+
cmd = start_command_for(port)
|
795
|
+
|
796
|
+
log = './tmp/rails_build_server.log'
|
797
|
+
|
798
|
+
@cli.log(:info, "server: #{ cmd } > #{ log } 2>&1")
|
799
|
+
|
800
|
+
@thread = Thread.new do
|
801
|
+
Thread.current.abort_on_exception = true
|
802
|
+
pipe = IO.popen("#{ cmd } > #{ log } 2>&1")
|
803
|
+
q.push(pipe.pid)
|
804
|
+
end
|
805
|
+
|
806
|
+
@pid = q.pop
|
807
|
+
|
808
|
+
@cli.log(:info, "pid: #{ @pid }")
|
809
|
+
|
810
|
+
@assassin = Assassin.ate(@pid)
|
811
|
+
|
812
|
+
at_exit{ stop! }
|
813
|
+
end
|
814
|
+
|
815
|
+
def version_command
|
816
|
+
cmd_for(
|
817
|
+
%W[
|
818
|
+
RAILS_ENV=#{ @env }
|
819
|
+
DISABLE_SPRING=true
|
820
|
+
|
821
|
+
rails --version
|
822
|
+
]
|
823
|
+
)
|
824
|
+
end
|
825
|
+
|
826
|
+
def start_command_for(port)
|
827
|
+
cmd_for(
|
828
|
+
%W[
|
829
|
+
RAILS_ENV=#{ @env }
|
830
|
+
DISABLE_SPRING=true
|
831
|
+
|
832
|
+
RAILS_BUILD=#{ @uuid }
|
833
|
+
|
834
|
+
RAILS_SERVE_STATIC_FILES=true
|
835
|
+
RAILS_LOG_TO_STDOUT=true
|
836
|
+
WEB_CONCURRENCY=#{ @parallel.to_s }
|
837
|
+
|
838
|
+
rails server
|
839
|
+
|
840
|
+
--environment=#{ @env }
|
841
|
+
--port=#{ port }
|
842
|
+
--binding=0.0.0.0
|
843
|
+
--log-to-stdout
|
844
|
+
]
|
845
|
+
)
|
846
|
+
end
|
847
|
+
|
848
|
+
def cmd_for(arg, *args)
|
849
|
+
[arg, *args].flatten.compact.join(' ').squeeze(' ').strip
|
850
|
+
end
|
851
|
+
|
852
|
+
def stop!
|
853
|
+
kill!(@pid)
|
854
|
+
@thread.kill
|
855
|
+
@cli.log(:info, "stopped: #{ @pid }")
|
856
|
+
end
|
857
|
+
|
858
|
+
def kill!(pid)
|
859
|
+
42.times do
|
860
|
+
begin
|
861
|
+
Process.kill(0, pid)
|
862
|
+
return(true)
|
863
|
+
rescue Object => e
|
864
|
+
if e.is_a?(Errno::ESRCH)
|
865
|
+
Process.kill(-15, pid) rescue nil
|
866
|
+
sleep(rand + rand)
|
867
|
+
Process.kill(-9, pid) rescue nil
|
868
|
+
end
|
869
|
+
end
|
870
|
+
sleep(0.42 + rand)
|
871
|
+
end
|
872
|
+
return(false)
|
873
|
+
end
|
874
|
+
end
|
875
|
+
end
|
876
|
+
|
877
|
+
END {
|
878
|
+
require_relative '../lib/rails_build.rb'
|
879
|
+
|
880
|
+
STDOUT.sync = true
|
881
|
+
STDERR.sync = true
|
882
|
+
|
883
|
+
RailsBuild::CLI.run!
|
884
|
+
}
|
885
|
+
|
886
|
+
__END__
|
887
|
+
<<~________
|
888
|
+
|
889
|
+
this file should to enumerate all the urls you'd like to build
|
890
|
+
|
891
|
+
the contents of your ./public directory, and any assets, are automaticaly included
|
892
|
+
|
893
|
+
therefore you need only declare which dynamic urls, that is to say, 'routes'
|
894
|
+
|
895
|
+
you would like included in your build
|
896
|
+
|
897
|
+
it is not loaded except during build time, and will not affect your normal rails app in any way
|
898
|
+
|
899
|
+
________
|
900
|
+
|
901
|
+
|
902
|
+
RailsBuild.configure do |config|
|
903
|
+
|
904
|
+
# most of the time you are going to want your route included, which will
|
905
|
+
# translate into an ./index.html being output in the build
|
906
|
+
#
|
907
|
+
|
908
|
+
config.urls << '/'
|
909
|
+
|
910
|
+
# include any/all additional routes youd' like built thusly
|
911
|
+
#
|
912
|
+
|
913
|
+
Post.each do |post|
|
914
|
+
config.urls << "/posts/#{ post.id }"
|
915
|
+
end
|
916
|
+
|
917
|
+
# thats it! - now just run `rails_build` and you are GTG
|
918
|
+
|
730
919
|
end
|