ruflet 0.0.8 → 0.0.9
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/bin/ruflet +6 -0
- data/lib/ruflet/cli/build_command.rb +372 -0
- data/lib/ruflet/cli/extra_command.rb +146 -0
- data/lib/ruflet/cli/flutter_sdk.rb +359 -0
- data/lib/ruflet/cli/new_command.rb +221 -0
- data/lib/ruflet/cli/run_command.rb +699 -0
- data/lib/ruflet/cli/templates.rb +68 -0
- data/lib/ruflet/cli/update_command.rb +111 -0
- data/lib/ruflet/cli.rb +85 -0
- data/lib/ruflet/version.rb +1 -1
- data/lib/ruflet_cli.rb +3 -0
- metadata +59 -209
- data/lib/ruflet.rb +0 -40
- data/lib/ruflet_protocol/ruflet/protocol.rb +0 -62
- data/lib/ruflet_protocol.rb +0 -4
- data/lib/ruflet_ui/ruflet/app.rb +0 -27
- data/lib/ruflet_ui/ruflet/colors.rb +0 -234
- data/lib/ruflet_ui/ruflet/control.rb +0 -281
- data/lib/ruflet_ui/ruflet/dsl.rb +0 -291
- data/lib/ruflet_ui/ruflet/event.rb +0 -42
- data/lib/ruflet_ui/ruflet/events/gesture_events.rb +0 -552
- data/lib/ruflet_ui/ruflet/icon_data.rb +0 -62
- data/lib/ruflet_ui/ruflet/icons/cupertino/cupertino_icons.rb +0 -54
- data/lib/ruflet_ui/ruflet/icons/cupertino_icon_lookup.rb +0 -112
- data/lib/ruflet_ui/ruflet/icons/material_icon_lookup.rb +0 -112
- data/lib/ruflet_ui/ruflet/icons/material_icons.rb +0 -55
- data/lib/ruflet_ui/ruflet/page.rb +0 -1222
- data/lib/ruflet_ui/ruflet/types/geometry.rb +0 -65
- data/lib/ruflet_ui/ruflet/types/text_style.rb +0 -191
- data/lib/ruflet_ui/ruflet/ui/control_factory.rb +0 -53
- data/lib/ruflet_ui/ruflet/ui/control_methods.rb +0 -17
- data/lib/ruflet_ui/ruflet/ui/control_registry.rb +0 -33
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheet_control.rb +0 -57
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactionsheetaction_control.rb +0 -58
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoactivityindicator_control.rb +0 -57
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoalertdialog_control.rb +0 -39
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoappbar_control.rb +0 -44
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobottomsheet_control.rb +0 -38
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinobutton_control.rb +0 -73
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocheckbox_control.rb +0 -70
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenu_control.rb +0 -34
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinocontextmenuaction_control.rb +0 -36
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodatepicker_control.rb +0 -67
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinodialogaction_control.rb +0 -35
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinofilledbutton_control.rb +0 -73
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinolisttile_control.rb +0 -67
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinonavigationbar_control.rb +0 -61
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinopicker_control.rb +0 -66
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoradio_control.rb +0 -66
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinosegmentedbutton_control.rb +0 -63
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslider_control.rb +0 -64
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoslidingsegmentedbutton_control.rb +0 -60
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinoswitch_control.rb +0 -73
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotextfield_control.rb +0 -159
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotimerpicker_control.rb +0 -61
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/cupertinotintedbutton_control.rb +0 -73
- data/lib/ruflet_ui/ruflet/ui/controls/cupertinos/ruflet_controls.rb +0 -89
- data/lib/ruflet_ui/ruflet/ui/controls/materials/alertdialog_control.rb +0 -58
- data/lib/ruflet_ui/ruflet/ui/controls/materials/appbar_control.rb +0 -53
- data/lib/ruflet_ui/ruflet/ui/controls/materials/audio_control.rb +0 -36
- data/lib/ruflet_ui/ruflet/ui/controls/materials/autocomplete_control.rb +0 -58
- data/lib/ruflet_ui/ruflet/ui/controls/materials/badge_control.rb +0 -31
- data/lib/ruflet_ui/ruflet/ui/controls/materials/banner_control.rb +0 -47
- data/lib/ruflet_ui/ruflet/ui/controls/materials/bottomappbar_control.rb +0 -62
- data/lib/ruflet_ui/ruflet/ui/controls/materials/bottomsheet_control.rb +0 -48
- data/lib/ruflet_ui/ruflet/ui/controls/materials/button_control.rb +0 -69
- data/lib/ruflet_ui/ruflet/ui/controls/materials/card_control.rb +0 -63
- data/lib/ruflet_ui/ruflet/ui/controls/materials/chart_controls.rb +0 -321
- data/lib/ruflet_ui/ruflet/ui/controls/materials/checkbox_control.rb +0 -76
- data/lib/ruflet_ui/ruflet/ui/controls/materials/chip_control.rb +0 -88
- data/lib/ruflet_ui/ruflet/ui/controls/materials/circleavatar_control.rb +0 -62
- data/lib/ruflet_ui/ruflet/ui/controls/materials/container_control.rb +0 -81
- data/lib/ruflet_ui/ruflet/ui/controls/materials/contextmenu_control.rb +0 -63
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datacell_control.rb +0 -38
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datacolumn_control.rb +0 -34
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datarow_control.rb +0 -35
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datatable_control.rb +0 -78
- data/lib/ruflet_ui/ruflet/ui/controls/materials/datepicker_control.rb +0 -55
- data/lib/ruflet_ui/ruflet/ui/controls/materials/daterangepicker_control.rb +0 -57
- data/lib/ruflet_ui/ruflet/ui/controls/materials/divider_control.rb +0 -36
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdown_control.rb +0 -99
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdownm2_control.rb +0 -119
- data/lib/ruflet_ui/ruflet/ui/controls/materials/dropdownoption_control.rb +0 -35
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansionpanel_control.rb +0 -61
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansionpanellist_control.rb +0 -60
- data/lib/ruflet_ui/ruflet/ui/controls/materials/expansiontile_control.rb +0 -82
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledbutton_control.rb +0 -69
- data/lib/ruflet_ui/ruflet/ui/controls/materials/fillediconbutton_control.rb +0 -81
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledtonalbutton_control.rb +0 -69
- data/lib/ruflet_ui/ruflet/ui/controls/materials/filledtonaliconbutton_control.rb +0 -81
- data/lib/ruflet_ui/ruflet/ui/controls/materials/floatingactionbutton_control.rb +0 -73
- data/lib/ruflet_ui/ruflet/ui/controls/materials/iconbutton_control.rb +0 -81
- data/lib/ruflet_ui/ruflet/ui/controls/materials/listtile_control.rb +0 -87
- data/lib/ruflet_ui/ruflet/ui/controls/materials/menubar_control.rb +0 -33
- data/lib/ruflet_ui/ruflet/ui/controls/materials/menuitembutton_control.rb +0 -67
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationbar_control.rb +0 -67
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationbardestination_control.rb +0 -35
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationdrawer_control.rb +0 -41
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationdrawerdestination_control.rb +0 -34
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationrail_control.rb +0 -70
- data/lib/ruflet_ui/ruflet/ui/controls/materials/navigationraildestination_control.rb +0 -36
- data/lib/ruflet_ui/ruflet/ui/controls/materials/option_control.rb +0 -35
- data/lib/ruflet_ui/ruflet/ui/controls/materials/outlinedbutton_control.rb +0 -66
- data/lib/ruflet_ui/ruflet/ui/controls/materials/outlinediconbutton_control.rb +0 -81
- data/lib/ruflet_ui/ruflet/ui/controls/materials/popupmenubutton_control.rb +0 -74
- data/lib/ruflet_ui/ruflet/ui/controls/materials/popupmenuitem_control.rb +0 -38
- data/lib/ruflet_ui/ruflet/ui/controls/materials/progressbar_control.rb +0 -64
- data/lib/ruflet_ui/ruflet/ui/controls/materials/progressring_control.rb +0 -65
- data/lib/ruflet_ui/ruflet/ui/controls/materials/radio_control.rb +0 -70
- data/lib/ruflet_ui/ruflet/ui/controls/materials/radiogroup_control.rb +0 -33
- data/lib/ruflet_ui/ruflet/ui/controls/materials/rangeslider_control.rb +0 -67
- data/lib/ruflet_ui/ruflet/ui/controls/materials/reorderablelistview_control.rb +0 -80
- data/lib/ruflet_ui/ruflet/ui/controls/materials/ruflet_controls.rb +0 -252
- data/lib/ruflet_ui/ruflet/ui/controls/materials/searchbar_control.rb +0 -94
- data/lib/ruflet_ui/ruflet/ui/controls/materials/segment_control.rb +0 -33
- data/lib/ruflet_ui/ruflet/ui/controls/materials/segmentedbutton_control.rb +0 -63
- data/lib/ruflet_ui/ruflet/ui/controls/materials/selectionarea_control.rb +0 -32
- data/lib/ruflet_ui/ruflet/ui/controls/materials/slider_control.rb +0 -76
- data/lib/ruflet_ui/ruflet/ui/controls/materials/snackbar_control.rb +0 -51
- data/lib/ruflet_ui/ruflet/ui/controls/materials/submenubutton_control.rb +0 -66
- data/lib/ruflet_ui/ruflet/ui/controls/materials/switch_control.rb +0 -77
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tab_control.rb +0 -35
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabbar_control.rb +0 -77
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabbarview_control.rb +0 -57
- data/lib/ruflet_ui/ruflet/ui/controls/materials/tabs_control.rb +0 -59
- data/lib/ruflet_ui/ruflet/ui/controls/materials/textbutton_control.rb +0 -66
- data/lib/ruflet_ui/ruflet/ui/controls/materials/textfield_control.rb +0 -148
- data/lib/ruflet_ui/ruflet/ui/controls/materials/timepicker_control.rb +0 -50
- data/lib/ruflet_ui/ruflet/ui/controls/materials/verticaldivider_control.rb +0 -36
- data/lib/ruflet_ui/ruflet/ui/controls/materials/video_control.rb +0 -39
- data/lib/ruflet_ui/ruflet/ui/controls/materials/webview_control.rb +0 -35
- data/lib/ruflet_ui/ruflet/ui/controls/ruflet_controls.rb +0 -447
- data/lib/ruflet_ui/ruflet/ui/controls/shared/animatedswitcher_control.rb +0 -59
- data/lib/ruflet_ui/ruflet/ui/controls/shared/arc_control.rb +0 -29
- data/lib/ruflet_ui/ruflet/ui/controls/shared/autofillgroup_control.rb +0 -32
- data/lib/ruflet_ui/ruflet/ui/controls/shared/basepage_control.rb +0 -44
- data/lib/ruflet_ui/ruflet/ui/controls/shared/browsercontextmenu_control.rb +0 -21
- data/lib/ruflet_ui/ruflet/ui/controls/shared/canvas_control.rb +0 -57
- data/lib/ruflet_ui/ruflet/ui/controls/shared/circle_control.rb +0 -25
- data/lib/ruflet_ui/ruflet/ui/controls/shared/color_control.rb +0 -23
- data/lib/ruflet_ui/ruflet/ui/controls/shared/column_control.rb +0 -67
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dialogs_control.rb +0 -22
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dismissible_control.rb +0 -66
- data/lib/ruflet_ui/ruflet/ui/controls/shared/draggable_control.rb +0 -39
- data/lib/ruflet_ui/ruflet/ui/controls/shared/dragtarget_control.rb +0 -36
- data/lib/ruflet_ui/ruflet/ui/controls/shared/fill_control.rb +0 -22
- data/lib/ruflet_ui/ruflet/ui/controls/shared/fletapp_control.rb +0 -62
- data/lib/ruflet_ui/ruflet/ui/controls/shared/gesturedetector_control.rb +0 -129
- data/lib/ruflet_ui/ruflet/ui/controls/shared/gridview_control.rb +0 -71
- data/lib/ruflet_ui/ruflet/ui/controls/shared/hero_control.rb +0 -56
- data/lib/ruflet_ui/ruflet/ui/controls/shared/icon_control.rb +0 -64
- data/lib/ruflet_ui/ruflet/ui/controls/shared/image_control.rb +0 -27
- data/lib/ruflet_ui/ruflet/ui/controls/shared/interactiveviewer_control.rb +0 -69
- data/lib/ruflet_ui/ruflet/ui/controls/shared/keyboardlistener_control.rb +0 -36
- data/lib/ruflet_ui/ruflet/ui/controls/shared/line_control.rb +0 -26
- data/lib/ruflet_ui/ruflet/ui/controls/shared/listview_control.rb +0 -71
- data/lib/ruflet_ui/ruflet/ui/controls/shared/markdown_control.rb +0 -70
- data/lib/ruflet_ui/ruflet/ui/controls/shared/mergesemantics_control.rb +0 -31
- data/lib/ruflet_ui/ruflet/ui/controls/shared/oval_control.rb +0 -26
- data/lib/ruflet_ui/ruflet/ui/controls/shared/overlay_control.rb +0 -22
- data/lib/ruflet_ui/ruflet/ui/controls/shared/page_control.rb +0 -74
- data/lib/ruflet_ui/ruflet/ui/controls/shared/pagelet_control.rb +0 -64
- data/lib/ruflet_ui/ruflet/ui/controls/shared/pageview_control.rb +0 -64
- data/lib/ruflet_ui/ruflet/ui/controls/shared/path_control.rb +0 -23
- data/lib/ruflet_ui/ruflet/ui/controls/shared/placeholder_control.rb +0 -58
- data/lib/ruflet_ui/ruflet/ui/controls/shared/points_control.rb +0 -24
- data/lib/ruflet_ui/ruflet/ui/controls/shared/rect_control.rb +0 -27
- data/lib/ruflet_ui/ruflet/ui/controls/shared/reorderabledraghandle_control.rb +0 -56
- data/lib/ruflet_ui/ruflet/ui/controls/shared/responsiverow_control.rb +0 -61
- data/lib/ruflet_ui/ruflet/ui/controls/shared/row_control.rb +0 -67
- data/lib/ruflet_ui/ruflet/ui/controls/shared/ruflet_controls.rb +0 -140
- data/lib/ruflet_ui/ruflet/ui/controls/shared/safearea_control.rb +0 -61
- data/lib/ruflet_ui/ruflet/ui/controls/shared/semantics_control.rb +0 -79
- data/lib/ruflet_ui/ruflet/ui/controls/shared/serviceregistry_control.rb +0 -21
- data/lib/ruflet_ui/ruflet/ui/controls/shared/shadermask_control.rb +0 -57
- data/lib/ruflet_ui/ruflet/ui/controls/shared/shadow_control.rb +0 -25
- data/lib/ruflet_ui/ruflet/ui/controls/shared/shimmer_control.rb +0 -60
- data/lib/ruflet_ui/ruflet/ui/controls/shared/stack_control.rb +0 -58
- data/lib/ruflet_ui/ruflet/ui/controls/shared/text_control.rb +0 -32
- data/lib/ruflet_ui/ruflet/ui/controls/shared/textspan_control.rb +0 -39
- data/lib/ruflet_ui/ruflet/ui/controls/shared/transparentpointer_control.rb +0 -54
- data/lib/ruflet_ui/ruflet/ui/controls/shared/view_control.rb +0 -77
- data/lib/ruflet_ui/ruflet/ui/controls/shared/window_control.rb +0 -56
- data/lib/ruflet_ui/ruflet/ui/controls/shared/windowdragarea_control.rb +0 -58
- data/lib/ruflet_ui/ruflet/ui/cupertino_control_factory.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/cupertino_control_methods.rb +0 -26
- data/lib/ruflet_ui/ruflet/ui/cupertino_control_registry.rb +0 -49
- data/lib/ruflet_ui/ruflet/ui/material_control_factory.rb +0 -13
- data/lib/ruflet_ui/ruflet/ui/material_control_methods.rb +0 -170
- data/lib/ruflet_ui/ruflet/ui/material_control_registry.rb +0 -168
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/accelerometer_control.rb +0 -26
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/barometer_control.rb +0 -26
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/battery_control.rb +0 -22
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/camera_control.rb +0 -58
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/clipboard_control.rb +0 -21
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/connectivity_control.rb +0 -22
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/filepicker_control.rb +0 -23
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/flashlight_control.rb +0 -22
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/gyroscope_control.rb +0 -26
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/hapticfeedback_control.rb +0 -21
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/magnetometer_control.rb +0 -26
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/screenbrightness_control.rb +0 -23
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/screenshot_control.rb +0 -31
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/semanticsservice_control.rb +0 -21
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/shakedetector_control.rb +0 -26
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/share_control.rb +0 -21
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/sharedpreferences_control.rb +0 -21
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/storagepaths_control.rb +0 -21
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/urllauncher_control.rb +0 -21
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/useraccelerometer_control.rb +0 -26
- data/lib/ruflet_ui/ruflet/ui/services/ruflet/wakelock_control.rb +0 -21
- data/lib/ruflet_ui/ruflet/ui/services/ruflet_services.rb +0 -66
- data/lib/ruflet_ui/ruflet/ui/shared_control_forwarders.rb +0 -129
- data/lib/ruflet_ui/ruflet/ui/widget_builder.rb +0 -64
- data/lib/ruflet_ui.rb +0 -124
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "json"
|
|
5
|
+
require "net/http"
|
|
6
|
+
require "open3"
|
|
7
|
+
require "rbconfig"
|
|
8
|
+
require "tmpdir"
|
|
9
|
+
require "uri"
|
|
10
|
+
require "yaml"
|
|
11
|
+
|
|
12
|
+
module Ruflet
|
|
13
|
+
module CLI
|
|
14
|
+
module FlutterSdk
|
|
15
|
+
RELEASES_BASE = "https://storage.googleapis.com/flutter_infra_release/releases".freeze
|
|
16
|
+
DEFAULT_FLUTTER_CHANNEL = "stable".freeze
|
|
17
|
+
|
|
18
|
+
def ensure_flutter!(command_name, client_dir: nil, auto_install: true)
|
|
19
|
+
tools = flutter_tools(client_dir: client_dir, auto_install: auto_install)
|
|
20
|
+
return tools if tools
|
|
21
|
+
|
|
22
|
+
warn "Flutter is required for `ruflet #{command_name}` and FVM bootstrap failed."
|
|
23
|
+
warn "Set RUFLET_FLUTTER_VERSION or add .fvmrc to the project."
|
|
24
|
+
exit 1
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def flutter_version_summary(tools)
|
|
28
|
+
flutter_bin = tools[:flutter]
|
|
29
|
+
env = tools[:env] || {}
|
|
30
|
+
|
|
31
|
+
machine_output, status = Open3.capture2e(env, flutter_bin, "--version", "--machine")
|
|
32
|
+
if status.success?
|
|
33
|
+
parsed = JSON.parse(machine_output) rescue nil
|
|
34
|
+
version = parsed && parsed["frameworkVersion"].to_s.strip
|
|
35
|
+
channel = parsed && parsed["channel"].to_s.strip
|
|
36
|
+
return [version, channel].reject(&:empty?).join(" ") unless version.to_s.empty?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
text_output, text_status = Open3.capture2e(env, flutter_bin, "--version")
|
|
40
|
+
return text_output.lines.first.to_s.strip if text_status.success?
|
|
41
|
+
|
|
42
|
+
File.basename(flutter_bin.to_s)
|
|
43
|
+
rescue StandardError
|
|
44
|
+
File.basename(flutter_bin.to_s)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def flutter_tools(client_dir: nil, auto_install: true)
|
|
50
|
+
# Always use FVM so Flutter/Dart match pinned SDK.
|
|
51
|
+
fvm_tools = flutter_tools_via_fvm(client_dir: client_dir, auto_install: auto_install)
|
|
52
|
+
return fvm_tools if fvm_tools
|
|
53
|
+
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def flutter_tools_via_fvm(client_dir: nil, auto_install: true)
|
|
58
|
+
version = desired_flutter_version(client_dir: client_dir)
|
|
59
|
+
return nil if version.to_s.strip.empty?
|
|
60
|
+
|
|
61
|
+
project_dir = fvm_project_dir(client_dir: client_dir)
|
|
62
|
+
flutter = existing_fvm_flutter_bin(project_dir)
|
|
63
|
+
return tools_from_flutter_bin(flutter) if flutter
|
|
64
|
+
|
|
65
|
+
return nil unless auto_install
|
|
66
|
+
|
|
67
|
+
fvm = ensure_fvm_available(client_dir: client_dir)
|
|
68
|
+
return nil unless fvm
|
|
69
|
+
FileUtils.mkdir_p(project_dir)
|
|
70
|
+
fvmrc_path = File.join(project_dir, ".fvmrc")
|
|
71
|
+
unless File.file?(fvmrc_path)
|
|
72
|
+
File.write(fvmrc_path, "{\"flutter\":\"#{version}\"}\n")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
system(fvm_env, fvm, "install", version.to_s, chdir: project_dir, out: File::NULL, err: File::NULL)
|
|
76
|
+
system(fvm_env, fvm, "use", "--force", version.to_s, chdir: project_dir, out: File::NULL, err: File::NULL)
|
|
77
|
+
|
|
78
|
+
flutter = File.join(project_dir, ".fvm", "flutter_sdk", "bin", windows_host? ? "flutter.bat" : "flutter")
|
|
79
|
+
return nil unless File.executable?(flutter)
|
|
80
|
+
|
|
81
|
+
tools_from_flutter_bin(flutter)
|
|
82
|
+
rescue StandardError => e
|
|
83
|
+
warn "FVM bootstrap failed: #{e.class}: #{e.message}"
|
|
84
|
+
nil
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def ensure_fvm_available(client_dir: nil)
|
|
88
|
+
fvm = which_command("fvm")
|
|
89
|
+
return fvm if fvm
|
|
90
|
+
|
|
91
|
+
dart = which_command("dart")
|
|
92
|
+
unless dart
|
|
93
|
+
sdk_root = ensure_flutter_sdk_downloaded(client_dir: client_dir)
|
|
94
|
+
dart = sdk_root ? File.join(sdk_root, "bin", windows_host? ? "dart.bat" : "dart") : nil
|
|
95
|
+
end
|
|
96
|
+
return nil unless dart && File.executable?(dart)
|
|
97
|
+
|
|
98
|
+
system(dart, "pub", "global", "activate", "fvm", out: File::NULL, err: File::NULL)
|
|
99
|
+
which_command("fvm")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def fvm_env
|
|
103
|
+
pub_bin = File.join(Dir.home, ".pub-cache", "bin")
|
|
104
|
+
{ "PATH" => "#{pub_bin}#{File::PATH_SEPARATOR}#{ENV.fetch('PATH', '')}" }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def tools_from_flutter_bin(flutter_bin)
|
|
108
|
+
return nil unless File.executable?(flutter_bin)
|
|
109
|
+
|
|
110
|
+
bin_dir = File.dirname(flutter_bin)
|
|
111
|
+
dart = File.join(bin_dir, windows_host? ? "dart.bat" : "dart")
|
|
112
|
+
{
|
|
113
|
+
flutter: flutter_bin,
|
|
114
|
+
dart: (File.executable?(dart) ? dart : "dart"),
|
|
115
|
+
env: { "PATH" => "#{bin_dir}#{File::PATH_SEPARATOR}#{ENV.fetch('PATH', '')}" }
|
|
116
|
+
}
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def ensure_flutter_sdk_downloaded(client_dir: nil)
|
|
120
|
+
release_info = resolve_flutter_release(client_dir: client_dir)
|
|
121
|
+
return nil unless release_info
|
|
122
|
+
|
|
123
|
+
release = release_info[:release]
|
|
124
|
+
host = release_info[:host]
|
|
125
|
+
archive = release.fetch("archive")
|
|
126
|
+
install_root = File.join(Dir.home, ".ruflet", "flutter", release.fetch("version"), host)
|
|
127
|
+
sdk_root = File.join(install_root, "flutter")
|
|
128
|
+
flutter_bin = File.join(sdk_root, "bin", windows_host? ? "flutter.bat" : "flutter")
|
|
129
|
+
return sdk_root if File.executable?(flutter_bin)
|
|
130
|
+
|
|
131
|
+
FileUtils.mkdir_p(install_root)
|
|
132
|
+
Dir.mktmpdir("ruflet-flutter-sdk-") do |tmpdir|
|
|
133
|
+
archive_path = File.join(tmpdir, File.basename(archive))
|
|
134
|
+
download_file("#{RELEASES_BASE}/#{archive}", archive_path)
|
|
135
|
+
extract_archive(archive_path, install_root)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
return sdk_root if File.executable?(flutter_bin)
|
|
139
|
+
|
|
140
|
+
# Some archives may unpack into a different folder name.
|
|
141
|
+
guessed = Dir.glob(File.join(install_root, "**", windows_host? ? "flutter.bat" : "flutter"))
|
|
142
|
+
.map { |p| File.expand_path("../..", p) }
|
|
143
|
+
.find { |root| File.executable?(File.join(root, "bin", windows_host? ? "flutter.bat" : "flutter")) }
|
|
144
|
+
return guessed if guessed
|
|
145
|
+
|
|
146
|
+
nil
|
|
147
|
+
rescue StandardError => e
|
|
148
|
+
warn "Flutter auto-install failed: #{e.class}: #{e.message}"
|
|
149
|
+
nil
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def resolve_flutter_release(client_dir: nil)
|
|
153
|
+
host = flutter_host
|
|
154
|
+
return nil unless host
|
|
155
|
+
|
|
156
|
+
manifest = fetch_releases_manifest(host)
|
|
157
|
+
return nil unless manifest
|
|
158
|
+
|
|
159
|
+
desired = desired_flutter_spec(client_dir: client_dir)
|
|
160
|
+
release = pick_release(
|
|
161
|
+
manifest,
|
|
162
|
+
version: desired[:version],
|
|
163
|
+
revision: desired[:revision],
|
|
164
|
+
channel: desired[:channel]
|
|
165
|
+
)
|
|
166
|
+
return nil unless release
|
|
167
|
+
|
|
168
|
+
{ release: release, host: host }
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def desired_flutter_version(client_dir: nil)
|
|
172
|
+
desired_flutter_spec(client_dir: client_dir)[:version] || DEFAULT_FLUTTER_CHANNEL
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def desired_flutter_spec(client_dir: nil)
|
|
176
|
+
env = ENV["RUFLET_FLUTTER_VERSION"].to_s.strip
|
|
177
|
+
return { version: env, source: :env } unless env.empty?
|
|
178
|
+
|
|
179
|
+
fvm = parse_fvmrc(find_fvmrc(client_dir))
|
|
180
|
+
return { version: fvm, source: :fvmrc } if fvm
|
|
181
|
+
|
|
182
|
+
metadata = parse_flutter_metadata(find_flutter_metadata(client_dir))
|
|
183
|
+
return metadata.merge(source: :metadata) if metadata
|
|
184
|
+
|
|
185
|
+
{ channel: DEFAULT_FLUTTER_CHANNEL, version: DEFAULT_FLUTTER_CHANNEL, source: :default }
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def fvm_project_dir(client_dir: nil)
|
|
189
|
+
return client_dir if client_dir
|
|
190
|
+
|
|
191
|
+
cwd_fvmrc = find_fvmrc(nil)
|
|
192
|
+
return File.dirname(cwd_fvmrc) if cwd_fvmrc
|
|
193
|
+
|
|
194
|
+
File.join(Dir.home, ".ruflet", "fvm_project")
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def existing_fvm_flutter_bin(project_dir)
|
|
198
|
+
flutter = File.join(project_dir, ".fvm", "flutter_sdk", "bin", windows_host? ? "flutter.bat" : "flutter")
|
|
199
|
+
return flutter if File.executable?(flutter)
|
|
200
|
+
|
|
201
|
+
nil
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def find_fvmrc(client_dir)
|
|
205
|
+
candidates = []
|
|
206
|
+
candidates << File.join(client_dir, ".fvmrc") if client_dir
|
|
207
|
+
candidates << File.join(Dir.pwd, ".fvmrc")
|
|
208
|
+
candidates.find { |p| File.file?(p) }
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def find_flutter_metadata(client_dir)
|
|
212
|
+
candidates = []
|
|
213
|
+
candidates << File.join(client_dir, ".metadata") if client_dir
|
|
214
|
+
repo_client = File.expand_path("../../../../../ruflet_client/.metadata", __dir__)
|
|
215
|
+
template_client = File.expand_path("../../../../../templates/ruflet_flutter_template/.metadata", __dir__)
|
|
216
|
+
candidates << repo_client
|
|
217
|
+
candidates << template_client
|
|
218
|
+
candidates.find { |path| File.file?(path) }
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def parse_fvmrc(path)
|
|
222
|
+
return nil unless path && File.file?(path)
|
|
223
|
+
|
|
224
|
+
raw = File.read(path).strip
|
|
225
|
+
return nil if raw.empty?
|
|
226
|
+
|
|
227
|
+
if raw.start_with?("{")
|
|
228
|
+
json = JSON.parse(raw) rescue {}
|
|
229
|
+
val = json["flutter"] || json["flutterSdkVersion"] || json["flutter_version"]
|
|
230
|
+
return val.to_s.strip unless val.to_s.strip.empty?
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
raw
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def parse_flutter_metadata(path)
|
|
237
|
+
return nil unless path && File.file?(path)
|
|
238
|
+
|
|
239
|
+
parsed = YAML.safe_load(File.read(path), aliases: true) || {}
|
|
240
|
+
version_info = parsed["version"]
|
|
241
|
+
return nil unless version_info.is_a?(Hash)
|
|
242
|
+
|
|
243
|
+
revision = version_info["revision"].to_s.strip
|
|
244
|
+
channel = version_info["channel"].to_s.strip
|
|
245
|
+
return nil if revision.empty?
|
|
246
|
+
|
|
247
|
+
{
|
|
248
|
+
revision: revision,
|
|
249
|
+
channel: channel.empty? ? DEFAULT_FLUTTER_CHANNEL : channel
|
|
250
|
+
}
|
|
251
|
+
rescue StandardError
|
|
252
|
+
nil
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def fetch_releases_manifest(host)
|
|
256
|
+
url = "#{RELEASES_BASE}/releases_#{host}.json"
|
|
257
|
+
uri = URI(url)
|
|
258
|
+
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
|
259
|
+
req = Net::HTTP::Get.new(uri)
|
|
260
|
+
req["User-Agent"] = "ruflet-cli"
|
|
261
|
+
http.request(req)
|
|
262
|
+
end
|
|
263
|
+
return JSON.parse(response.body) if response.is_a?(Net::HTTPSuccess)
|
|
264
|
+
|
|
265
|
+
nil
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def pick_release(manifest, version: nil, revision: nil, channel: nil)
|
|
269
|
+
releases = manifest.fetch("releases", [])
|
|
270
|
+
if revision
|
|
271
|
+
pinned = releases.find { |r| r["hash"] == revision }
|
|
272
|
+
return pinned if pinned
|
|
273
|
+
warn "Requested Flutter revision #{revision} not found for host #{flutter_host}; falling back."
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
if version
|
|
277
|
+
pinned = releases.find { |r| r["channel"] == "stable" && r["version"] == version }
|
|
278
|
+
return pinned if pinned
|
|
279
|
+
warn "Requested Flutter #{version} not found in stable releases; falling back to latest stable."
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
current = manifest.fetch("current_release", {})[(channel || "stable")]
|
|
283
|
+
if current
|
|
284
|
+
by_hash = releases.find { |r| r["hash"] == current }
|
|
285
|
+
return by_hash if by_hash
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
releases.reverse.find { |r| r["channel"] == (channel || "stable") } ||
|
|
289
|
+
releases.reverse.find { |r| r["channel"] == "stable" }
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def flutter_host
|
|
293
|
+
os = RbConfig::CONFIG["host_os"]
|
|
294
|
+
if os.match?(/darwin/i)
|
|
295
|
+
return machine_arch.include?("arm") ? "macos_arm64" : "macos"
|
|
296
|
+
end
|
|
297
|
+
return "linux" if os.match?(/linux/i)
|
|
298
|
+
return "windows" if os.match?(/mswin|mingw|cygwin/i)
|
|
299
|
+
|
|
300
|
+
nil
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def machine_arch
|
|
304
|
+
RbConfig::CONFIG["host_cpu"].to_s.downcase
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def windows_host?
|
|
308
|
+
RbConfig::CONFIG["host_os"].match?(/mswin|mingw|cygwin/i)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def which_command(name)
|
|
312
|
+
exts = windows_host? ? ENV.fetch("PATHEXT", ".EXE;.BAT;.CMD").split(";") : [""]
|
|
313
|
+
ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).each do |dir|
|
|
314
|
+
exts.each do |ext|
|
|
315
|
+
candidate = File.join(dir, "#{name}#{ext}")
|
|
316
|
+
return candidate if File.file?(candidate) && File.executable?(candidate)
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
nil
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def download_file(url, destination, limit: 5)
|
|
323
|
+
raise "Too many redirects while downloading #{url}" if limit <= 0
|
|
324
|
+
|
|
325
|
+
uri = URI(url)
|
|
326
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
|
327
|
+
req = Net::HTTP::Get.new(uri)
|
|
328
|
+
req["User-Agent"] = "ruflet-cli"
|
|
329
|
+
http.request(req) do |res|
|
|
330
|
+
case res
|
|
331
|
+
when Net::HTTPSuccess
|
|
332
|
+
File.open(destination, "wb") { |f| res.read_body { |chunk| f.write(chunk) } }
|
|
333
|
+
return destination
|
|
334
|
+
when Net::HTTPRedirection
|
|
335
|
+
return download_file(res["location"], destination, limit: limit - 1)
|
|
336
|
+
else
|
|
337
|
+
raise "Download failed (#{res.code})"
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def extract_archive(archive, destination)
|
|
344
|
+
if archive.end_with?(".zip")
|
|
345
|
+
if windows_host?
|
|
346
|
+
return system("powershell", "-NoProfile", "-Command", "Expand-Archive -Path '#{archive}' -DestinationPath '#{destination}' -Force")
|
|
347
|
+
end
|
|
348
|
+
return system("unzip", "-oq", archive, "-d", destination)
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
if archive.end_with?(".tar.xz") || archive.end_with?(".tar.gz") || archive.end_with?(".tgz")
|
|
352
|
+
return system("tar", "-xf", archive, "-C", destination)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
false
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "yaml"
|
|
5
|
+
|
|
6
|
+
module Ruflet
|
|
7
|
+
module CLI
|
|
8
|
+
module NewCommand
|
|
9
|
+
CLIENT_EXTENSION_MAP = {
|
|
10
|
+
"ads" => { package: "flet_ads", alias: "ruflet_ads" },
|
|
11
|
+
"audio" => { package: "flet_audio", alias: "ruflet_audio" },
|
|
12
|
+
"audio_recorder" => { package: "flet_audio_recorder", alias: "ruflet_audio_recorder" },
|
|
13
|
+
"camera" => { package: "flet_camera", alias: "ruflet_camera" },
|
|
14
|
+
"charts" => { package: "flet_charts", alias: "ruflet_charts" },
|
|
15
|
+
"code_editor" => { package: "flet_code_editor", alias: "ruflet_code_editor" },
|
|
16
|
+
"color_pickers" => { package: "flet_color_pickers", alias: "ruflet_color_picker" },
|
|
17
|
+
"datatable2" => { package: "flet_datatable2", alias: "ruflet_datatable2" },
|
|
18
|
+
"flashlight" => { package: "flet_flashlight", alias: "ruflet_flashlight" },
|
|
19
|
+
"geolocator" => { package: "flet_geolocator", alias: "ruflet_geolocator" },
|
|
20
|
+
"lottie" => { package: "flet_lottie", alias: "ruflet_lottie" },
|
|
21
|
+
"map" => { package: "flet_map", alias: "ruflet_map" },
|
|
22
|
+
"permission_handler" => { package: "flet_permission_handler", alias: "ruflet_permission_handler" },
|
|
23
|
+
"secure_storage" => { package: "flet_secure_storage", alias: "ruflet_secure_storage" },
|
|
24
|
+
"video" => { package: "flet_video", alias: "ruflet_video" },
|
|
25
|
+
"webview" => { package: "flet_webview", alias: "ruflet_webview" }
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
def command_new(args)
|
|
29
|
+
app_name = args.shift
|
|
30
|
+
if app_name.nil? || app_name.strip.empty?
|
|
31
|
+
warn "Usage: ruflet new <appname>"
|
|
32
|
+
return 1
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
root = File.expand_path(app_name, Dir.pwd)
|
|
36
|
+
if Dir.exist?(root)
|
|
37
|
+
warn "Directory already exists: #{root}"
|
|
38
|
+
return 1
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
FileUtils.mkdir_p(root)
|
|
42
|
+
File.write(File.join(root, "main.rb"), format(Ruflet::CLI::MAIN_TEMPLATE, app_title: humanize_name(File.basename(root))))
|
|
43
|
+
File.write(File.join(root, "Gemfile"), Ruflet::CLI::GEMFILE_TEMPLATE)
|
|
44
|
+
File.write(File.join(root, "README.md"), format(Ruflet::CLI::README_TEMPLATE, app_name: File.basename(root)))
|
|
45
|
+
write_default_ruflet_config(root, File.basename(root))
|
|
46
|
+
copy_ruflet_client_template(root)
|
|
47
|
+
configure_ruflet_client(root)
|
|
48
|
+
|
|
49
|
+
project_name = File.basename(root)
|
|
50
|
+
puts "Run:"
|
|
51
|
+
puts " cd #{project_name}"
|
|
52
|
+
puts " bundle install"
|
|
53
|
+
puts " bundle exec ruflet run main.rb"
|
|
54
|
+
puts
|
|
55
|
+
puts "Client template:"
|
|
56
|
+
puts " cd ruflet_client"
|
|
57
|
+
puts " flutter pub get"
|
|
58
|
+
puts " flutter run"
|
|
59
|
+
0
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def copy_ruflet_client_template(root)
|
|
65
|
+
template_root = File.expand_path("../../../../../ruflet_client", __dir__)
|
|
66
|
+
return unless Dir.exist?(template_root)
|
|
67
|
+
|
|
68
|
+
target = File.join(root, "ruflet_client")
|
|
69
|
+
FileUtils.cp_r(template_root, target)
|
|
70
|
+
prune_client_template(target)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def prune_client_template(target)
|
|
74
|
+
paths = %w[
|
|
75
|
+
.dart_tool
|
|
76
|
+
.idea
|
|
77
|
+
build
|
|
78
|
+
ios/Pods
|
|
79
|
+
ios/.symlinks
|
|
80
|
+
ios/Podfile.lock
|
|
81
|
+
macos/Pods
|
|
82
|
+
macos/Podfile.lock
|
|
83
|
+
android/.gradle
|
|
84
|
+
android/.kotlin
|
|
85
|
+
android/local.properties
|
|
86
|
+
]
|
|
87
|
+
paths.each do |path|
|
|
88
|
+
full = File.join(target, path)
|
|
89
|
+
FileUtils.rm_rf(full) if File.exist?(full)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def write_default_ruflet_config(root, app_name)
|
|
94
|
+
File.write(File.join(root, "ruflet.yaml"), <<~YAML)
|
|
95
|
+
app:
|
|
96
|
+
name: #{app_name}
|
|
97
|
+
# Optional production client endpoint used by `ruflet build`.
|
|
98
|
+
# Example: https://api.example.com
|
|
99
|
+
ruflet_client_url: ""
|
|
100
|
+
|
|
101
|
+
# Source of truth for Flutter client extensions/plugins.
|
|
102
|
+
# Examples: camera, video, audio, flashlight, webview, map
|
|
103
|
+
services: []
|
|
104
|
+
|
|
105
|
+
# Build assets configuration consumed by `ruflet build`.
|
|
106
|
+
# Paths are relative to this file unless absolute.
|
|
107
|
+
assets:
|
|
108
|
+
dir: assets
|
|
109
|
+
splash_screen: assets/splash.png
|
|
110
|
+
icon_launcher: assets/icon.png
|
|
111
|
+
|
|
112
|
+
build:
|
|
113
|
+
splash_color: "#FFFFFF"
|
|
114
|
+
splash_dark_color: "#0B0B0B"
|
|
115
|
+
icon_background: "#FFFFFF"
|
|
116
|
+
theme_color: "#FFFFFF"
|
|
117
|
+
YAML
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def configure_ruflet_client(root)
|
|
121
|
+
config_path = File.join(root, "ruflet.yaml")
|
|
122
|
+
return unless File.file?(config_path)
|
|
123
|
+
|
|
124
|
+
config = YAML.safe_load(File.read(config_path), aliases: true) || {}
|
|
125
|
+
extension_keys = extract_extension_keys(config)
|
|
126
|
+
extension_packages = extension_keys.filter_map { |key| CLIENT_EXTENSION_MAP[key]&.fetch(:package) }.uniq
|
|
127
|
+
extension_aliases = extension_keys.filter_map { |key| CLIENT_EXTENSION_MAP[key]&.fetch(:alias) }.uniq
|
|
128
|
+
|
|
129
|
+
client_dir = File.join(root, "ruflet_client")
|
|
130
|
+
apply_client_manifest!(client_dir, extension_packages, extension_aliases)
|
|
131
|
+
rescue StandardError => e
|
|
132
|
+
warn "Failed to configure ruflet_client from ruflet.yaml: #{e.class}: #{e.message}"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def extract_extension_keys(config)
|
|
136
|
+
from_services = Array(config["services"])
|
|
137
|
+
|
|
138
|
+
from_services
|
|
139
|
+
.map { |v| normalize_extension_key(v) }
|
|
140
|
+
.compact
|
|
141
|
+
.uniq
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def normalize_extension_key(value)
|
|
145
|
+
key = value.to_s.strip.downcase
|
|
146
|
+
return nil if key.empty?
|
|
147
|
+
|
|
148
|
+
key.tr!("-", "_")
|
|
149
|
+
key.gsub!(/\A(flet_)+/, "")
|
|
150
|
+
key.gsub!(/\Aservice_/, "")
|
|
151
|
+
key.gsub!(/\Acontrol_/, "")
|
|
152
|
+
key = "file_picker" if key == "filepicker"
|
|
153
|
+
key
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def apply_client_manifest!(client_dir, extension_packages, extension_aliases)
|
|
157
|
+
return unless Dir.exist?(client_dir)
|
|
158
|
+
|
|
159
|
+
pubspec_path = File.join(client_dir, "pubspec.yaml")
|
|
160
|
+
main_path = File.join(client_dir, "lib", "main.dart")
|
|
161
|
+
prune_client_pubspec(pubspec_path, extension_packages) if File.file?(pubspec_path)
|
|
162
|
+
prune_client_main(main_path, extension_aliases) if File.file?(main_path)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def prune_client_pubspec(path, selected_packages)
|
|
166
|
+
data = YAML.safe_load(File.read(path), aliases: true) || {}
|
|
167
|
+
deps = (data["dependencies"] || {}).dup
|
|
168
|
+
|
|
169
|
+
deps.keys.each do |name|
|
|
170
|
+
next unless name.start_with?("flet_")
|
|
171
|
+
next if name == "flet"
|
|
172
|
+
next if selected_packages.include?(name)
|
|
173
|
+
|
|
174
|
+
deps.delete(name)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
data["dependencies"] = deps
|
|
178
|
+
File.write(path, YAML.dump(data))
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def prune_client_main(path, selected_aliases)
|
|
182
|
+
lines = File.readlines(path)
|
|
183
|
+
alias_to_package = {}
|
|
184
|
+
|
|
185
|
+
lines.each do |line|
|
|
186
|
+
match = line.match(%r{\Aimport 'package:(flet_[^/]+)/\1\.dart' as ([a-zA-Z0-9_]+);})
|
|
187
|
+
next unless match
|
|
188
|
+
|
|
189
|
+
alias_to_package[match[2]] = match[1]
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
kept = lines.select do |line|
|
|
193
|
+
import_match = line.match(%r{\Aimport 'package:(flet_[^/]+)/\1\.dart' as ([a-zA-Z0-9_]+);})
|
|
194
|
+
if import_match
|
|
195
|
+
package_name = import_match[1]
|
|
196
|
+
next true if package_name == "flet"
|
|
197
|
+
next true if selected_aliases.include?(import_match[2])
|
|
198
|
+
next false
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
extension_match = line.match(/\A\s*([a-zA-Z0-9_]+)\.Extension\(\),\s*\z/)
|
|
202
|
+
if extension_match
|
|
203
|
+
extension_alias = extension_match[1]
|
|
204
|
+
package_name = alias_to_package[extension_alias]
|
|
205
|
+
next true if package_name.nil? # non-Flet extension lines
|
|
206
|
+
next true if selected_aliases.include?(extension_alias)
|
|
207
|
+
next false
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
true
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
File.write(path, kept.join)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def humanize_name(name)
|
|
217
|
+
name.to_s.gsub(/[_-]+/, " ").split.map(&:capitalize).join(" ")
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|