homura-runtime 0.3.6 → 0.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/exe/homura-build CHANGED
@@ -4,11 +4,11 @@
4
4
  # homura build: ERB precompile → assets embed → Opal bundle → patch-opal-evals → worker.entrypoint.mjs
5
5
  # Use --standalone for generated consumer apps (no homura inline routes).
6
6
 
7
- require 'fileutils'
8
- require 'open3'
9
- require 'optparse'
10
- require 'pathname'
11
- require_relative '../lib/homura/runtime/build_support'
7
+ require "fileutils"
8
+ require "open3"
9
+ require "optparse"
10
+ require "pathname"
11
+ require_relative "../lib/homura/runtime/build_support"
12
12
 
13
13
  module HomuraRuntimeBuild
14
14
  class << self
@@ -17,11 +17,11 @@ module HomuraRuntimeBuild
17
17
  end
18
18
 
19
19
  def runtime_dir
20
- gem_root.join('runtime')
20
+ gem_root.join("runtime")
21
21
  end
22
22
 
23
23
  def exe_path(name)
24
- gem_root.join('exe', name)
24
+ gem_root.join("exe", name)
25
25
  end
26
26
 
27
27
  def gem_lib(*names)
@@ -37,9 +37,9 @@ end
37
37
  options = {
38
38
  root: Dir.pwd,
39
39
  standalone: false,
40
- opal_input: ENV['HOMURA_OPAL_INPUT'],
41
- opal_output: ENV['HOMURA_OPAL_OUTPUT'] || 'build/hello.no-exit.mjs',
42
- patch_input: ENV['HOMURA_OPAL_PATCH_INPUT'],
40
+ opal_input: ENV["HOMURA_OPAL_INPUT"],
41
+ opal_output: ENV["HOMURA_OPAL_OUTPUT"] || "build/hello.no-exit.mjs",
42
+ patch_input: ENV["HOMURA_OPAL_PATCH_INPUT"],
43
43
  setup_import: nil,
44
44
  bundle_import: nil,
45
45
  worker_module_import: nil,
@@ -49,74 +49,133 @@ options = {
49
49
  assets_namespace: nil
50
50
  }
51
51
 
52
- OptionParser.new do |o|
53
- o.banner = 'usage: homura build [options]'
54
- o.on('--root PATH', 'Project root (default: cwd)') { |p| options[:root] = p }
55
- o.on('--standalone', 'Consumer app (skip inline-routes; use Gemfile-resolved load paths)') do
56
- options[:standalone] = true
57
- end
58
- o.on('--with-db', 'Include sequel-d1 on Opal load path (standalone)') do
59
- options[:with_db] = true
52
+ OptionParser
53
+ .new do |o|
54
+ o.banner = "usage: homura build [options]"
55
+ o.on("--root PATH", "Project root (default: cwd)") do |p|
56
+ options[:root] = p
57
+ end
58
+ o.on(
59
+ "--standalone",
60
+ "Consumer app (skip inline-routes; use Gemfile-resolved load paths)"
61
+ ) { options[:standalone] = true }
62
+ o.on("--with-db", "Include sequel-d1 on Opal load path (standalone)") do
63
+ options[:with_db] = true
64
+ end
65
+ o.on("--input PATH", "Opal entry .rb") { |p| options[:opal_input] = p }
66
+ o.on("--output PATH", "Opal bundle .mjs") { |p| options[:opal_output] = p }
67
+ o.on(
68
+ "--patch-input PATH",
69
+ "Override patch target (default: same as --output)"
70
+ ) { |p| options[:patch_input] = p }
71
+ o.on("--setup-import PATH", "setup-node-crypto import in entrypoint") do |p|
72
+ options[:setup_import] = p
73
+ end
74
+ o.on("--bundle-import PATH", "Opal bundle import in entrypoint") do |p|
75
+ options[:bundle_import] = p
76
+ end
77
+ o.on(
78
+ "--worker-module-import PATH",
79
+ "worker_module.mjs import in entrypoint"
80
+ ) { |p| options[:worker_module_import] = p }
81
+ o.on("--entrypoint-out PATH", "Where to write worker.entrypoint.mjs") do |p|
82
+ options[:entrypoint_out] = p
83
+ end
84
+ o.on(
85
+ "--templates-namespace NAME",
86
+ "Standalone templates module name (default: project-derived)"
87
+ ) { |n| options[:templates_namespace] = n }
88
+ o.on(
89
+ "--assets-namespace NAME",
90
+ "Standalone assets module name (default: project-derived)"
91
+ ) { |n| options[:assets_namespace] = n }
60
92
  end
61
- o.on('--input PATH', 'Opal entry .rb') { |p| options[:opal_input] = p }
62
- o.on('--output PATH', 'Opal bundle .mjs') { |p| options[:opal_output] = p }
63
- o.on('--patch-input PATH', 'Override patch target (default: same as --output)') { |p| options[:patch_input] = p }
64
- o.on('--setup-import PATH', 'setup-node-crypto import in entrypoint') { |p| options[:setup_import] = p }
65
- o.on('--bundle-import PATH', 'Opal bundle import in entrypoint') { |p| options[:bundle_import] = p }
66
- o.on('--worker-module-import PATH', 'worker_module.mjs import in entrypoint') { |p| options[:worker_module_import] = p }
67
- o.on('--entrypoint-out PATH', 'Where to write worker.entrypoint.mjs') { |p| options[:entrypoint_out] = p }
68
- o.on('--templates-namespace NAME', 'Standalone templates module name (default: project-derived)') { |n| options[:templates_namespace] = n }
69
- o.on('--assets-namespace NAME', 'Standalone assets module name (default: project-derived)') { |n| options[:assets_namespace] = n }
70
- end.parse!
93
+ .parse!
71
94
 
72
95
  options[:standalone] = true if options[:with_db]
73
96
 
74
97
  root = Pathname(options[:root]).expand_path
75
- options[:templates_namespace] ||= HomuraRuntime::BuildSupport.standalone_namespace(root, 'Templates') if options[:standalone]
76
- options[:assets_namespace] ||= HomuraRuntime::BuildSupport.standalone_namespace(root, 'Assets') if options[:standalone]
98
+ options[
99
+ :templates_namespace
100
+ ] ||= HomuraRuntime::BuildSupport.standalone_namespace(
101
+ root,
102
+ "Templates"
103
+ ) if options[:standalone]
104
+ options[:assets_namespace] ||= HomuraRuntime::BuildSupport.standalone_namespace(
105
+ root,
106
+ "Assets"
107
+ ) if options[:standalone]
77
108
 
78
109
  if options[:standalone]
79
- Dir.chdir(root) { require 'bundler/setup' }
110
+ Dir.chdir(root) { require "bundler/setup" }
80
111
  # Both .mjs glue files and the entrypoint live under `build/` from
81
112
  # 0.2.23 on. write_entrypoint! resolves these as project-root
82
113
  # relative paths and computes the entrypoint-relative import spec.
83
- options[:setup_import] ||= 'build/cf-runtime/setup-node-crypto.mjs'
114
+ options[:setup_import] ||= "build/cf-runtime/setup-node-crypto.mjs"
84
115
  options[:bundle_import] ||= options[:opal_output]
85
- options[:worker_module_import] ||= 'build/cf-runtime/worker_module.mjs'
86
- options[:entrypoint_out] ||= 'build/worker.entrypoint.mjs'
116
+ options[:worker_module_import] ||= "build/cf-runtime/worker_module.mjs"
117
+ options[:entrypoint_out] ||= "build/worker.entrypoint.mjs"
87
118
  else
88
- options[:setup_import] ||= 'gems/homura-runtime/runtime/setup-node-crypto.mjs'
119
+ options[:setup_import] ||= "gems/homura-runtime/runtime/setup-node-crypto.mjs"
89
120
  options[:bundle_import] ||= options[:opal_output]
90
- options[:worker_module_import] ||= 'gems/homura-runtime/runtime/worker_module.mjs'
91
- options[:entrypoint_out] ||= 'build/worker.entrypoint.mjs'
121
+ options[
122
+ :worker_module_import
123
+ ] ||= "gems/homura-runtime/runtime/worker_module.mjs"
124
+ options[:entrypoint_out] ||= "build/worker.entrypoint.mjs"
92
125
  end
93
126
 
94
127
  patch_target = options[:patch_input] || options[:opal_output]
95
128
 
96
129
  def run!(argv, chdir:)
97
130
  Dir.chdir(chdir) do
98
- system(*argv) || abort("homura build: failed: #{argv.join(' ')}")
131
+ system(*argv) || abort("homura build: failed: #{argv.join(" ")}")
99
132
  end
100
133
  end
101
134
 
102
135
  def run_opal_homura!(root, opal_input, opal_output)
103
136
  argv = [
104
- 'bundle', 'exec', 'opal',
105
- '-c', '-E', '--esm', '--no-source-map',
106
- '-I', '.',
107
- '-I', 'build/auto_await/app', '-I', 'build/auto_await', '-I', 'app',
108
- '-I', 'gems/homura-runtime/lib',
109
- '-I', 'gems/sinatra-homura/lib',
110
- '-I', 'gems/sequel-d1/lib',
111
- '-I', 'lib', '-I', 'vendor', '-I', 'build',
112
- '-r', 'opal_patches', '-r', 'homura/runtime',
113
- '-r', 'homura_templates', '-r', 'homura_assets',
114
- '-o', opal_output,
137
+ "bundle",
138
+ "exec",
139
+ "opal",
140
+ "-c",
141
+ "-E",
142
+ "--esm",
143
+ "--no-source-map",
144
+ "-I",
145
+ ".",
146
+ "-I",
147
+ "build/auto_await/app",
148
+ "-I",
149
+ "build/auto_await",
150
+ "-I",
151
+ "app",
152
+ "-I",
153
+ "gems/homura-runtime/lib",
154
+ "-I",
155
+ "gems/sinatra-homura/lib",
156
+ "-I",
157
+ "gems/sequel-d1/lib",
158
+ "-I",
159
+ "lib",
160
+ "-I",
161
+ "vendor",
162
+ "-I",
163
+ "build",
164
+ "-r",
165
+ "opal_patches",
166
+ "-r",
167
+ "homura/runtime",
168
+ "-r",
169
+ "homura_templates",
170
+ "-r",
171
+ "homura_assets",
172
+ "-o",
173
+ opal_output,
115
174
  opal_input
116
175
  ]
117
- stderr_log = root.join('build/opal.stderr.log')
118
- FileUtils.mkdir_p(root.join('build'))
119
- env = { 'OPAL_PREFORK_DISABLE' => '1' }
176
+ stderr_log = root.join("build/opal.stderr.log")
177
+ FileUtils.mkdir_p(root.join("build"))
178
+ env = { "OPAL_PREFORK_DISABLE" => "1" }
120
179
  out_err, status = Open3.capture2e(env, *argv, chdir: root.to_s)
121
180
  File.write(stderr_log, out_err)
122
181
  abort("homura build: opal failed (see #{stderr_log})") unless status.success?
@@ -127,15 +186,18 @@ def homura_vendor_from_gemfile(project_root)
127
186
  end
128
187
 
129
188
  def run_opal_standalone!(root, opal_input, opal_output, with_db:)
130
- load_paths = HomuraRuntime::BuildSupport.standalone_load_paths(root, with_db: with_db)
131
-
132
- argv = ['bundle', 'exec', 'opal', '-c', '-E', '--esm', '--no-source-map']
133
- load_paths.each { |p| argv.push('-I', p) }
134
- argv += %w[-r opal_patches -r homura/runtime -r app_templates -r app_assets -o] + [opal_output, opal_input]
135
-
136
- stderr_log = root.join('build/opal.stderr.log')
137
- FileUtils.mkdir_p(root.join('build'))
138
- env = { 'OPAL_PREFORK_DISABLE' => '1' }
189
+ load_paths =
190
+ HomuraRuntime::BuildSupport.standalone_load_paths(root, with_db: with_db)
191
+
192
+ argv = %w[bundle exec opal -c -E --esm --no-source-map]
193
+ load_paths.each { |p| argv.push("-I", p) }
194
+ argv +=
195
+ %w[-r opal_patches -r homura/runtime -r app_templates -r app_assets -o] +
196
+ [opal_output, opal_input]
197
+
198
+ stderr_log = root.join("build/opal.stderr.log")
199
+ FileUtils.mkdir_p(root.join("build"))
200
+ env = { "OPAL_PREFORK_DISABLE" => "1" }
139
201
  out_err, status = Open3.capture2e(env, *argv, chdir: root.to_s)
140
202
  File.write(stderr_log, out_err)
141
203
  abort("homura build: opal failed (see #{stderr_log})") unless status.success?
@@ -155,25 +217,27 @@ end
155
217
 
156
218
  def relative_import_spec(from_dir, target_path)
157
219
  rel = Pathname(target_path).relative_path_from(Pathname(from_dir)).to_s
158
- rel.start_with?('.', '/') ? rel : "./#{rel}"
220
+ rel.start_with?(".", "/") ? rel : "./#{rel}"
159
221
  end
160
222
 
161
223
  def resolve_opal_input(root, explicit_input)
162
224
  return explicit_input if explicit_input
163
225
 
164
- candidates = ['config.ru', 'app/hello.rb', 'app/app.rb']
226
+ candidates = %w[config.ru app/hello.rb app/app.rb]
165
227
  found = candidates.find { |path| root.join(path).file? }
166
228
  return found if found
167
229
 
168
- abort("homura build: no default entrypoint found (looked for #{candidates.join(', ')})")
230
+ abort(
231
+ "homura build: no default entrypoint found (looked for #{candidates.join(", ")})"
232
+ )
169
233
  end
170
234
 
171
235
  def prepare_opal_input(root, input_path)
172
236
  rel = Pathname(input_path)
173
237
  rel = root.join(rel).relative_path_from(root) if rel.absolute?
174
- return [rel.to_s, nil] unless rel.extname == '.ru'
238
+ return rel.to_s, nil unless rel.extname == ".ru"
175
239
 
176
- tmp_dir = root.join('build', 'auto_await')
240
+ tmp_dir = root.join("build", "auto_await")
177
241
  tmp_dir = root unless tmp_dir.directory?
178
242
  tmp = tmp_dir.join(".homura-build-#{rel.basename}.rb")
179
243
  FileUtils.mkdir_p(tmp.dirname)
@@ -182,38 +246,52 @@ def prepare_opal_input(root, input_path)
182
246
  end
183
247
 
184
248
  unless options[:standalone]
185
- run!(['ruby', 'bin/inline-routes-for-opal'], chdir: root)
249
+ run!(%w[ruby bin/inline-routes-for-opal], chdir: root)
186
250
  run!(
187
251
  [
188
- 'ruby', HomuraRuntimeBuild.exe_path('auto-await').to_s,
189
- '--input', 'app',
190
- '--output', 'build/auto_await/app'
252
+ "ruby",
253
+ HomuraRuntimeBuild.exe_path("auto-await").to_s,
254
+ "--input",
255
+ "app",
256
+ "--output",
257
+ "build/auto_await/app"
191
258
  ],
192
259
  chdir: root
193
260
  )
194
261
  run!(
195
262
  [
196
- 'ruby', HomuraRuntimeBuild.exe_path('auto-await').to_s,
197
- '--input', 'build/routes_app_class_eval.rb',
198
- '--output', 'build/auto_await/routes_app_class_eval.rb'
263
+ "ruby",
264
+ HomuraRuntimeBuild.exe_path("auto-await").to_s,
265
+ "--input",
266
+ "build/routes_app_class_eval.rb",
267
+ "--output",
268
+ "build/auto_await/routes_app_class_eval.rb"
199
269
  ],
200
270
  chdir: root
201
271
  )
202
272
  run!(
203
273
  [
204
- 'ruby', HomuraRuntimeBuild.exe_path('compile-erb').to_s,
205
- '--input', 'views',
206
- '--output', 'build/homura_templates.rb',
207
- '--namespace', 'HomuraTemplates'
274
+ "ruby",
275
+ HomuraRuntimeBuild.exe_path("compile-erb").to_s,
276
+ "--input",
277
+ "views",
278
+ "--output",
279
+ "build/homura_templates.rb",
280
+ "--namespace",
281
+ "HomuraTemplates"
208
282
  ],
209
283
  chdir: root
210
284
  )
211
285
  run!(
212
286
  [
213
- 'ruby', HomuraRuntimeBuild.exe_path('compile-assets').to_s,
214
- '--input', 'public',
215
- '--output', 'build/homura_assets.rb',
216
- '--namespace', 'HomuraAssets'
287
+ "ruby",
288
+ HomuraRuntimeBuild.exe_path("compile-assets").to_s,
289
+ "--input",
290
+ "public",
291
+ "--output",
292
+ "build/homura_assets.rb",
293
+ "--namespace",
294
+ "HomuraAssets"
217
295
  ],
218
296
  chdir: root
219
297
  )
@@ -229,22 +307,33 @@ unless options[:standalone]
229
307
  FileUtils.rm_f(temp_input) if temp_input
230
308
  end
231
309
  else
232
- HomuraRuntime::BuildSupport.ensure_standalone_runtime(root, current_file: __FILE__)
310
+ HomuraRuntime::BuildSupport.ensure_standalone_runtime(
311
+ root,
312
+ current_file: __FILE__
313
+ )
233
314
  run!(
234
315
  [
235
- 'ruby', HomuraRuntimeBuild.exe_path('compile-erb').to_s,
236
- '--input', 'views',
237
- '--output', 'build/app_templates.rb',
238
- '--namespace', options[:templates_namespace]
316
+ "ruby",
317
+ HomuraRuntimeBuild.exe_path("compile-erb").to_s,
318
+ "--input",
319
+ "views",
320
+ "--output",
321
+ "build/app_templates.rb",
322
+ "--namespace",
323
+ options[:templates_namespace]
239
324
  ],
240
325
  chdir: root
241
326
  )
242
327
  run!(
243
328
  [
244
- 'ruby', HomuraRuntimeBuild.exe_path('compile-assets').to_s,
245
- '--input', 'public',
246
- '--output', 'build/app_assets.rb',
247
- '--namespace', options[:assets_namespace]
329
+ "ruby",
330
+ HomuraRuntimeBuild.exe_path("compile-assets").to_s,
331
+ "--input",
332
+ "public",
333
+ "--output",
334
+ "build/app_assets.rb",
335
+ "--namespace",
336
+ options[:assets_namespace]
248
337
  ],
249
338
  chdir: root
250
339
  )
@@ -253,26 +342,32 @@ else
253
342
  # top-level `app.rb`) are still valid — feed the lone file to
254
343
  # auto-await so its `db.execute` / `kv.get` / etc. still get
255
344
  # `__await__` inserted.
256
- if root.join('app').directory?
345
+ if root.join("app").directory?
257
346
  run!(
258
347
  [
259
- 'ruby', HomuraRuntimeBuild.exe_path('auto-await').to_s,
260
- '--input', 'app',
261
- '--output', 'build/auto_await/app'
348
+ "ruby",
349
+ HomuraRuntimeBuild.exe_path("auto-await").to_s,
350
+ "--input",
351
+ "app",
352
+ "--output",
353
+ "build/auto_await/app"
262
354
  ],
263
355
  chdir: root
264
356
  )
265
- elsif root.join('app.rb').file?
357
+ elsif root.join("app.rb").file?
266
358
  run!(
267
359
  [
268
- 'ruby', HomuraRuntimeBuild.exe_path('auto-await').to_s,
269
- '--input', 'app.rb',
270
- '--output', 'build/auto_await/app.rb'
360
+ "ruby",
361
+ HomuraRuntimeBuild.exe_path("auto-await").to_s,
362
+ "--input",
363
+ "app.rb",
364
+ "--output",
365
+ "build/auto_await/app.rb"
271
366
  ],
272
367
  chdir: root
273
368
  )
274
369
  else
275
- warn 'homura build: no app/ directory or top-level app.rb — skipping auto-await'
370
+ warn "homura build: no app/ directory or top-level app.rb — skipping auto-await"
276
371
  end
277
372
 
278
373
  # Also run auto-await over every gem we ship to Opal:
@@ -282,22 +377,27 @@ else
282
377
  # `build/auto_await/gem_<basename>/<sub>` and
283
378
  # `standalone_load_paths` puts those rewritten copies ahead of the
284
379
  # gem's untransformed `lib/`.
285
- HomuraRuntime::BuildSupport.opal_gem_paths(root).each do |gem_path|
286
- %w[lib].each do |sub|
287
- src = gem_path.join(sub)
288
- next unless src.directory?
289
- out = root.join('build', 'auto_await', "gem_#{gem_path.basename}", sub)
290
- FileUtils.mkdir_p(out)
291
- run!(
292
- [
293
- 'ruby', HomuraRuntimeBuild.exe_path('auto-await').to_s,
294
- '--input', src.to_s,
295
- '--output', out.to_s
296
- ],
297
- chdir: root
298
- )
380
+ HomuraRuntime::BuildSupport
381
+ .opal_gem_paths(root)
382
+ .each do |gem_path|
383
+ %w[lib].each do |sub|
384
+ src = gem_path.join(sub)
385
+ next unless src.directory?
386
+ out = root.join("build", "auto_await", "gem_#{gem_path.basename}", sub)
387
+ FileUtils.mkdir_p(out)
388
+ run!(
389
+ [
390
+ "ruby",
391
+ HomuraRuntimeBuild.exe_path("auto-await").to_s,
392
+ "--input",
393
+ src.to_s,
394
+ "--output",
395
+ out.to_s
396
+ ],
397
+ chdir: root
398
+ )
399
+ end
299
400
  end
300
- end
301
401
 
302
402
  opal_in = Pathname(resolve_opal_input(root, options[:opal_input]))
303
403
  opal_out = Pathname(options[:opal_output])
@@ -305,8 +405,12 @@ else
305
405
  opal_out = root.join(opal_out) unless opal_out.absolute?
306
406
  prepared_in, temp_input = prepare_opal_input(root, opal_in)
307
407
  begin
308
- run_opal_standalone!(root, prepared_in, opal_out.relative_path_from(root).to_s,
309
- with_db: options[:with_db])
408
+ run_opal_standalone!(
409
+ root,
410
+ prepared_in,
411
+ opal_out.relative_path_from(root).to_s,
412
+ with_db: options[:with_db]
413
+ )
310
414
  ensure
311
415
  FileUtils.rm_f(temp_input) if temp_input
312
416
  end
@@ -316,8 +420,8 @@ patch_rel = Pathname(patch_target)
316
420
  patch_rel = root.join(patch_rel) unless patch_rel.absolute?
317
421
  run!(
318
422
  [
319
- 'node',
320
- HomuraRuntimeBuild.runtime_dir.join('patch-opal-evals.mjs').to_s,
423
+ "node",
424
+ HomuraRuntimeBuild.runtime_dir.join("patch-opal-evals.mjs").to_s,
321
425
  patch_rel.relative_path_from(root).to_s
322
426
  ],
323
427
  chdir: root
@@ -331,4 +435,4 @@ write_entrypoint!(
331
435
  worker_mod: options[:worker_module_import]
332
436
  )
333
437
 
334
- $stderr.puts 'homura build: ok'
438
+ $stderr.puts "homura build: ok"