rails_build 1.0.0 → 1.2.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.
- checksums.yaml +4 -4
- data/README.md +8 -5
- data/bin/rails_build +730 -642
- data/lib/rails_build.rb +2 -0
- data/lib/rails_build/engine.rb +2 -2
- data/lib/rails_build/version.rb +1 -1
- metadata +46 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e8b28d514b5404bbcadaca8e7d8ade5021265e8
|
4
|
+
data.tar.gz: a36bf4c19682e86162b5579122ee776fdd9b20bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be11ffbdd737215266b85ca7de68a873ecc23b1b59e9dc668045f82bdffd769862c36c0e0cd29d16e3fe57ce564abb08a7c53303f66edcd7d3a785a9c9cb54ec
|
7
|
+
data.tar.gz: 2e2a593592f58735a55989dbd6af9849b0b74f9b09870708b62a05bbed33b18a1d1d5523735dc4adbe369acf1d00a7492a596295802250a922539776b1ddd2a2
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@ built as a Rails 5 engine.
|
|
8
8
|
## How It Works
|
9
9
|
|
10
10
|
RailsBuild bundles all your assets, public directory, and configured urls into
|
11
|
-
a static site suitable for deployment to Netlify, Amazon S3, or your favorite
|
11
|
+
a static site suitable for deployment to [Netlify](https://www.netlify.com/), Amazon S3, or your favorite
|
12
12
|
static website hosting solution. It does this by:
|
13
13
|
|
14
14
|
- Booting your application in *production* mode
|
@@ -92,14 +92,17 @@ like './about' vs. '../about'
|
|
92
92
|
|
93
93
|
## Optimization and Notes
|
94
94
|
|
95
|
-
|
96
95
|
RailsBuild is fast. Very fast. [DOJO4](http://dojo4.com) has seen optimized [Middleman](https://middlemanapp.com/) builds of > 30 minutes dropped to *60 seconds* by simply making basic use of Rails' built-in caching facilites.
|
97
96
|
|
97
|
+
You app has to run in production mode to build! Don't forget to setup
|
98
|
+
secrets, or anything else generally required in production mode.
|
99
|
+
|
98
100
|
When trying to squeeze out performance just remember that RailsBuild runs in
|
99
101
|
production mode and, therefore, making a build go fast follows the *exact same
|
100
102
|
rules* as making anything other Rails' application fast. The first place to
|
101
103
|
reach is typically fragment caching of partials used in your app.
|
102
104
|
|
105
|
+
|
103
106
|
Finally, don't forget about *./config/initializers/assets.rb* - RailsBuild
|
104
107
|
doesn't do anything special to the asset pipeline and only those assets
|
105
108
|
normally built when
|
@@ -157,14 +160,14 @@ After installation and configuration simply run
|
|
157
160
|
|
158
161
|
|
159
162
|
|
160
|
-
##
|
163
|
+
## Netlify
|
161
164
|
|
162
|
-
We love Netlify at [DOJO4](http://dojo4.com). RailsBuild works with netlify
|
165
|
+
We love [Netlify](https://www.netlify.com/) at [DOJO4](http://dojo4.com). RailsBuild works with netlify
|
163
166
|
out of the box and simply requires
|
164
167
|
|
165
168
|
```yaml
|
166
169
|
|
167
|
-
build_command : rails_build
|
170
|
+
build_command : ./bin/rails_build
|
168
171
|
|
169
172
|
build_directory: build
|
170
173
|
|
data/bin/rails_build
CHANGED
@@ -10,13 +10,13 @@ END{
|
|
10
10
|
|
11
11
|
|
12
12
|
module RailsBuild
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
class CLI
|
14
|
+
def CLI.usage
|
15
|
+
<<-__
|
16
|
+
NAME
|
17
|
+
rails_build
|
18
18
|
|
19
|
-
|
19
|
+
SYNOPSIS
|
20
20
|
a small, simple, bullet proof, and very fast static site generator built on rails 5
|
21
21
|
|
22
22
|
USAGE
|
@@ -27,168 +27,171 @@ module RailsBuild
|
|
27
27
|
--rails_root,--r : specifiy the RAILS_ROOT, default=./
|
28
28
|
--parallel,--p : how many requests to make in parallel, default=n_cpus/2
|
29
29
|
--env,--e : speciify the RAILS_ENV, default=production
|
30
|
-
--
|
30
|
+
--url, -u : provide the url of the build server, do *not* start separate one
|
31
|
+
--server, -s : passenger | puma, default=passenger
|
31
32
|
--log, -l : specify the logfile, default=STDERR
|
32
33
|
--verbose, -v : turn on verbose logging
|
33
|
-
|
34
|
-
|
34
|
+
__
|
35
|
+
end
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
def CLI.opts
|
38
|
+
GetoptLong.new(
|
39
|
+
[ '--help' , '-h' , GetoptLong::NO_ARGUMENT ] ,
|
40
|
+
[ '--url' , '-u' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
41
|
+
[ '--server' , '-s' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
42
|
+
[ '--parallel' , '-p' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
43
|
+
[ '--rails_root' , '-r' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
44
|
+
[ '--env' , '-e' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
45
|
+
[ '--log' , '-l' , GetoptLong::REQUIRED_ARGUMENT ] ,
|
46
|
+
[ '--verbose' , '-v' , GetoptLong::NO_ARGUMENT ] ,
|
47
|
+
)
|
48
|
+
end
|
47
49
|
|
48
|
-
|
49
|
-
|
50
|
+
def build!
|
51
|
+
prepare!
|
50
52
|
|
51
|
-
|
53
|
+
mkdir!
|
52
54
|
|
53
|
-
|
55
|
+
start_server! unless url
|
54
56
|
|
55
|
-
|
57
|
+
clear_cache!
|
56
58
|
|
57
|
-
|
59
|
+
extract_urls! url_for('/rails_build/configuration.json')
|
58
60
|
|
59
|
-
|
61
|
+
precompile_assets!
|
60
62
|
|
61
|
-
|
63
|
+
rsync_public!
|
62
64
|
|
63
|
-
|
65
|
+
parallel_build!
|
64
66
|
|
65
|
-
|
66
|
-
|
67
|
+
finalize!
|
68
|
+
end
|
67
69
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
70
|
+
#
|
71
|
+
def CLI.build!(*args, &block)
|
72
|
+
new(*args, &block).build!
|
73
|
+
end
|
72
74
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
attr_accessor :url
|
75
|
+
#
|
76
|
+
attr_accessor :rails_root
|
77
|
+
attr_accessor :url
|
78
|
+
attr_accessor :server
|
79
|
+
attr_accessor :directory
|
80
|
+
attr_accessor :uuid
|
81
|
+
attr_accessor :id
|
82
|
+
attr_accessor :env
|
83
|
+
attr_accessor :parallel
|
83
84
|
|
84
|
-
|
85
|
-
|
85
|
+
#
|
86
|
+
def initialize(*args, &block)
|
86
87
|
setup!
|
87
88
|
|
88
|
-
|
89
|
+
@args = parse_args!
|
89
90
|
|
90
|
-
|
91
|
+
@opts = parse_opts!
|
91
92
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
93
|
+
if @opts[:help]
|
94
|
+
usage!
|
95
|
+
exit(42)
|
96
|
+
end
|
97
|
+
end
|
97
98
|
|
98
99
|
#
|
99
100
|
def setup!
|
100
|
-
|
101
|
-
|
102
|
-
|
101
|
+
#
|
102
|
+
STDOUT.sync = true
|
103
|
+
STDERR.sync = true
|
103
104
|
|
104
|
-
|
105
|
-
|
106
|
-
|
105
|
+
#
|
106
|
+
ENV['SPRING_DISABLE'] = 'true'
|
107
|
+
ENV['DISABLE_SPRING'] = 'true'
|
107
108
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
109
|
+
#
|
110
|
+
%w[
|
111
|
+
fileutils pathname thread socket timeout time uri etc open-uri securerandom logger getoptlong rubygems json
|
112
|
+
].each do |stdlib|
|
113
|
+
require(stdlib)
|
114
|
+
end
|
114
115
|
end
|
115
116
|
|
116
|
-
|
117
|
-
|
117
|
+
#
|
118
|
+
def prepare!
|
118
119
|
#
|
119
|
-
|
120
|
+
@rails_root = find_rails_root!(@args[0] || '.')
|
120
121
|
|
121
122
|
#
|
122
|
-
|
123
|
+
Dir.chdir(@rails_root)
|
123
124
|
|
124
125
|
#
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
threadify persistent_http
|
133
|
-
|
126
|
+
if File.exists?('./Gemfile')
|
127
|
+
require 'bundler/setup'
|
128
|
+
Bundler.setup(:require => false)
|
129
|
+
end
|
130
|
+
|
131
|
+
#
|
132
|
+
%w[
|
133
|
+
threadify persistent_http
|
134
|
+
].each do |gem|
|
134
135
|
begin
|
135
136
|
require(gem)
|
136
137
|
rescue LoadError
|
137
|
-
abort "add gem '
|
138
|
+
abort "add gem '#{ gem }' to your Gemfile"
|
138
139
|
end
|
139
|
-
|
140
|
+
end
|
140
141
|
|
141
142
|
#
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
#
|
149
|
-
@logger = Logger.new(@opts[:log] || STDERR)
|
150
|
-
|
151
|
-
@uuid = ENV['RAILS_BUILD']
|
152
|
-
@time = ENV['RAILS_BUILD_TIME']
|
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']
|
157
|
-
|
158
|
-
@uuid ||= SecureRandom.uuid
|
159
|
-
@time ||= Time.now.utc
|
160
|
-
@env ||= 'production'
|
161
|
-
@parallel ||= (Etc.nprocessors/2)
|
162
|
-
|
163
|
-
unless @time.is_a?(Time)
|
164
|
-
@time = Time.parse(@time.to_s).utc
|
165
|
-
end
|
166
|
-
|
167
|
-
@parallel = @parallel.to_i
|
143
|
+
begin
|
144
|
+
require('pry')
|
145
|
+
rescue LoadError
|
146
|
+
nil
|
147
|
+
end
|
168
148
|
|
149
|
+
#
|
150
|
+
@logger = Logger.new(@opts[:log] || STDERR)
|
151
|
+
|
152
|
+
@uuid = ENV['RAILS_BUILD']
|
153
|
+
@time = ENV['RAILS_BUILD_TIME']
|
154
|
+
@url = @opts[:url] || ENV['RAILS_BUILD_URL']
|
155
|
+
@server = @opts[:server] || ENV['RAILS_BUILD_SERVER']
|
156
|
+
@env = @opts[:env] || ENV['RAILS_BUILD_ENV'] || ENV['RAILS_ENV']
|
157
|
+
@parallel = @opts[:parallel] || ENV['RAILS_BUILD_PARALLEL']
|
158
|
+
@verbose = @opts[:verbose] || ENV['RAILS_BUILD_VERBOSE']
|
159
|
+
|
160
|
+
@uuid ||= SecureRandom.uuid
|
161
|
+
@time ||= Time.now.utc
|
162
|
+
@server ||= 'passenger'
|
163
|
+
@env ||= 'production'
|
164
|
+
@parallel ||= (Etc.nprocessors/2)
|
165
|
+
|
166
|
+
unless @time.is_a?(Time)
|
167
|
+
@time = Time.parse(@time.to_s).utc
|
168
|
+
end
|
169
169
|
|
170
|
-
|
171
|
-
@pumactl = 'bundle exec pumactl'
|
170
|
+
@parallel = @parallel.to_i
|
172
171
|
|
173
|
-
|
172
|
+
if ENV['RAILS_BUILD_DIRECTORY']
|
173
|
+
@build_directory = File.expand_path(ENV['RAILS_BUILD_DIRECTORY'])
|
174
|
+
else
|
175
|
+
@build_directory = File.join(@rails_root, 'builds')
|
176
|
+
end
|
174
177
|
|
175
|
-
|
176
|
-
@build_directory = File.expand_path(ENV['RAILS_BUILD_DIRECTORY'])
|
177
|
-
else
|
178
|
-
@build_directory = File.join(@rails_root, 'builds')
|
179
|
-
end
|
178
|
+
@directory = File.join(@build_directory, @uuid)
|
180
179
|
|
181
|
-
|
180
|
+
ENV['RAILS_ENV'] = @env
|
181
|
+
ENV['RAILS_BUILD'] = @uuid
|
182
|
+
ENV['RAILS_BUILD_ENV'] = @env
|
183
|
+
ENV['RAILS_BUILD_TIME'] = @time.httpdate
|
182
184
|
|
183
|
-
|
184
|
-
ENV['RAILS_BUILD'] = @uuid
|
185
|
-
ENV['RAILS_BUILD_ENV'] = @env
|
186
|
-
ENV['RAILS_BUILD_TIME'] = @time.httpdate
|
185
|
+
@urls = []
|
187
186
|
|
188
|
-
|
187
|
+
@started_at = Time.now
|
189
188
|
|
190
|
-
|
191
|
-
|
189
|
+
unless(( server = Server.for(@server, self) ))
|
190
|
+
abort "no server found for server=#{ @server.inspect }"
|
191
|
+
else
|
192
|
+
@server = server
|
193
|
+
end
|
194
|
+
end
|
192
195
|
|
193
196
|
#
|
194
197
|
def find_rails_root!(path)
|
@@ -208,523 +211,608 @@ module RailsBuild
|
|
208
211
|
abort("could not find a rails_root in or above #{ path }!?")
|
209
212
|
end
|
210
213
|
|
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
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
=
|
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
|
-
|
214
|
+
#
|
215
|
+
def parse_args!
|
216
|
+
@args = ARGV.map{|arg| "#{ arg }"}
|
217
|
+
end
|
218
|
+
|
219
|
+
#
|
220
|
+
def parse_opts!
|
221
|
+
@opts = Hash.new
|
222
|
+
|
223
|
+
CLI.opts.each do |opt, arg|
|
224
|
+
key, val = opt.split('--').last, arg
|
225
|
+
@opts[key.to_s.to_sym] = (val == '' ? true : val)
|
226
|
+
end
|
227
|
+
|
228
|
+
@opts
|
229
|
+
end
|
230
|
+
|
231
|
+
#
|
232
|
+
def usage!
|
233
|
+
lines = CLI.usage.strip.split(/\n/)
|
234
|
+
n = lines[1].to_s.scan(/^\s+/).size
|
235
|
+
indent = ' ' * n
|
236
|
+
re = /^#{ Regexp.escape(indent) }/
|
237
|
+
usage = lines.map{|line| line.gsub(re, '')}.join("\n")
|
238
|
+
STDERR.puts(usage)
|
239
|
+
end
|
240
|
+
|
241
|
+
#
|
242
|
+
def mkdir!
|
243
|
+
FileUtils.rm_rf(@directory)
|
244
|
+
FileUtils.mkdir_p(@directory)
|
245
|
+
log(:info, "directory: #{ @directory }")
|
246
|
+
end
|
247
|
+
|
248
|
+
#
|
249
|
+
def start_server!
|
250
|
+
@url =
|
251
|
+
nil
|
252
|
+
|
253
|
+
@port =
|
254
|
+
nil
|
255
|
+
|
256
|
+
ports =
|
257
|
+
(2000 .. 9000).to_a
|
258
|
+
|
259
|
+
start_server, stop_server = nil
|
260
|
+
|
261
|
+
@server.setup!
|
262
|
+
|
263
|
+
ports.each do |port|
|
264
|
+
next unless port_open?(port)
|
265
|
+
|
266
|
+
start_server = @server.start_command_for(port)
|
267
|
+
stop_server = @server.stop_command_for(port)
|
268
|
+
|
269
|
+
`#{ stop_server } 2>&1`.strip
|
270
|
+
|
271
|
+
log(:info, "cmd: #{ start_server }")
|
272
|
+
server_output = `#{ start_server } 2>&1`.strip
|
273
|
+
|
274
|
+
log(:info, "status: #{ $?.exitstatus }")
|
275
|
+
|
276
|
+
t = Time.now.to_f
|
277
|
+
timeout = 10
|
278
|
+
i = 0
|
279
|
+
url = nil
|
280
|
+
|
281
|
+
loop do
|
282
|
+
i += 1
|
283
|
+
|
284
|
+
begin
|
285
|
+
url = "http://localhost:#{ port }"
|
286
|
+
open(url){|socket| socket.read}
|
287
|
+
@url = url
|
288
|
+
@port = port
|
289
|
+
break
|
290
|
+
rescue Object => e
|
291
|
+
if i > 2
|
292
|
+
log :error, "url: #{ url } ->"
|
293
|
+
log :error, "#{ e.message }(#{ e.class })\n"
|
294
|
+
log :error, "#{ server_output }\n\n"
|
295
|
+
end
|
296
|
+
|
297
|
+
if((Time.now.to_f - t) > timeout)
|
298
|
+
abort("could not start server inside of #{ timeout } seconds via\n\n#{ start_server }\n\n;-/")
|
299
|
+
else
|
300
|
+
sleep(rand(0.42))
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
break if @url
|
306
|
+
end
|
307
|
+
|
308
|
+
# barf if server could not be started
|
309
|
+
#
|
310
|
+
unless @url
|
311
|
+
abort("could not start server on any of ports #{ ports.first } .. #{ ports.last }")
|
312
|
+
else
|
313
|
+
log(:info, "started server on #{ @url }")
|
314
|
+
end
|
315
|
+
|
316
|
+
# set assassins to ensure the server daemon never outlives the build script
|
317
|
+
# no matter how it is killed (even -9)
|
318
|
+
#
|
319
|
+
at_exit{
|
320
|
+
log(:info, "cmd: #{ stop_server }")
|
321
|
+
`#{ stop_server } >/dev/null 2>&1`
|
322
|
+
log(:info, "status: #{ $?.exitstatus }")
|
323
|
+
log(:info, "stopped server #{ @url }")
|
324
|
+
@server.cleanup!(:port => @port)
|
325
|
+
}
|
326
|
+
|
327
|
+
assassin = <<-__
|
328
|
+
pid = #{ Process.pid }
|
329
|
+
|
330
|
+
4242.times do
|
331
|
+
begin
|
332
|
+
Process.kill(0, pid)
|
333
|
+
rescue Object => e
|
334
|
+
if e.is_a?(Errno::ESRCH)
|
335
|
+
`#{ stop_server } >/dev/null 2>&1`
|
336
|
+
Process.kill(-15, pid) rescue nil
|
337
|
+
sleep(rand + rand)
|
338
|
+
Process.kill(-9, pid) rescue nil
|
339
|
+
end
|
340
|
+
exit
|
341
|
+
end
|
342
|
+
sleep(1 + rand)
|
343
|
+
end
|
344
|
+
__
|
345
|
+
IO.binwrite('tmp/build-assassin.rb', assassin)
|
346
|
+
cmd = "nohup ruby tmp/build-assassin.rb >/dev/null 2>&1 &"
|
347
|
+
system cmd
|
348
|
+
|
349
|
+
#
|
350
|
+
@started_at = Time.now
|
351
|
+
@url
|
352
|
+
end
|
353
|
+
|
354
|
+
#
|
355
|
+
def extract_urls!(build_url)
|
356
|
+
urls = []
|
357
|
+
|
358
|
+
code, body = http_get(build_url)
|
359
|
+
|
360
|
+
unless code == 200
|
361
|
+
raise "failed to get build urls from #{ build_url }"
|
362
|
+
end
|
363
|
+
|
364
|
+
@_build = JSON.parse(body)
|
365
|
+
|
366
|
+
unless @_build['urls'].is_a?(Array)
|
367
|
+
raise "failed to find any build urls at #{ build_url } - edit ./config/rails_build.rb # see README"
|
368
|
+
end
|
369
|
+
|
370
|
+
urls = @_build['urls']
|
371
|
+
|
372
|
+
urls.map!{|url| url_for(url)}
|
373
|
+
|
374
|
+
log(:info, "extracted #{ urls.size } url(s) to build from #{ build_url }")
|
375
|
+
|
376
|
+
@urls = urls
|
377
|
+
end
|
378
|
+
|
379
|
+
#
|
380
|
+
def clear_cache!
|
381
|
+
#spawn "rake tmp:cache:clear"
|
382
|
+
spawn "rails runner 'Rails.cache.clear'"
|
383
|
+
end
|
384
|
+
|
385
|
+
#
|
386
|
+
def precompile_assets!
|
387
|
+
@asset_dir = File.join(@rails_root, "public/assets")
|
388
|
+
@asset_tmp = false
|
389
|
+
|
390
|
+
if test(?d, @asset_dir)
|
391
|
+
@asset_tmp = File.join(@rails_root, "tmp/assets-build-#{ @uuid }")
|
392
|
+
FileUtils.mv(@asset_dir, @asset_tmp)
|
393
|
+
end
|
394
|
+
|
395
|
+
spawn "RAILS_ENV=production rake assets:precompile"
|
396
|
+
|
397
|
+
assets = Dir.glob(File.join(@rails_root, 'public/assets/**/**'))
|
398
|
+
|
399
|
+
log(:info, "precompiled #{ assets.size } assets")
|
400
|
+
|
401
|
+
ensure_non_digested_assets_also_exist!(assets)
|
402
|
+
end
|
403
|
+
|
404
|
+
#
|
405
|
+
def rsync_public!
|
406
|
+
spawn "rsync -avz ./public/ #{ @directory }"
|
407
|
+
|
408
|
+
count = 0
|
409
|
+
|
410
|
+
Dir.glob(File.join(@directory, '**/**')).each{ count += 1 }
|
411
|
+
|
412
|
+
log(:info, "rsync'd #{ count } files")
|
413
|
+
|
414
|
+
if @asset_tmp
|
415
|
+
FileUtils.rm_rf(@asset_dir)
|
416
|
+
FileUtils.mv(@asset_tmp, @asset_dir)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
#
|
421
|
+
def parallel_build!(n = nil)
|
422
|
+
n ||= @parallel
|
423
|
+
|
424
|
+
stats = {
|
425
|
+
:success => [], :missing => [], :failure => [],
|
426
|
+
}
|
427
|
+
|
428
|
+
times = Queue.new
|
429
|
+
|
430
|
+
avg = nil
|
431
|
+
|
432
|
+
Thread.new do
|
433
|
+
Thread.current.abort_on_exception = true
|
434
|
+
total = 0.0
|
435
|
+
n = 0
|
436
|
+
loop do
|
437
|
+
while(time = times.pop)
|
438
|
+
total += time
|
439
|
+
n += 1
|
440
|
+
avg = (total / n).round(2)
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
a = Time.now.to_f
|
446
|
+
|
447
|
+
_stats =
|
448
|
+
@urls.threadify(n) do |url|
|
449
|
+
uri = uri_for(url)
|
450
|
+
path = path_for(uri)
|
451
|
+
upath = uri.path
|
452
|
+
rpath = relative_path(path, :from => @directory)
|
453
|
+
|
454
|
+
_a = Time.now.to_f
|
455
|
+
|
456
|
+
code, body = http_get(uri)
|
457
|
+
|
458
|
+
_b = Time.now.to_f
|
459
|
+
_e = (_b - _a).round(2)
|
460
|
+
|
461
|
+
times.push(_e)
|
462
|
+
|
463
|
+
label = "#{ code } @ (t̄:#{ avg }s)"
|
464
|
+
|
465
|
+
case code
|
466
|
+
when 200
|
467
|
+
write_path(path, body)
|
468
|
+
log(:info, "#{ label }: #{ upath } -> #{ rpath } (t:#{ _e }s)")
|
469
|
+
[:success, url]
|
470
|
+
when 404
|
471
|
+
log(:error, "#{ label }: #{ upath }")
|
472
|
+
[:missing, url]
|
473
|
+
when 500
|
474
|
+
log(:error, "#{ label }: #{ upath }")
|
475
|
+
[:failure, url]
|
476
|
+
else
|
477
|
+
log(:error, "#{ label }: #{ upath }")
|
478
|
+
[:failure, url]
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
_stats.each{|stat, url| stats[stat].push(url)}
|
483
|
+
|
484
|
+
b = Time.now.to_f
|
485
|
+
|
486
|
+
borked = false
|
487
|
+
|
488
|
+
if stats[:missing].size > 0
|
489
|
+
borked = true
|
490
|
+
log(:error, "missing on #{ stats[:missing].size } urls")
|
491
|
+
end
|
492
|
+
|
493
|
+
if stats[:failure].size > 0
|
494
|
+
borked = true
|
495
|
+
log(:error, "failure on #{ stats[:failure].size } urls")
|
496
|
+
end
|
497
|
+
|
498
|
+
if borked
|
499
|
+
exit(1)
|
500
|
+
end
|
501
|
+
|
502
|
+
elapsed = b - a
|
503
|
+
n = @urls.size
|
504
|
+
rps = (n / elapsed).round(2)
|
505
|
+
|
506
|
+
log(:info, "downloaded #{ n } urls at ~#{ rps }/s")
|
507
|
+
|
508
|
+
@urls
|
509
|
+
end
|
510
|
+
|
511
|
+
#
|
512
|
+
def finalize!
|
513
|
+
@finished_at = Time.now
|
514
|
+
elapsed = (@finished_at.to_f - @started_at.to_f)
|
515
|
+
log(:info, "build time - #{ hms(elapsed) }")
|
516
|
+
on_netlify = ENV['DEPLOY_PRIME_URL'].to_s =~ /netlify/
|
517
|
+
strategy = on_netlify ? 'cp_r' : 'ln_s' # netlify refuses to deploy from a symlink ;-/ # FIXME
|
518
|
+
build = File.join(@rails_root, 'build')
|
519
|
+
FileUtils.rm_rf(build)
|
520
|
+
FileUtils.send(strategy, @directory, build)
|
521
|
+
log(:info, "preview with `static ./build/` # brew install node-static")
|
522
|
+
end
|
523
|
+
|
524
|
+
def http_connection
|
525
|
+
@http_connection ||= (
|
526
|
+
PersistentHTTP.new({
|
527
|
+
:url => @url,
|
528
|
+
:pool_size => (@parallel + 1),
|
529
|
+
:logger => (@verbose ? @logger : nil),
|
530
|
+
:pool_timeout => 10,
|
531
|
+
:warn_timeout => 1,
|
532
|
+
:force_retry => true,
|
533
|
+
})
|
534
|
+
)
|
535
|
+
end
|
536
|
+
|
537
|
+
def http_get(url)
|
538
|
+
request = Net::HTTP::Get.new(url)
|
539
|
+
response = http_connection.request(request)
|
540
|
+
|
541
|
+
if response.is_a?(Net::HTTPRedirection)
|
542
|
+
location = response['Location']
|
543
|
+
if location.to_s == url.to_s
|
544
|
+
log(:fatal, "circular redirection on #{ url }")
|
545
|
+
exit(1)
|
546
|
+
end
|
547
|
+
return http_get(location)
|
548
|
+
end
|
549
|
+
|
550
|
+
code = response.code.to_i rescue 500
|
551
|
+
body = response.body.to_s rescue ''
|
552
|
+
|
553
|
+
[code, body]
|
554
|
+
end
|
555
|
+
|
556
|
+
#
|
557
|
+
def to_s
|
558
|
+
@directory.to_s
|
559
|
+
end
|
560
|
+
|
561
|
+
#
|
562
|
+
def log(level, *args, &block)
|
563
|
+
@logger.send(level, *args, &block)
|
564
|
+
end
|
565
|
+
|
566
|
+
#
|
567
|
+
def path_for(url)
|
568
|
+
uri = uri_for(url)
|
569
|
+
|
570
|
+
case
|
571
|
+
when uri.path=='/' || uri.path=='.'
|
572
|
+
path = File.join(@directory, 'index.html')
|
573
|
+
else
|
574
|
+
path = File.join(@directory, uri.path)
|
575
|
+
dirname, basename = File.split(path)
|
576
|
+
base, ext = basename.split('.', 2)
|
577
|
+
if ext.nil?
|
578
|
+
path = File.join(path, 'index.html')
|
579
|
+
end
|
580
|
+
end
|
581
|
+
path
|
582
|
+
end
|
583
|
+
|
584
|
+
#
|
585
|
+
def write_path(path, body)
|
586
|
+
FileUtils.mkdir_p(File.dirname(path))
|
587
|
+
IO.binwrite(path, body)
|
588
|
+
end
|
589
|
+
|
590
|
+
#
|
591
|
+
def ensure_non_digested_assets_also_exist!(assets)
|
592
|
+
re = /(-{1}[a-z0-9]{32}*\.{1}){1}/
|
593
|
+
|
594
|
+
assets.each do |file|
|
595
|
+
next if File.directory?(file) || file !~ re
|
596
|
+
source = file.split('/')
|
597
|
+
source.push(source.pop.gsub(re, '.'))
|
598
|
+
non_digested = File.join(source)
|
599
|
+
#log(:debug, "asset: #{ file } -> #{ non_digested }")
|
600
|
+
FileUtils.ln(file, non_digested)
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
#
|
605
|
+
def url_for(url)
|
606
|
+
uri = URI.parse(url.to_s)
|
607
|
+
|
608
|
+
if uri.absolute?
|
609
|
+
uri.to_s
|
610
|
+
else
|
611
|
+
relative_uri = URI.parse(@url)
|
612
|
+
relative_uri.path = absolute_path_for(uri.path)
|
613
|
+
relative_uri.query = uri.query
|
614
|
+
relative_uri.fragment = uri.fragment
|
615
|
+
relative_uri.to_s
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
#
|
620
|
+
def uri_for(url)
|
621
|
+
uri = url.is_a?(URI) ? url : URI.parse(url.to_s)
|
622
|
+
end
|
623
|
+
|
624
|
+
#
|
625
|
+
def hms(seconds)
|
626
|
+
return unless seconds
|
627
|
+
"%02d:%02d:%02d" % hours_minutes_seconds(seconds)
|
628
|
+
end
|
629
|
+
|
630
|
+
#
|
631
|
+
def hours_minutes_seconds(seconds)
|
632
|
+
return unless seconds
|
633
|
+
seconds = Float(seconds).to_i
|
634
|
+
hours, seconds = seconds.divmod(3600)
|
635
|
+
minutes, seconds = seconds.divmod(60)
|
636
|
+
[hours.to_i, minutes.to_s, seconds]
|
637
|
+
end
|
638
|
+
|
639
|
+
#
|
640
|
+
def stopwatch(&block)
|
641
|
+
a = Time.now
|
642
|
+
result = block.call
|
643
|
+
b = Time.now
|
644
|
+
[result, b.to_f - a.to_f]
|
645
|
+
end
|
646
|
+
|
647
|
+
#
|
648
|
+
def port_open?(port, options = {})
|
649
|
+
seconds = options[:timeout] || 1
|
650
|
+
ip = options[:ip] || '0.0.0.0'
|
651
|
+
|
652
|
+
Timeout::timeout(seconds) do
|
653
|
+
begin
|
654
|
+
TCPSocket.new(ip, port).close
|
655
|
+
false
|
656
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
657
|
+
true
|
658
|
+
rescue Object
|
659
|
+
false
|
660
|
+
end
|
661
|
+
end
|
662
|
+
rescue Timeout::Error
|
663
|
+
false
|
664
|
+
end
|
665
|
+
|
666
|
+
#
|
667
|
+
def paths_for(*args)
|
668
|
+
path = args.flatten.compact.join('/')
|
669
|
+
path.gsub!(%r|[.]+/|, '/')
|
670
|
+
path.squeeze!('/')
|
671
|
+
path.sub!(%r|^/|, '')
|
672
|
+
path.sub!(%r|/$|, '')
|
673
|
+
paths = path.split('/')
|
674
|
+
end
|
675
|
+
|
676
|
+
#
|
677
|
+
def absolute_path_for(*args)
|
678
|
+
path = ('/' + paths_for(*args).join('/')).squeeze('/')
|
679
|
+
path unless path.strip.empty?
|
680
|
+
end
|
681
|
+
|
682
|
+
#
|
683
|
+
def relative_path_for(*args)
|
684
|
+
path = absolute_path_for(*args).sub(%r{^/+}, '')
|
685
|
+
path unless path.strip.empty?
|
686
|
+
end
|
687
|
+
|
688
|
+
#
|
689
|
+
def relative_path(path, *args)
|
690
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
691
|
+
path = path.to_s
|
692
|
+
relative = args.shift || options[:relative] || options[:to] || options[:from]
|
693
|
+
if relative
|
694
|
+
Pathname.new(path).relative_path_from(Pathname.new(relative.to_s)).to_s
|
695
|
+
else
|
696
|
+
relative_path_for(path)
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
#
|
701
|
+
def spawn(command)
|
702
|
+
oe = `#{ command } 2>&1`
|
703
|
+
|
704
|
+
unless $? == 0
|
705
|
+
msg = "command(#{ command }) failed with (#{ $? })"
|
706
|
+
log(:error, msg)
|
707
|
+
raise(msg)
|
708
|
+
end
|
709
|
+
|
710
|
+
oe
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
#
|
715
|
+
class Server
|
716
|
+
def Server.for(type, cli, *args, &block)
|
717
|
+
type = type.to_s.strip.downcase
|
718
|
+
|
719
|
+
case type
|
720
|
+
when /puma/
|
721
|
+
Puma.new(cli, *args, &block)
|
722
|
+
when /passenger/
|
723
|
+
Passenger.new(cli, *args, &block)
|
724
|
+
else
|
725
|
+
nil
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|
729
|
+
def initialize(cli)
|
730
|
+
@cli = cli
|
731
|
+
end
|
732
|
+
|
733
|
+
def setup!
|
734
|
+
nil
|
735
|
+
end
|
736
|
+
|
737
|
+
class Puma < Server
|
738
|
+
def initialize(cli)
|
739
|
+
@cli = cli
|
740
|
+
|
741
|
+
@env = @cli.env
|
742
|
+
@directory = @cli.directory
|
743
|
+
@rails_root = @cli.rails_root
|
744
|
+
@parallel = @cli.parallel
|
745
|
+
|
746
|
+
@puma = "bundle exec puma"
|
747
|
+
@pumactl = "bundle exec pumactl"
|
748
|
+
|
749
|
+
@pidfile = @cli.relative_path(File.join(@directory, ".puma-pid.txt"), :from => @cli.rails_root)
|
750
|
+
@statefile = @cli.relative_path(File.join(@directory, ".puma-state.txt"), :from => @cli.rails_root)
|
751
|
+
end
|
752
|
+
|
753
|
+
def start_command_for(port)
|
754
|
+
%W[
|
755
|
+
#{ @puma }
|
756
|
+
--pidfile=#{ @pidfile }
|
757
|
+
--state=#{ @statefile }
|
758
|
+
--port=#{ port }
|
759
|
+
--environment=#{ @env }
|
760
|
+
--workers=#{ @parallel }
|
761
|
+
--config=/dev/null
|
762
|
+
--threads=1:1
|
763
|
+
--preload
|
764
|
+
--daemon
|
765
|
+
./config.ru
|
766
|
+
].join(' ').strip
|
767
|
+
end
|
768
|
+
|
769
|
+
def stop_command_for(port)
|
770
|
+
%W[
|
771
|
+
#{ @pumactl }
|
772
|
+
--pidfile=#{ @pidfile }
|
773
|
+
--state=#{ @statefile }
|
774
|
+
stop
|
775
|
+
].join(' ').strip
|
776
|
+
end
|
777
|
+
|
778
|
+
def cleanup!(*args)
|
779
|
+
nil
|
780
|
+
end
|
781
|
+
end
|
782
|
+
|
783
|
+
class Passenger < Server
|
784
|
+
def initialize(cli)
|
785
|
+
@cli = cli
|
786
|
+
|
787
|
+
@env = @cli.env
|
788
|
+
@directory = @cli.directory
|
789
|
+
@rails_root = @cli.rails_root
|
790
|
+
@parallel = @cli.parallel
|
791
|
+
|
792
|
+
@passenger = "bundle exec passenger"
|
793
|
+
end
|
794
|
+
|
795
|
+
def start_command_for(port)
|
796
|
+
"#{ @passenger } start --daemonize --environment #{ @env } --port #{ port } --max-pool-size #{ @parallel }"
|
797
|
+
end
|
798
|
+
|
799
|
+
def stop_command_for(port)
|
800
|
+
"#{ @passenger } stop --port #{ port }"
|
801
|
+
end
|
802
|
+
|
803
|
+
def cleanup!(*args)
|
804
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
805
|
+
port = options[:port]
|
806
|
+
FileUtils.rm_rf("#{ @rails_root }/tmp/pids/passenger.#{ port }.pid")
|
807
|
+
end
|
808
|
+
|
809
|
+
def setup!
|
810
|
+
begin
|
811
|
+
require 'phusion_passenger'
|
812
|
+
rescue LoadError => le
|
813
|
+
abort "please add `gem 'passenger'` to your Gemfile"
|
814
|
+
end
|
815
|
+
end
|
816
|
+
end
|
817
|
+
end
|
730
818
|
end
|