ruflet 0.0.17 → 0.0.18
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 +1 -40
- data/lib/ruflet/cli/build_command.rb +124 -697
- data/lib/ruflet/cli/extra_command.rb +3 -15
- data/lib/ruflet/cli/flutter_sdk.rb +9 -91
- data/lib/ruflet/cli/new_command.rb +7 -36
- data/lib/ruflet/cli/run_command.rb +97 -186
- data/lib/ruflet/cli/templates.rb +8 -9
- data/lib/ruflet/cli.rb +0 -13
- data/lib/ruflet/version.rb +1 -1
- metadata +1 -3
- data/lib/ruflet/cli/android_sdk.rb +0 -306
- data/lib/ruflet/cli/environment_setup.rb +0 -241
|
@@ -6,8 +6,6 @@ module Ruflet
|
|
|
6
6
|
module CLI
|
|
7
7
|
module ExtraCommand
|
|
8
8
|
include FlutterSdk
|
|
9
|
-
include EnvironmentSetup
|
|
10
|
-
include AndroidSdk
|
|
11
9
|
include NewCommand
|
|
12
10
|
|
|
13
11
|
def command_create(args)
|
|
@@ -22,12 +20,6 @@ module Ruflet
|
|
|
22
20
|
puts "Ruflet doctor"
|
|
23
21
|
puts " Ruby: #{RUBY_VERSION}"
|
|
24
22
|
puts " Flutter host target: #{flutter_host || 'unsupported'}"
|
|
25
|
-
|
|
26
|
-
# System prerequisites first: Flutter cannot be installed (or even
|
|
27
|
-
# extracted) without them.
|
|
28
|
-
environment_issues = environment_setup!(fix: !!fix, verbose: !!verbose)
|
|
29
|
-
return 1 unless flutter_host
|
|
30
|
-
|
|
31
23
|
if template_root
|
|
32
24
|
puts " Template: #{template_root}"
|
|
33
25
|
elsif fix
|
|
@@ -54,13 +46,9 @@ module Ruflet
|
|
|
54
46
|
end
|
|
55
47
|
end
|
|
56
48
|
puts " Flutter: #{flutter_version_summary(tools)}"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
status
|
|
60
|
-
if environment_issues.any?
|
|
61
|
-
warn "Unresolved environment issues: #{environment_issues.join('; ')}"
|
|
62
|
-
status = 1 if status.zero?
|
|
63
|
-
end
|
|
49
|
+
ok = system(tools[:env], tools[:flutter], "doctor", *(verbose ? ["-v"] : []))
|
|
50
|
+
status = $?.exitstatus if $?
|
|
51
|
+
status ||= ok ? 0 : 1
|
|
64
52
|
status
|
|
65
53
|
end
|
|
66
54
|
|
|
@@ -84,12 +84,8 @@ module Ruflet
|
|
|
84
84
|
File.write(fvmrc_path, "{\"flutter\":\"#{version}\"}\n")
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
puts " $ fvm install #{version}"
|
|
90
|
-
system(fvm_env, fvm, "install", version.to_s, chdir: project_dir, out: $stdout, err: $stderr)
|
|
91
|
-
puts " $ fvm use --force #{version}"
|
|
92
|
-
system(fvm_env, fvm, "use", "--force", version.to_s, chdir: project_dir, out: $stdout, err: $stderr)
|
|
87
|
+
system(fvm_env, fvm, "install", version.to_s, chdir: project_dir, out: File::NULL, err: File::NULL)
|
|
88
|
+
system(fvm_env, fvm, "use", "--force", version.to_s, chdir: project_dir, out: File::NULL, err: File::NULL)
|
|
93
89
|
|
|
94
90
|
flutter = flutter_bin_path(project_dir)
|
|
95
91
|
return nil unless File.executable?(flutter)
|
|
@@ -111,8 +107,7 @@ module Ruflet
|
|
|
111
107
|
end
|
|
112
108
|
return nil unless dart && File.executable?(dart)
|
|
113
109
|
|
|
114
|
-
|
|
115
|
-
system(dart, "pub", "global", "activate", "fvm", out: $stdout, err: $stderr)
|
|
110
|
+
system(dart, "pub", "global", "activate", "fvm", out: File::NULL, err: File::NULL)
|
|
116
111
|
installed_fvm = File.join(pub_cache_bin_dir, fvm_executable_name)
|
|
117
112
|
return installed_fvm if File.executable?(installed_fvm)
|
|
118
113
|
|
|
@@ -153,13 +148,10 @@ module Ruflet
|
|
|
153
148
|
return sdk_root if File.executable?(flutter_bin)
|
|
154
149
|
|
|
155
150
|
FileUtils.mkdir_p(install_root)
|
|
156
|
-
puts " Installing Flutter #{release.fetch('version')} (#{host}) into #{install_root}"
|
|
157
151
|
Dir.mktmpdir("ruflet-flutter-sdk-") do |tmpdir|
|
|
158
152
|
archive_path = File.join(tmpdir, File.basename(archive))
|
|
159
|
-
download_file("#{RELEASES_BASE}/#{archive}", archive_path
|
|
160
|
-
puts " Extracting #{File.basename(archive)} (this can take a minute)"
|
|
153
|
+
download_file("#{RELEASES_BASE}/#{archive}", archive_path)
|
|
161
154
|
extract_archive(archive_path, install_root)
|
|
162
|
-
puts " Extracted Flutter SDK"
|
|
163
155
|
end
|
|
164
156
|
|
|
165
157
|
return sdk_root if File.executable?(flutter_bin)
|
|
@@ -297,8 +289,6 @@ module Ruflet
|
|
|
297
289
|
return JSON.parse(response.body) if response.is_a?(Net::HTTPSuccess)
|
|
298
290
|
|
|
299
291
|
nil
|
|
300
|
-
rescue OpenSSL::SSL::SSLError
|
|
301
|
-
JSON.parse(curl_get(url, headers: ["User-Agent: ruflet-cli"]))
|
|
302
292
|
end
|
|
303
293
|
|
|
304
294
|
def pick_release(manifest, version: nil, revision: nil, channel: nil)
|
|
@@ -330,10 +320,7 @@ module Ruflet
|
|
|
330
320
|
if os.match?(/darwin/i)
|
|
331
321
|
return machine_arch.include?("arm") ? "macos_arm64" : "macos"
|
|
332
322
|
end
|
|
333
|
-
if os.match?(/linux/i)
|
|
334
|
-
# Flutter publishes Linux archives for x64 only.
|
|
335
|
-
return machine_arch.match?(/arm|aarch64/) ? nil : "linux"
|
|
336
|
-
end
|
|
323
|
+
return "linux" if os.match?(/linux/i)
|
|
337
324
|
return "windows" if os.match?(/mswin|mingw|cygwin/i)
|
|
338
325
|
|
|
339
326
|
nil
|
|
@@ -374,7 +361,7 @@ module Ruflet
|
|
|
374
361
|
nil
|
|
375
362
|
end
|
|
376
363
|
|
|
377
|
-
def download_file(url, destination, limit: 5
|
|
364
|
+
def download_file(url, destination, limit: 5)
|
|
378
365
|
raise "Too many redirects while downloading #{url}" if limit <= 0
|
|
379
366
|
|
|
380
367
|
uri = URI(url)
|
|
@@ -384,73 +371,15 @@ module Ruflet
|
|
|
384
371
|
http.request(req) do |res|
|
|
385
372
|
case res
|
|
386
373
|
when Net::HTTPSuccess
|
|
387
|
-
|
|
388
|
-
total = res["content-length"].to_i
|
|
389
|
-
downloaded = 0
|
|
390
|
-
marker = -1
|
|
391
|
-
File.open(destination, "wb") do |f|
|
|
392
|
-
res.read_body do |chunk|
|
|
393
|
-
f.write(chunk)
|
|
394
|
-
downloaded += chunk.bytesize
|
|
395
|
-
marker = report_download_progress(name, downloaded, total, marker)
|
|
396
|
-
end
|
|
397
|
-
end
|
|
398
|
-
finish_download_progress(name, downloaded, total)
|
|
374
|
+
File.open(destination, "wb") { |f| res.read_body { |chunk| f.write(chunk) } }
|
|
399
375
|
return destination
|
|
400
376
|
when Net::HTTPRedirection
|
|
401
|
-
return download_file(res["location"], destination, limit: limit - 1
|
|
377
|
+
return download_file(res["location"], destination, limit: limit - 1)
|
|
402
378
|
else
|
|
403
379
|
raise "Download failed (#{res.code})"
|
|
404
380
|
end
|
|
405
381
|
end
|
|
406
382
|
end
|
|
407
|
-
rescue OpenSSL::SSL::SSLError
|
|
408
|
-
curl_download(url, destination)
|
|
409
|
-
end
|
|
410
|
-
|
|
411
|
-
# Net::HTTP gives no progress for a multi-hundred-MB SDK download, which
|
|
412
|
-
# looks like a hang. Report percentage on a TTY (rewritten in place) and
|
|
413
|
-
# at coarse steps when piped, so logs stay readable either way.
|
|
414
|
-
def report_download_progress(name, downloaded, total, marker)
|
|
415
|
-
if total.positive?
|
|
416
|
-
percent = downloaded * 100 / total
|
|
417
|
-
return marker if percent <= marker
|
|
418
|
-
|
|
419
|
-
line = " Downloading #{name}: #{percent}% (#{human_size(downloaded)} / #{human_size(total)})"
|
|
420
|
-
if $stdout.tty?
|
|
421
|
-
$stdout.print("\r#{line}")
|
|
422
|
-
elsif (percent % 10).zero?
|
|
423
|
-
puts line
|
|
424
|
-
end
|
|
425
|
-
percent
|
|
426
|
-
else
|
|
427
|
-
step = downloaded / (5 * 1024 * 1024)
|
|
428
|
-
return marker if step <= marker
|
|
429
|
-
|
|
430
|
-
line = " Downloading #{name}: #{human_size(downloaded)}"
|
|
431
|
-
$stdout.tty? ? $stdout.print("\r#{line}") : puts(line)
|
|
432
|
-
step
|
|
433
|
-
end
|
|
434
|
-
end
|
|
435
|
-
|
|
436
|
-
def finish_download_progress(name, downloaded, total)
|
|
437
|
-
summary = total.positive? ? "#{human_size(downloaded)} / #{human_size(total)}" : human_size(downloaded)
|
|
438
|
-
if $stdout.tty?
|
|
439
|
-
$stdout.print("\r Downloaded #{name}: #{summary}\n")
|
|
440
|
-
else
|
|
441
|
-
puts " Downloaded #{name}: #{summary}"
|
|
442
|
-
end
|
|
443
|
-
end
|
|
444
|
-
|
|
445
|
-
def human_size(bytes)
|
|
446
|
-
units = %w[B KB MB GB TB]
|
|
447
|
-
size = bytes.to_f
|
|
448
|
-
unit = units.shift
|
|
449
|
-
while size >= 1024 && units.any?
|
|
450
|
-
size /= 1024
|
|
451
|
-
unit = units.shift
|
|
452
|
-
end
|
|
453
|
-
format("%.1f %s", size, unit)
|
|
454
383
|
end
|
|
455
384
|
|
|
456
385
|
def extract_archive(archive, destination)
|
|
@@ -458,25 +387,14 @@ module Ruflet
|
|
|
458
387
|
if windows_host?
|
|
459
388
|
return system("powershell", "-NoProfile", "-Command", "Expand-Archive -Path '#{archive}' -DestinationPath '#{destination}' -Force")
|
|
460
389
|
end
|
|
461
|
-
|
|
462
|
-
require_extract_tool!("unzip")
|
|
463
390
|
return system("unzip", "-oq", archive, "-d", destination)
|
|
464
391
|
end
|
|
465
392
|
|
|
466
393
|
if archive.end_with?(".tar.xz") || archive.end_with?(".tar.gz") || archive.end_with?(".tgz")
|
|
467
|
-
require_extract_tool!("tar")
|
|
468
|
-
require_extract_tool!("xz") if archive.end_with?(".tar.xz") && !windows_host?
|
|
469
394
|
return system("tar", "-xf", archive, "-C", destination)
|
|
470
395
|
end
|
|
471
396
|
|
|
472
|
-
|
|
473
|
-
end
|
|
474
|
-
|
|
475
|
-
def require_extract_tool!(name)
|
|
476
|
-
return if which_command(name)
|
|
477
|
-
|
|
478
|
-
raise "`#{name}` is required to extract the Flutter SDK but was not found. " \
|
|
479
|
-
"Run `ruflet doctor --fix` to install the missing system tools."
|
|
397
|
+
false
|
|
480
398
|
end
|
|
481
399
|
end
|
|
482
400
|
end
|
|
@@ -24,8 +24,8 @@ module Ruflet
|
|
|
24
24
|
"lottie" => { package: "flet_lottie", alias: "ruflet_lottie" },
|
|
25
25
|
"map" => { package: "flet_map", alias: "ruflet_map" },
|
|
26
26
|
"permission_handler" => { package: "flet_permission_handler", alias: "ruflet_permission_handler" },
|
|
27
|
+
"rive" => { package: "flet_rive", alias: "ruflet_rive" },
|
|
27
28
|
"secure_storage" => { package: "flet_secure_storage", alias: "ruflet_secure_storage" },
|
|
28
|
-
"spinkit" => { package: "flet_spinkit", alias: "ruflet_spinkit" },
|
|
29
29
|
"video" => { package: "flet_video", alias: "ruflet_video" },
|
|
30
30
|
"webview" => { package: "flet_webview", alias: "ruflet_webview" }
|
|
31
31
|
}.freeze
|
|
@@ -85,20 +85,7 @@ module Ruflet
|
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
cached_template = cached_ruflet_client_template_root
|
|
88
|
-
if Dir.exist?(cached_template)
|
|
89
|
-
return cached_template if cached_template_current?(cached_template)
|
|
90
|
-
|
|
91
|
-
# The cache was written by a different ruflet version; stale
|
|
92
|
-
# framework Dart breaks newer asset layouts. Refresh, but never
|
|
93
|
-
# block a build on the network: fall back to the stale copy loudly.
|
|
94
|
-
refreshed = download_ruflet_template(force: true)
|
|
95
|
-
return refreshed if refreshed && Dir.exist?(refreshed)
|
|
96
|
-
|
|
97
|
-
warn "ruflet: could not refresh the Flutter client template cache; " \
|
|
98
|
-
"using a stale copy from another ruflet version at #{cached_template}. " \
|
|
99
|
-
"Delete it or run with network access to update."
|
|
100
|
-
return cached_template
|
|
101
|
-
end
|
|
88
|
+
return cached_template if Dir.exist?(cached_template)
|
|
102
89
|
|
|
103
90
|
[
|
|
104
91
|
File.expand_path("../../../ruflet_client", __dir__),
|
|
@@ -126,21 +113,6 @@ module Ruflet
|
|
|
126
113
|
File.join(template_cache_root, "ruflet_flutter_template")
|
|
127
114
|
end
|
|
128
115
|
|
|
129
|
-
TEMPLATE_CACHE_STAMP = ".ruflet_template_version"
|
|
130
|
-
|
|
131
|
-
def cached_template_current?(target)
|
|
132
|
-
stamp = File.join(target, TEMPLATE_CACHE_STAMP)
|
|
133
|
-
File.file?(stamp) && File.read(stamp).strip == Ruflet::VERSION
|
|
134
|
-
rescue StandardError
|
|
135
|
-
false
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def write_template_cache_stamp(target)
|
|
139
|
-
File.write(File.join(target, TEMPLATE_CACHE_STAMP), Ruflet::VERSION)
|
|
140
|
-
rescue StandardError
|
|
141
|
-
nil
|
|
142
|
-
end
|
|
143
|
-
|
|
144
116
|
def cached_ruby_runtime_root
|
|
145
117
|
File.join(cache_root, "ruby_runtime")
|
|
146
118
|
end
|
|
@@ -179,7 +151,6 @@ module Ruflet
|
|
|
179
151
|
FileUtils.cp_r(source, target)
|
|
180
152
|
end
|
|
181
153
|
|
|
182
|
-
write_template_cache_stamp(target)
|
|
183
154
|
target
|
|
184
155
|
rescue StandardError => e
|
|
185
156
|
warn "Failed to fetch Ruflet template: #{e.class}: #{e.message}"
|
|
@@ -225,10 +196,8 @@ module Ruflet
|
|
|
225
196
|
# Example: https://api.example.com
|
|
226
197
|
backend_url: ""
|
|
227
198
|
|
|
228
|
-
# Flutter
|
|
229
|
-
#
|
|
230
|
-
# geolocator, and permission_handler are activated by services.yaml
|
|
231
|
-
# and ignored here.
|
|
199
|
+
# Optional Flutter client extensions. Only listed extensions are bundled.
|
|
200
|
+
# Examples: audio, charts, code_editor, map, rive, video, webview
|
|
232
201
|
extensions: []
|
|
233
202
|
|
|
234
203
|
# Build assets configuration consumed by `ruflet build`.
|
|
@@ -246,7 +215,9 @@ module Ruflet
|
|
|
246
215
|
YAML
|
|
247
216
|
|
|
248
217
|
File.write(File.join(root, "services.yaml"), <<~YAML)
|
|
249
|
-
#
|
|
218
|
+
# Native capabilities that require platform permissions. Ruflet activates
|
|
219
|
+
# the matching client extensions and writes Android/iOS permissions.
|
|
220
|
+
# Supported services: camera, microphone, location, motion
|
|
250
221
|
services: []
|
|
251
222
|
YAML
|
|
252
223
|
end
|