dockerfile-rails 1.0.18 → 1.1.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/DEMO.md +61 -27
- data/MOTIVATION.md +58 -0
- data/README.md +25 -9
- data/Rakefile +5 -3
- data/lib/dockerfile-rails/scanner.rb +29 -28
- data/lib/dockerfile-rails.rb +5 -3
- data/lib/generators/dockerfile_generator.rb +302 -174
- data/lib/generators/templates/Dockerfile.erb +32 -6
- data/lib/generators/templates/docker-compose.yml.erb +9 -0
- metadata +3 -2
@@ -1,40 +1,45 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "erb"
|
4
|
+
require_relative "../dockerfile-rails/scanner.rb"
|
3
5
|
|
4
6
|
class DockerfileGenerator < Rails::Generators::Base
|
5
7
|
include DockerfileRails::Scanner
|
6
8
|
|
7
|
-
OPTION_DEFAULTS =
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
9
|
+
OPTION_DEFAULTS = {
|
10
|
+
"bin-cd" => false,
|
11
|
+
"cache" => false,
|
12
|
+
"ci" => false,
|
13
|
+
"compose" => false,
|
14
|
+
"fullstaq" => false,
|
15
|
+
"jemalloc" => false,
|
16
|
+
"label" => {},
|
17
|
+
"mysql" => false,
|
18
|
+
"nginx" => false,
|
19
|
+
"parallel" => false,
|
20
|
+
"platform" => nil,
|
21
|
+
"postgresql" => false,
|
22
|
+
"precompile" => nil,
|
23
|
+
"prepare" => true,
|
24
|
+
"redis" => false,
|
25
|
+
"root" => false,
|
26
|
+
"sqlite3" => false,
|
27
|
+
"swap" => nil,
|
28
|
+
"yjit" => false,
|
29
|
+
}.then { |hash| Struct.new(*hash.keys.map(&:to_sym)).new(*hash.values) }
|
27
30
|
|
28
31
|
@@labels = {}
|
29
|
-
@@packages = {"base" => [], "build" => [], "deploy" => []}
|
32
|
+
@@packages = { "base" => [], "build" => [], "deploy" => [] }
|
33
|
+
@@vars = { "base" => {}, "build" => {}, "deploy" => {} }
|
34
|
+
@@args = { "base" => {}, "build" => {}, "deploy" => {} }
|
30
35
|
|
31
36
|
# load defaults from config file
|
32
|
-
if File.exist?
|
33
|
-
options = YAML.safe_load(IO.read(
|
37
|
+
if File.exist? "config/dockerfile.yml"
|
38
|
+
options = YAML.safe_load(IO.read("config/dockerfile.yml"), symbolize_names: true)[:options]
|
34
39
|
|
35
40
|
if options
|
36
41
|
OPTION_DEFAULTS.to_h.each do |option, value|
|
37
|
-
OPTION_DEFAULTS[option] = options[option] if options.include? option
|
42
|
+
OPTION_DEFAULTS[option] = options[option] if options.include? option
|
38
43
|
end
|
39
44
|
|
40
45
|
if options[:packages]
|
@@ -43,90 +48,124 @@ class DockerfileGenerator < Rails::Generators::Base
|
|
43
48
|
end
|
44
49
|
end
|
45
50
|
|
51
|
+
if options[:envs]
|
52
|
+
options[:envs].each do |stage, vars|
|
53
|
+
@@vars[stage.to_s] = vars.stringify_keys
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
if options[:args]
|
58
|
+
options[:args].each do |stage, vars|
|
59
|
+
@@args[stage.to_s] = vars.stringify_keys
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
46
63
|
@@labels = options[:label].stringify_keys if options.include? :label
|
47
64
|
end
|
48
65
|
end
|
49
66
|
|
50
67
|
class_option :ci, type: :boolean, default: OPTION_DEFAULTS.ci,
|
51
|
-
desc:
|
68
|
+
desc: "include test gems in bundle"
|
52
69
|
|
53
70
|
class_option :precompile, type: :string, default: OPTION_DEFAULTS.precompile,
|
54
71
|
desc: 'if set to "defer", assets:precompile will be done at deploy time'
|
55
72
|
|
56
|
-
class_option
|
57
|
-
desc:
|
73
|
+
class_option "bin-cd", type: :boolean, default: OPTION_DEFAULTS["bin-cd"],
|
74
|
+
desc: "modify binstubs to set working directory"
|
58
75
|
|
59
76
|
class_option :cache, type: :boolean, default: OPTION_DEFAULTS.cache,
|
60
|
-
desc:
|
77
|
+
desc: "use build cache to speed up installs"
|
61
78
|
|
62
79
|
class_option :prepare, type: :boolean, default: OPTION_DEFAULTS.prepare,
|
63
|
-
desc:
|
80
|
+
desc: "include db:prepare step"
|
64
81
|
|
65
82
|
class_option :parallel, type: :boolean, default: OPTION_DEFAULTS.parallel,
|
66
|
-
desc:
|
83
|
+
desc: "use build stages to install gems and node modules in parallel"
|
67
84
|
|
68
85
|
class_option :swap, type: :string, default: OPTION_DEFAULTS.swap,
|
69
|
-
desc:
|
86
|
+
desc: "allocate swapspace"
|
70
87
|
|
71
88
|
class_option :compose, type: :boolean, default: OPTION_DEFAULTS.compose,
|
72
|
-
desc:
|
89
|
+
desc: "generate a docker-compose.yml file"
|
73
90
|
|
74
91
|
class_option :redis, type: :boolean, default: OPTION_DEFAULTS.redis,
|
75
|
-
desc:
|
92
|
+
desc: "include redis libraries"
|
76
93
|
|
77
|
-
class_option :sqlite3, aliases:
|
78
|
-
desc:
|
94
|
+
class_option :sqlite3, aliases: "--sqlite", type: :boolean, default: OPTION_DEFAULTS.sqlite3,
|
95
|
+
desc: "include sqlite3 libraries"
|
79
96
|
|
80
|
-
class_option :postgresql, aliases:
|
81
|
-
desc:
|
97
|
+
class_option :postgresql, aliases: "--postgres", type: :boolean, default: OPTION_DEFAULTS.postgresql,
|
98
|
+
desc: "include postgresql libraries"
|
82
99
|
|
83
100
|
class_option :mysql, type: :boolean, default: OPTION_DEFAULTS.mysql,
|
84
|
-
desc:
|
101
|
+
desc: "include mysql libraries"
|
85
102
|
|
86
103
|
class_option :platform, type: :string, default: OPTION_DEFAULTS.platform,
|
87
|
-
desc:
|
104
|
+
desc: "image platform (example: linux/arm64)"
|
88
105
|
|
89
106
|
class_option :jemalloc, type: :boolean, default: OPTION_DEFAULTS.jemalloc,
|
90
|
-
desc:
|
91
|
-
|
107
|
+
desc: "use jemalloc alternative malloc implementation"
|
108
|
+
|
92
109
|
class_option :fullstaq, type: :boolean, default: OPTION_DEFAULTS.fullstaq,
|
93
|
-
descr:
|
110
|
+
descr: "use Fullstaq Ruby image from Quay.io"
|
94
111
|
|
95
112
|
class_option :yjit, type: :boolean, default: OPTION_DEFAULTS.yjit,
|
96
|
-
desc:
|
113
|
+
desc: "enable YJIT optimizing compiler"
|
97
114
|
|
98
115
|
class_option :label, type: :hash, default: {},
|
99
|
-
desc:
|
116
|
+
desc: "Add Docker label(s)"
|
100
117
|
|
101
118
|
class_option :nginx, type: :boolean, default: OPTION_DEFAULTS.nginx,
|
102
|
-
desc:
|
119
|
+
desc: "Serve static files with nginx"
|
103
120
|
|
104
121
|
class_option :root, type: :boolean, default: OPTION_DEFAULTS.root,
|
105
|
-
desc:
|
122
|
+
desc: "Run application as root user"
|
123
|
+
|
124
|
+
|
125
|
+
class_option "add-base", type: :array, default: [],
|
126
|
+
desc: "additional packages to install for both build and deploy"
|
127
|
+
|
128
|
+
class_option "add-build", type: :array, default: [],
|
129
|
+
desc: "additional packages to install for use during build"
|
130
|
+
|
131
|
+
class_option "add-deploy", aliases: "--add", type: :array, default: [],
|
132
|
+
desc: "additional packages to install for deployment"
|
133
|
+
|
134
|
+
class_option "remove-base", type: :array, default: [],
|
135
|
+
desc: "remove from list of base packages"
|
136
|
+
|
137
|
+
class_option "remove-build", type: :array, default: [],
|
138
|
+
desc: "remove from list of build packages"
|
139
|
+
|
140
|
+
class_option "remove-deploy", aliases: "--remove", type: :array, default: [],
|
141
|
+
desc: "remove from list of deploy packages"
|
142
|
+
|
106
143
|
|
107
|
-
class_option
|
108
|
-
desc:
|
144
|
+
class_option "env-base", type: :hash, default: {},
|
145
|
+
desc: "additional environment variables for both build and deploy"
|
109
146
|
|
110
|
-
class_option
|
111
|
-
desc:
|
147
|
+
class_option "env-build", type: :hash, default: {},
|
148
|
+
desc: "additional environment variables to set during build"
|
112
149
|
|
113
|
-
class_option
|
114
|
-
desc:
|
150
|
+
class_option "env-deploy", aliases: "--env", type: :hash, default: {},
|
151
|
+
desc: "additional environment variables to set for deployment"
|
115
152
|
|
116
|
-
class_option 'remove-base', type: :array, default: [],
|
117
|
-
desc: 'remove from list of base packages'
|
118
153
|
|
119
|
-
class_option
|
120
|
-
desc:
|
154
|
+
class_option "arg-base", aliases: "--arg", type: :hash, default: {},
|
155
|
+
desc: "additional build arguments for both build and deploy"
|
156
|
+
|
157
|
+
class_option "arg-build", type: :hash, default: {},
|
158
|
+
desc: "additional build arguments to set during build"
|
159
|
+
|
160
|
+
class_option "arg-deploy", type: :hash, default: {},
|
161
|
+
desc: "additional build arguments to set for deployment"
|
121
162
|
|
122
|
-
class_option 'remove-deploy', aliases: '--remove', type: :array, default: [],
|
123
|
-
desc: 'remove from list of deploy packages'
|
124
163
|
|
125
164
|
def generate_app
|
126
|
-
source_paths.push File.expand_path(
|
165
|
+
source_paths.push File.expand_path("./templates", __dir__)
|
127
166
|
|
128
167
|
# merge options
|
129
|
-
options.label.replace(@@labels.merge(options.label).select {|key, value| value !=
|
168
|
+
options.label.replace(@@labels.merge(options.label).select { |key, value| value != "" })
|
130
169
|
|
131
170
|
# gather up options for config file
|
132
171
|
@dockerfile_config = OPTION_DEFAULTS.dup.to_h.stringify_keys
|
@@ -134,57 +173,68 @@ class DockerfileGenerator < Rails::Generators::Base
|
|
134
173
|
@dockerfile_config[option] = value if @dockerfile_config.include? option
|
135
174
|
end
|
136
175
|
|
137
|
-
# apply requested package changes
|
138
176
|
%w(base build deploy).each do |phase|
|
139
177
|
@@packages[phase] += options["add-#{phase}"]
|
140
178
|
@@packages[phase] -= options["remove-#{phase}"]
|
141
179
|
@@packages[phase].uniq!
|
142
180
|
@@packages.delete phase if @@packages[phase].empty?
|
181
|
+
|
182
|
+
@@vars[phase].merge! options["env-#{phase}"]
|
183
|
+
@@vars[phase].delete_if { |key, value| value.blank? }
|
184
|
+
@@vars.delete phase if @@vars[phase].empty?
|
185
|
+
|
186
|
+
@@args[phase].merge! options["arg-#{phase}"]
|
187
|
+
@@args[phase].delete_if { |key, value| value.blank? }
|
188
|
+
@@args.delete phase if @@args[phase].empty?
|
143
189
|
end
|
144
190
|
|
145
|
-
@dockerfile_config[
|
191
|
+
@dockerfile_config["packages"] = @@packages
|
192
|
+
@dockerfile_config["envs"] = @@vars
|
193
|
+
@dockerfile_config["args"] = @@args
|
146
194
|
|
147
195
|
scan_rails_app
|
148
196
|
|
149
197
|
Bundler.with_original_env { install_gems }
|
150
198
|
|
151
|
-
template
|
152
|
-
template
|
199
|
+
template "Dockerfile.erb", "Dockerfile"
|
200
|
+
template "dockerignore.erb", ".dockerignore"
|
153
201
|
|
154
|
-
if using_node?
|
155
|
-
template
|
202
|
+
if using_node? && node_version =~ (/\A\d+\.\d+\.\d+\z/)
|
203
|
+
template "node-version.erb", ".node-version"
|
156
204
|
end
|
157
205
|
|
158
|
-
template
|
206
|
+
template "docker-entrypoint.erb", "bin/docker-entrypoint"
|
159
207
|
chmod "bin/docker-entrypoint", 0755 & ~File.umask, verbose: false
|
160
208
|
|
161
|
-
template
|
209
|
+
template "docker-compose.yml.erb", "docker-compose.yml" if options.compose
|
162
210
|
|
163
|
-
template
|
211
|
+
template "dockerfile.yml.erb", "config/dockerfile.yml", force: true
|
164
212
|
|
165
|
-
if @gemfile.include?(
|
166
|
-
package = JSON.load_file(
|
167
|
-
unless package.dig(
|
168
|
-
package[
|
169
|
-
package[
|
213
|
+
if @gemfile.include?("vite_ruby")
|
214
|
+
package = JSON.load_file("package.json")
|
215
|
+
unless package.dig("scripts", "build")
|
216
|
+
package["scripts"] ||= {}
|
217
|
+
package["scripts"]["build"] = "vite build --outDir public"
|
170
218
|
|
171
|
-
say_status :update,
|
172
|
-
IO.write(
|
219
|
+
say_status :update, "package.json"
|
220
|
+
IO.write("package.json", JSON.pretty_generate(package))
|
173
221
|
end
|
174
222
|
end
|
175
223
|
end
|
176
224
|
|
177
225
|
private
|
178
|
-
|
179
226
|
def render(options)
|
180
227
|
scope = (Class.new do
|
181
228
|
def initialize(obj, locals)
|
182
229
|
@_obj = obj
|
183
|
-
@_locals =
|
230
|
+
@_locals = locals.then do |hash|
|
231
|
+
return nil if hash.empty?
|
232
|
+
Struct.new(*hash.keys.map(&:to_sym)).new(*hash.values)
|
233
|
+
end
|
184
234
|
end
|
185
235
|
|
186
236
|
def method_missing(method, *args, &block)
|
187
|
-
if @_locals
|
237
|
+
if @_locals&.respond_to? method
|
188
238
|
@_locals.send method, *args, &block
|
189
239
|
else
|
190
240
|
@_obj.send method, *args, &block
|
@@ -197,7 +247,7 @@ private
|
|
197
247
|
end).new(self, options[:locals] || {})
|
198
248
|
|
199
249
|
template = IO.read(File.join(source_paths.last, "_#{options[:partial]}.erb"))
|
200
|
-
ERB.new(template, trim_mode:
|
250
|
+
ERB.new(template, trim_mode: "-").result(scope.get_binding).strip
|
201
251
|
end
|
202
252
|
|
203
253
|
def platform
|
@@ -209,28 +259,28 @@ private
|
|
209
259
|
end
|
210
260
|
|
211
261
|
def run_as_root?
|
212
|
-
|
262
|
+
options.root? || options.nginx? # needed to access /dev/stdout
|
213
263
|
end
|
214
264
|
|
215
265
|
def using_node?
|
216
266
|
return @using_node if @using_node != nil
|
217
|
-
@using_node = File.exist?
|
267
|
+
@using_node = File.exist? "package.json"
|
218
268
|
end
|
219
269
|
|
220
270
|
def using_redis?
|
221
|
-
options.redis? or @redis or @gemfile.include?(
|
271
|
+
options.redis? or @redis or @gemfile.include?("sidekiq")
|
222
272
|
end
|
223
273
|
|
224
274
|
def using_execjs?
|
225
|
-
@gemfile.include?(
|
275
|
+
@gemfile.include?("execjs") or @gemfile.include?("grover")
|
226
276
|
end
|
227
277
|
|
228
278
|
def using_puppeteer?
|
229
|
-
@gemfile.include?(
|
279
|
+
@gemfile.include?("grover") or @gemfile.include?("puppeteer-ruby")
|
230
280
|
end
|
231
281
|
|
232
282
|
def using_sidekiq?
|
233
|
-
@gemfile.include?(
|
283
|
+
@gemfile.include?("sidekiq")
|
234
284
|
end
|
235
285
|
|
236
286
|
def parallel?
|
@@ -239,26 +289,26 @@ private
|
|
239
289
|
|
240
290
|
def keeps?
|
241
291
|
return @keeps if @keeps != nil
|
242
|
-
@keeps = !!Dir[
|
292
|
+
@keeps = !!Dir["**/.keep"]
|
243
293
|
end
|
244
294
|
|
245
295
|
def install_gems
|
246
|
-
if options.postgresql?
|
247
|
-
system "bundle add pg" unless @gemfile.include?
|
296
|
+
if options.postgresql? || @postgresql
|
297
|
+
system "bundle add pg" unless @gemfile.include? "pg"
|
248
298
|
end
|
249
299
|
|
250
|
-
if options.mysql?
|
251
|
-
system "bundle add mysql2" unless @gemfile.include?
|
300
|
+
if options.mysql? || @mysql
|
301
|
+
system "bundle add mysql2" unless @gemfile.include? "mysql2"
|
252
302
|
end
|
253
303
|
|
254
|
-
if options.redis?
|
255
|
-
system "bundle add redis" unless @gemfile.include?
|
304
|
+
if options.redis? || using_redis?
|
305
|
+
system "bundle add redis" unless @gemfile.include? "redis"
|
256
306
|
end
|
257
307
|
end
|
258
308
|
|
259
309
|
def base_packages
|
260
310
|
packages = []
|
261
|
-
packages += @@packages[
|
311
|
+
packages += @@packages["base"] if @@packages["base"]
|
262
312
|
|
263
313
|
if using_execjs?
|
264
314
|
packages += %w(curl unzip)
|
@@ -270,10 +320,10 @@ private
|
|
270
320
|
|
271
321
|
# charlock_holmes. Placed here as the library itself is
|
272
322
|
# libicu63 in buster, libicu67 in bullseye, libiclu72 in bookworm...
|
273
|
-
packages << "libicu-dev" if @gemfile.include?
|
323
|
+
packages << "libicu-dev" if @gemfile.include? "charlock_holmes"
|
274
324
|
|
275
325
|
|
276
|
-
if @gemfile.include?
|
326
|
+
if @gemfile.include? "webp-ffi"
|
277
327
|
# https://github.com/le0pard/webp-ffi#requirements
|
278
328
|
packages += %w(libjpeg-dev libpng-dev libtiff-dev libwebp-dev)
|
279
329
|
end
|
@@ -283,38 +333,38 @@ private
|
|
283
333
|
|
284
334
|
def base_requirements
|
285
335
|
requirements = []
|
286
|
-
requirements <<
|
287
|
-
requirements <<
|
288
|
-
requirements << "charlock_holmes" if @gemfile.include?
|
289
|
-
requirements.join(
|
336
|
+
requirements << "nodejs" if using_execjs?
|
337
|
+
requirements << "chrome" if using_puppeteer?
|
338
|
+
requirements << "charlock_holmes" if @gemfile.include? "charlock_holmes"
|
339
|
+
requirements.join(" and ")
|
290
340
|
end
|
291
341
|
|
292
342
|
def build_packages
|
293
343
|
# start with the essentials
|
294
344
|
packages = %w(build-essential)
|
295
|
-
packages += @@packages[
|
345
|
+
packages += @@packages["build"] if @@packages["build"]
|
296
346
|
|
297
347
|
# add databases: sqlite3, postgres, mysql
|
298
|
-
packages <<
|
299
|
-
packages <<
|
300
|
-
packages <<
|
348
|
+
packages << "pkg-config" if options.sqlite3? || @sqlite3
|
349
|
+
packages << "libpq-dev" if options.postgresql? || @postgresql
|
350
|
+
packages << "default-libmysqlclient-dev" if options.mysql? || @mysql
|
301
351
|
|
302
352
|
# add git if needed to install gems
|
303
|
-
packages <<
|
353
|
+
packages << "git" if @git
|
304
354
|
|
305
355
|
# add redis if Action Cable, caching, or sidekiq are used
|
306
|
-
packages << "redis" if options.redis?
|
356
|
+
packages << "redis" if options.redis? || using_redis?
|
307
357
|
|
308
358
|
# ActiveStorage preview support
|
309
|
-
packages << "libvips" if @gemfile.include?
|
359
|
+
packages << "libvips" if @gemfile.include? "ruby-vips"
|
310
360
|
|
311
361
|
# Rmagick gem
|
312
|
-
packages += %w[pkg-config libmagickwand-dev] if @gemfile.include?
|
362
|
+
packages += %w[pkg-config libmagickwand-dev] if @gemfile.include? "rmagick"
|
313
363
|
|
314
364
|
# node support, including support for building native modules
|
315
365
|
if using_node?
|
316
366
|
packages += %w(node-gyp pkg-config)
|
317
|
-
packages += %w(curl unzip) unless using_execjs?
|
367
|
+
packages += %w(curl unzip) unless using_execjs? || using_puppeteer?
|
318
368
|
|
319
369
|
# module build process depends on Python, and debian changed
|
320
370
|
# how python is installed with the bullseye release. Below
|
@@ -343,29 +393,29 @@ private
|
|
343
393
|
|
344
394
|
def deploy_packages
|
345
395
|
packages = []
|
346
|
-
packages += @@packages[
|
396
|
+
packages += @@packages["deploy"] if @@packages["deploy"]
|
347
397
|
|
348
398
|
# start with databases: sqlite3, postgres, mysql
|
349
|
-
packages <<
|
350
|
-
packages <<
|
351
|
-
packages <<
|
399
|
+
packages << "libsqlite3-0" if options.sqlite3? || @sqlite3
|
400
|
+
packages << "postgresql-client" if options.postgresql? || @postgresql
|
401
|
+
packages << "default-mysql-client" if options.mysql || @mysql
|
352
402
|
|
353
403
|
# add redis in case Action Cable, caching, or sidekiq are added later
|
354
404
|
packages << "redis" if using_redis?
|
355
405
|
|
356
406
|
# ActiveStorage preview support
|
357
|
-
packages << "libvips" if @gemfile.include?
|
407
|
+
packages << "libvips" if @gemfile.include? "ruby-vips"
|
358
408
|
|
359
409
|
# Rmagick gem
|
360
|
-
if @gemfile.include?(
|
361
|
-
packages <<
|
410
|
+
if @gemfile.include?("rmagick") || @gemfile.include?("mini_magick")
|
411
|
+
packages << "imagemagick"
|
362
412
|
end
|
363
413
|
|
364
414
|
# Puppeteer
|
365
|
-
packages <<
|
415
|
+
packages << "google-chrome-stable" if using_puppeteer?
|
366
416
|
|
367
417
|
# nginx
|
368
|
-
packages <<
|
418
|
+
packages << "nginx" if options.nginx?
|
369
419
|
|
370
420
|
packages.sort
|
371
421
|
end
|
@@ -382,57 +432,133 @@ private
|
|
382
432
|
end
|
383
433
|
|
384
434
|
if repos.empty?
|
385
|
-
|
435
|
+
""
|
386
436
|
else
|
387
437
|
repos.join(" \\\n ") + " && \\\n "
|
388
438
|
end
|
389
439
|
end
|
390
440
|
|
441
|
+
def base_env
|
442
|
+
env = {
|
443
|
+
"RAILS_ENV" => "production",
|
444
|
+
"BUNDLE_PATH" => "vendor/bundle",
|
445
|
+
"BUNDLE_WITHOUT" => options.ci? ? "development" : "development:test"
|
446
|
+
}
|
447
|
+
|
448
|
+
if @@args["base"]
|
449
|
+
env.merge! @@args["base"].to_h { |key, value| [key, "$#{key}"] }
|
450
|
+
end
|
451
|
+
|
452
|
+
env.merge! @@vars["base"] if @@vars["base"]
|
453
|
+
|
454
|
+
env.map { |key, value| "#{key}=#{value.inspect}" }
|
455
|
+
end
|
456
|
+
|
457
|
+
def build_env
|
458
|
+
env = {}
|
459
|
+
|
460
|
+
if @@args["build"]
|
461
|
+
env.merge! @@args["build"].to_h { |key, value| [key, "$#{key}"] }
|
462
|
+
end
|
463
|
+
|
464
|
+
env.merge! @@vars["build"] if @@vars["build"]
|
465
|
+
|
466
|
+
env.map { |key, value| "#{key}=#{value.inspect}" }
|
467
|
+
end
|
468
|
+
|
391
469
|
def deploy_env
|
392
|
-
env =
|
470
|
+
env = {}
|
393
471
|
|
394
|
-
env
|
472
|
+
env["PORT"] = "3001" if options.nginx?
|
395
473
|
|
396
|
-
if Rails::VERSION::MAJOR<7 || Rails::VERSION::STRING.start_with?(
|
397
|
-
env
|
398
|
-
env
|
474
|
+
if Rails::VERSION::MAJOR < 7 || Rails::VERSION::STRING.start_with?("7.0")
|
475
|
+
env["RAILS_LOG_TO_STDOUT"] = "1"
|
476
|
+
env["RAILS_SERVE_STATIC_FILES"] = "true" unless options.nginx?
|
399
477
|
end
|
400
478
|
|
401
479
|
if options.yjit?
|
402
|
-
env
|
480
|
+
env["RUBY_YJIT_ENABLE"] = "1"
|
403
481
|
end
|
404
482
|
|
405
|
-
if options.jemalloc?
|
406
|
-
if (options.platform || Gem::Platform
|
407
|
-
env
|
483
|
+
if options.jemalloc? && (not options.fullstaq?)
|
484
|
+
if (options.platform || Gem::Platform.local.cpu).include? "arm"
|
485
|
+
env["LD_PRELOAD"] = "/usr/lib/aarch64-linux-gnu/libjemalloc.so.2"
|
408
486
|
else
|
409
|
-
env
|
487
|
+
env["LD_PRELOAD"] = "/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
|
410
488
|
end
|
411
489
|
|
412
|
-
env
|
490
|
+
env["MALLOC_CONF"] = "dirty_decay_ms:1000,narenas:2,background_thread:true"
|
413
491
|
end
|
414
492
|
|
415
493
|
if using_puppeteer?
|
416
|
-
|
417
|
-
|
418
|
-
|
494
|
+
if options.root?
|
495
|
+
env["GROVER_NO_SANDBOX"] = "true" if @gemfile.include? "grover"
|
496
|
+
env["PUPPETEER_RUBY_NO_SANDBOX"] = "1" if @gemfile.include? "puppeteer-ruby"
|
497
|
+
end
|
498
|
+
|
499
|
+
env["PUPPETEER_EXECUTABLE_PATH"] = "/usr/bin/google-chrome"
|
500
|
+
end
|
501
|
+
|
502
|
+
if @@args["deploy"]
|
503
|
+
env.merge! @@args["deploy"].to_h { |key, value| [key, "$#{key}"] }
|
504
|
+
end
|
505
|
+
|
506
|
+
env.merge! @@vars["base"] if @@vars["base"]
|
507
|
+
|
508
|
+
env.map { |key, value| "#{key}=#{value.inspect}" }
|
509
|
+
end
|
510
|
+
|
511
|
+
def base_args
|
512
|
+
args = {}
|
513
|
+
|
514
|
+
args.merge! @@args["base"] if @@args["base"]
|
515
|
+
|
516
|
+
args
|
517
|
+
end
|
518
|
+
|
519
|
+
def build_args
|
520
|
+
args = {}
|
521
|
+
|
522
|
+
args.merge! @@args["build"] if @@args["build"]
|
523
|
+
|
524
|
+
args
|
525
|
+
end
|
526
|
+
|
527
|
+
def deploy_args
|
528
|
+
args = {}
|
529
|
+
|
530
|
+
args.merge! @@args["deploy"] if @@args["deploy"]
|
531
|
+
|
532
|
+
args
|
533
|
+
end
|
534
|
+
|
535
|
+
def all_args
|
536
|
+
args = {}
|
537
|
+
|
538
|
+
unless options.root?
|
539
|
+
args[:UID] = "${UID:-1000}".html_safe
|
540
|
+
args[:GID] = "${GID:-${UID:-1000}}".html_safe
|
419
541
|
end
|
420
542
|
|
421
|
-
|
543
|
+
args.merge! base_args
|
544
|
+
args.merge! build_args
|
545
|
+
args.merge! deploy_args
|
546
|
+
|
547
|
+
args
|
422
548
|
end
|
423
549
|
|
424
550
|
def binfile_fixups
|
425
551
|
# binfiles may have OS specific paths to ruby. Normalize them.
|
426
552
|
shebangs = Dir["bin/*"].map { |file| IO.read(file).lines.first }.join
|
427
553
|
rubies = shebangs.scan(%r{#!/usr/bin/env (ruby.*)}).flatten.uniq
|
428
|
-
|
554
|
+
|
429
555
|
binfixups = (rubies - %w(ruby)).map do |ruby|
|
430
556
|
"sed -i 's/#{Regexp.quote(ruby)}$/ruby/' bin/*"
|
431
557
|
end
|
432
|
-
|
558
|
+
|
433
559
|
# Windows line endings will cause scripts to fail. If any
|
434
|
-
# or found OR this generation is run on a windows platform
|
435
|
-
# and there are other binfixups required, then convert
|
560
|
+
# or found OR this generation is run on a windows platform
|
561
|
+
# and there are other binfixups required, then convert
|
436
562
|
# line endings. This avoids adding unnecessary fixups if
|
437
563
|
# none are required, but prepares for the need to do the
|
438
564
|
# fix line endings if other fixups are required.
|
@@ -440,7 +566,7 @@ private
|
|
440
566
|
if has_cr || (Gem.win_platform? && !binfixups.empty?)
|
441
567
|
binfixups.unshift 'sed -i "s/\r$//g" bin/*'
|
442
568
|
end
|
443
|
-
|
569
|
+
|
444
570
|
# Windows file systems may not have the concept of executable.
|
445
571
|
# In such cases, fix up during the build.
|
446
572
|
unless Dir["bin/*"].all? { |file| File.executable? file }
|
@@ -448,7 +574,7 @@ private
|
|
448
574
|
end
|
449
575
|
|
450
576
|
# optionally, adjust cwd
|
451
|
-
if options[
|
577
|
+
if options["bin-cd"]
|
452
578
|
binfixups.push %{grep -l '#!/usr/bin/env ruby' /rails/bin/* | xargs sed -i '/^#!/aDir.chdir File.expand_path("..", __dir__)'}
|
453
579
|
end
|
454
580
|
|
@@ -456,50 +582,50 @@ private
|
|
456
582
|
end
|
457
583
|
|
458
584
|
def deploy_database
|
459
|
-
if options.postgresql?
|
460
|
-
|
461
|
-
elsif options.mysql
|
462
|
-
|
585
|
+
if options.postgresql? || @postgresql
|
586
|
+
"postgresql"
|
587
|
+
elsif options.mysql || @mysql
|
588
|
+
"mysql"
|
463
589
|
else
|
464
|
-
|
590
|
+
"sqlite3"
|
465
591
|
end
|
466
592
|
end
|
467
593
|
|
468
594
|
def node_version
|
469
595
|
version = nil
|
470
596
|
|
471
|
-
if File.exist?
|
472
|
-
version = IO.read(
|
597
|
+
if File.exist? ".node-version"
|
598
|
+
version = IO.read(".node-version")[/\d+\.\d+\.\d+/]
|
473
599
|
end
|
474
600
|
|
475
|
-
if !version
|
476
|
-
version = JSON.parse(IO.read(
|
477
|
-
version = nil unless
|
601
|
+
if !version && File.exist?("package.json")
|
602
|
+
version = JSON.parse(IO.read("package.json")).dig("engines", "node")
|
603
|
+
version = nil unless /\A(\d+\.)+(\d+|x)\z/.match?(version)
|
478
604
|
end
|
479
605
|
|
480
606
|
version || `node --version`[/\d+\.\d+\.\d+/]
|
481
607
|
rescue
|
482
|
-
"lts"
|
608
|
+
"lts"
|
483
609
|
end
|
484
610
|
|
485
611
|
def yarn_version
|
486
|
-
package = JSON.parse(IO.read(
|
612
|
+
package = JSON.parse(IO.read("package.json"))
|
487
613
|
|
488
|
-
if ENV[
|
614
|
+
if ENV["RAILS_ENV"] == "test"
|
489
615
|
# yarn install instructions changed in v2
|
490
|
-
version =
|
491
|
-
elsif package[
|
492
|
-
version = package[
|
616
|
+
version = "1.22.19"
|
617
|
+
elsif package["packageManager"].to_s.start_with? "yarn@"
|
618
|
+
version = package["packageManager"].sub("yarn@", "")
|
493
619
|
else
|
494
|
-
version = `yarn --version`[/\d+\.\d+\.\d+/] ||
|
620
|
+
version = `yarn --version`[/\d+\.\d+\.\d+/] || "1.22.19"
|
495
621
|
system "yarn set version #{version}"
|
496
|
-
package = JSON.parse(IO.read(
|
622
|
+
package = JSON.parse(IO.read("package.json"))
|
497
623
|
# apparently not all versions of yarn will update package.json...
|
498
624
|
end
|
499
625
|
|
500
|
-
unless package[
|
501
|
-
package[
|
502
|
-
IO.write(
|
626
|
+
unless package["packageManager"]
|
627
|
+
package["packageManager"] = "yarn@#{version}"
|
628
|
+
IO.write("package.json", JSON.pretty_generate(package))
|
503
629
|
end
|
504
630
|
|
505
631
|
version
|
@@ -508,7 +634,7 @@ private
|
|
508
634
|
end
|
509
635
|
|
510
636
|
def depend_on_bootsnap?
|
511
|
-
@gemfile.include?
|
637
|
+
@gemfile.include? "bootsnap"
|
512
638
|
end
|
513
639
|
|
514
640
|
def api_only?
|
@@ -519,13 +645,13 @@ private
|
|
519
645
|
# for specific directories.
|
520
646
|
def api_client_dir
|
521
647
|
if api_only?
|
522
|
-
scan =
|
648
|
+
scan = "*/package.json"
|
523
649
|
else
|
524
|
-
scan =
|
650
|
+
scan = "{client,frontend}/package.json"
|
525
651
|
end
|
526
652
|
|
527
653
|
file = Dir[scan].find do |file|
|
528
|
-
JSON.load_file(file).dig(
|
654
|
+
JSON.load_file(file).dig("scripts", "build")
|
529
655
|
end
|
530
656
|
|
531
657
|
file && File.dirname(file)
|
@@ -540,9 +666,9 @@ private
|
|
540
666
|
|
541
667
|
def dbprep_command
|
542
668
|
if Rails::VERSION::MAJOR >= 6
|
543
|
-
|
669
|
+
"db:prepare"
|
544
670
|
else
|
545
|
-
|
671
|
+
"db:migrate"
|
546
672
|
end
|
547
673
|
end
|
548
674
|
|
@@ -550,23 +676,25 @@ private
|
|
550
676
|
if options.nginx?
|
551
677
|
{
|
552
678
|
nginx: 'nginx -g "daemon off;"',
|
553
|
-
rails:
|
679
|
+
rails: "./bin/rails server -p 3001"
|
554
680
|
}
|
555
681
|
else
|
556
682
|
{
|
557
|
-
rails:
|
683
|
+
rails: "./bin/rails server"
|
558
684
|
}
|
559
685
|
end
|
560
686
|
end
|
561
687
|
|
562
688
|
def more_docker_ignores
|
563
|
-
more =
|
689
|
+
more = ""
|
564
690
|
|
565
|
-
if @gemfile.include?(
|
566
|
-
lines = IO.read(
|
691
|
+
if @gemfile.include?("vite_ruby")
|
692
|
+
lines = IO.read(".gitignore")[/^# Vite.*?\n\n/m].to_s.chomp.lines -
|
567
693
|
["node_modules\n"]
|
568
694
|
|
569
695
|
more += "\n" + lines.join
|
570
696
|
end
|
697
|
+
|
698
|
+
more
|
571
699
|
end
|
572
700
|
end
|