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.
@@ -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
- environment_issues += android_environment_setup!(fix: !!fix, verbose: !!verbose)
58
- ok = system(android_build_env(tools[:env]), tools[:flutter], "doctor", *(verbose ? ["-v"] : []))
59
- status = ok ? 0 : ($?&.exitstatus || 1)
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
- # Installing a Flutter SDK through FVM downloads/extracts hundreds of
88
- # megabytes. Stream FVM's output so the run does not look frozen.
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
- puts " $ dart pub global activate fvm"
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, label: "Flutter SDK")
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, label: nil)
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
- name = label || File.basename(destination)
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, label: label)
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
- raise "Unsupported archive format: #{File.basename(archive)}"
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 extension packages included in the managed client.
229
- # Permission-backed extensions such as camera, audio_recorder,
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
- # Protected device access requested by this app.
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