ruflet 0.0.20 → 0.0.22
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 +30 -2
- data/lib/ruflet/cli/build_command.rb +1689 -86
- data/lib/ruflet/cli/new_command.rb +89 -19
- data/lib/ruflet/cli/run_command.rb +300 -49
- data/lib/ruflet/cli/update_command.rb +6 -6
- data/lib/ruflet/cli.rb +7 -2
- data/lib/ruflet/hot_reload.rb +23 -10
- data/lib/ruflet/version.rb +1 -1
- metadata +1 -1
|
@@ -13,23 +13,25 @@ module Ruflet
|
|
|
13
13
|
RUNTIME_REPO_URL = ENV.fetch("RUFLET_RUNTIME_REPO_URL", "https://github.com/AdamMusa/ruflet.git")
|
|
14
14
|
|
|
15
15
|
CLIENT_EXTENSION_MAP = {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
16
|
+
"ads" => { package: "ruflet_ads", alias: "ruflet_ads" },
|
|
17
|
+
"audio" => { package: "ruflet_audio", alias: "ruflet_audio" },
|
|
18
|
+
"audio_recorder" => { package: "ruflet_audio_recorder", alias: "ruflet_audio_recorder" },
|
|
19
|
+
"camera" => { package: "ruflet_camera", alias: "ruflet_camera" },
|
|
20
|
+
"charts" => { package: "ruflet_charts", alias: "ruflet_charts" },
|
|
21
|
+
"code_editor" => { package: "ruflet_code_editor", alias: "ruflet_code_editor" },
|
|
22
|
+
"color_pickers" => { package: "ruflet_color_pickers", alias: "ruflet_color_picker" },
|
|
23
|
+
"datatable2" => { package: "ruflet_datatable2", alias: "ruflet_datatable2" },
|
|
24
|
+
"flashlight" => { package: "ruflet_flashlight", alias: "ruflet_flashlight" },
|
|
25
|
+
"geolocator" => { package: "ruflet_geolocator", alias: "ruflet_geolocator" },
|
|
26
|
+
"lottie" => { package: "ruflet_lottie", alias: "ruflet_lottie" },
|
|
27
|
+
"map" => { package: "ruflet_map", alias: "ruflet_map" },
|
|
28
|
+
"permission_handler" => { package: "ruflet_permission_handler", alias: "ruflet_permission_handler" },
|
|
28
29
|
"qrcode_scanner" => { package: "ruflet_qrcode_scanner", alias: "ruflet_qrcode_scanner" },
|
|
29
|
-
"rive" => { package: "
|
|
30
|
-
"secure_storage" => { package: "
|
|
31
|
-
"
|
|
32
|
-
"
|
|
30
|
+
"rive" => { package: "ruflet_rive", alias: "ruflet_rive" },
|
|
31
|
+
"secure_storage" => { package: "ruflet_secure_storage", alias: "ruflet_secure_storage" },
|
|
32
|
+
"spinkit" => { package: "ruflet_spinkit", alias: "ruflet_spinkit" },
|
|
33
|
+
"video" => { package: "ruflet_video", alias: "ruflet_video" },
|
|
34
|
+
"webview" => { package: "ruflet_webview", alias: "ruflet_webview" }
|
|
33
35
|
}.freeze
|
|
34
36
|
|
|
35
37
|
def command_new(args)
|
|
@@ -51,6 +53,7 @@ module Ruflet
|
|
|
51
53
|
File.write(File.join(root, "README.md"), format(Ruflet::CLI::README_TEMPLATE, app_name: File.basename(root)))
|
|
52
54
|
write_default_ruflet_config(root, File.basename(root))
|
|
53
55
|
copy_default_project_assets(root)
|
|
56
|
+
copy_default_apple_extensions(root)
|
|
54
57
|
project_name = File.basename(root)
|
|
55
58
|
puts "Run:"
|
|
56
59
|
puts " cd #{project_name}"
|
|
@@ -72,7 +75,16 @@ module Ruflet
|
|
|
72
75
|
target = hidden_flutter_client_dir(root)
|
|
73
76
|
FileUtils.mkdir_p(File.dirname(target))
|
|
74
77
|
FileUtils.rm_rf(target)
|
|
75
|
-
|
|
78
|
+
# `target` is the Flutter project root, not a directory that contains
|
|
79
|
+
# the template root. Copying a source directory onto a target that was
|
|
80
|
+
# already created by FileUtils can produce
|
|
81
|
+
# `build/client/ruflet_flutter_template/...`, leaving `build/client`
|
|
82
|
+
# without pubspec.yaml and making Flutter reject it as a project.
|
|
83
|
+
FileUtils.mkdir_p(target)
|
|
84
|
+
Dir.children(template_root).each do |entry|
|
|
85
|
+
copy_client_template_entry(
|
|
86
|
+
template_root, target, entry)
|
|
87
|
+
end
|
|
76
88
|
prune_client_template(target)
|
|
77
89
|
write_client_template_revision(target, installed_template_revision(template_root))
|
|
78
90
|
end
|
|
@@ -205,10 +217,16 @@ module Ruflet
|
|
|
205
217
|
git_revision(File.expand_path("../..", template_root))
|
|
206
218
|
end
|
|
207
219
|
|
|
220
|
+
# Always record where the client came from. A template resolved from a
|
|
221
|
+
# local checkout may have no readable revision, and skipping the marker
|
|
222
|
+
# entirely left the copied client indistinguishable from one that was
|
|
223
|
+
# never stamped. "local" never matches an expected revision, so the client
|
|
224
|
+
# is refreshed rather than treated as current.
|
|
208
225
|
def write_client_template_revision(target, revision)
|
|
209
|
-
|
|
226
|
+
value = revision.to_s.strip
|
|
227
|
+
value = "local" if value.empty?
|
|
210
228
|
|
|
211
|
-
File.write(File.join(target, ".ruflet-template-revision"), "#{
|
|
229
|
+
File.write(File.join(target, ".ruflet-template-revision"), "#{value}\n")
|
|
212
230
|
end
|
|
213
231
|
|
|
214
232
|
def client_template_current?(target, template_root)
|
|
@@ -255,6 +273,43 @@ module Ruflet
|
|
|
255
273
|
end
|
|
256
274
|
end
|
|
257
275
|
|
|
276
|
+
def copy_client_template_entry(template_root, target, relative)
|
|
277
|
+
return if generated_client_template_path?(relative)
|
|
278
|
+
|
|
279
|
+
source = File.join(template_root, relative)
|
|
280
|
+
destination = File.join(target, relative)
|
|
281
|
+
stat = File.lstat(source)
|
|
282
|
+
if stat.symlink?
|
|
283
|
+
FileUtils.mkdir_p(File.dirname(destination))
|
|
284
|
+
FileUtils.ln_s(File.readlink(source), destination)
|
|
285
|
+
elsif stat.directory?
|
|
286
|
+
FileUtils.mkdir_p(destination)
|
|
287
|
+
Dir.children(source).each do |entry|
|
|
288
|
+
copy_client_template_entry(
|
|
289
|
+
template_root, target, File.join(relative, entry))
|
|
290
|
+
end
|
|
291
|
+
else
|
|
292
|
+
FileUtils.mkdir_p(File.dirname(destination))
|
|
293
|
+
FileUtils.cp(source, destination, preserve: true)
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def generated_client_template_path?(relative)
|
|
298
|
+
components = relative.split(File::SEPARATOR)
|
|
299
|
+
generated_components = %w[
|
|
300
|
+
.build .cache .claude .dart_tool .git .idea .swiftpm .symlinks
|
|
301
|
+
build DerivedData Pods xcuserdata
|
|
302
|
+
]
|
|
303
|
+
return true if components.any? { |component| generated_components.include?(component) }
|
|
304
|
+
return true if components.any? { |component| component.start_with?(".build-") }
|
|
305
|
+
|
|
306
|
+
generated_files = %w[
|
|
307
|
+
.DS_Store Package.resolved Podfile.lock local.properties
|
|
308
|
+
pubspec_overrides.yaml
|
|
309
|
+
]
|
|
310
|
+
generated_files.include?(components.last) || components.last.end_with?(".xcuserstate")
|
|
311
|
+
end
|
|
312
|
+
|
|
258
313
|
def write_default_ruflet_config(root, app_name)
|
|
259
314
|
File.write(File.join(root, "ruflet.yaml"), <<~YAML)
|
|
260
315
|
app:
|
|
@@ -313,6 +368,21 @@ module Ruflet
|
|
|
313
368
|
end
|
|
314
369
|
end
|
|
315
370
|
|
|
371
|
+
def copy_default_apple_extensions(root)
|
|
372
|
+
template_root = resolve_ruflet_client_template_root || ensure_cached_ruflet_client_template!
|
|
373
|
+
source = template_root && File.join(template_root, "apple_extensions")
|
|
374
|
+
return unless source && File.file?(File.join(source, "Package.swift"))
|
|
375
|
+
|
|
376
|
+
destination = File.join(root, "apple_extensions")
|
|
377
|
+
FileUtils.mkdir_p(destination)
|
|
378
|
+
generated_entries = %w[.build .swiftpm .dart_tool .claude]
|
|
379
|
+
Dir.children(source).each do |entry|
|
|
380
|
+
next if generated_entries.include?(entry)
|
|
381
|
+
|
|
382
|
+
FileUtils.cp_r(File.join(source, entry), File.join(destination, entry), preserve: true)
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
316
386
|
def default_project_assets_root
|
|
317
387
|
[
|
|
318
388
|
File.expand_path("../../../assets", __dir__),
|