@_nazmiforreal/flutter-ota 0.1.12 → 0.1.14
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.
- package/README.md +1 -1
- package/bin/flutter-ota-linux-x64 +0 -0
- package/dart-src/packages/cli-tools/.dart_tool/package_config.json +46 -76
- package/dart-src/packages/cli-tools/.dart_tool/package_graph.json +140 -166
- package/dart-src/packages/cli-tools/README.md +1 -1
- package/dart-src/packages/cli-tools/lib/flutter_ota_kit_cli.dart +30 -17
- package/dart-src/packages/cli-tools/lib/src/backend.dart +30 -31
- package/dart-src/packages/cli-tools/lib/src/cli_base.dart +3 -1
- package/dart-src/packages/cli-tools/lib/src/commands/build.dart +44 -43
- package/dart-src/packages/cli-tools/lib/src/commands/bundle.dart +265 -239
- package/dart-src/packages/cli-tools/lib/src/commands/channel.dart +75 -66
- package/dart-src/packages/cli-tools/lib/src/commands/config_command.dart +39 -35
- package/dart-src/packages/cli-tools/lib/src/commands/console.dart +30 -27
- package/dart-src/packages/cli-tools/lib/src/commands/deploy.dart +88 -72
- package/dart-src/packages/cli-tools/lib/src/commands/doctor.dart +66 -29
- package/dart-src/packages/cli-tools/lib/src/commands/fingerprint.dart +10 -6
- package/dart-src/packages/cli-tools/lib/src/commands/init.dart +290 -181
- package/dart-src/packages/cli-tools/lib/src/commands/keys.dart +24 -23
- package/dart-src/packages/cli-tools/lib/src/commands/migrate.dart +111 -97
- package/dart-src/packages/cli-tools/lib/src/commands/pocketbase.dart +237 -0
- package/dart-src/packages/cli-tools/lib/src/commands/rollback.dart +43 -34
- package/dart-src/packages/cli-tools/lib/src/commands/storage.dart +57 -53
- package/dart-src/packages/cli-tools/lib/src/config.dart +227 -93
- package/dart-src/packages/cli-tools/lib/src/operations.dart +9 -8
- package/dart-src/packages/cli-tools/lib/src/pack.dart +26 -25
- package/dart-src/packages/cli-tools/lib/src/pocketbase/data_bootstrap.dart +39 -0
- package/dart-src/packages/cli-tools/lib/src/pocketbase/hooks/bundles.pb.js +56 -0
- package/dart-src/packages/cli-tools/lib/src/pocketbase/installer.dart +189 -0
- package/dart-src/packages/cli-tools/lib/src/pocketbase/process_manager.dart +123 -0
- package/dart-src/packages/cli-tools/lib/src/pocketbase/schema_installer.dart +237 -0
- package/dart-src/packages/cli-tools/lib/src/runner.dart +36 -15
- package/dart-src/packages/cli-tools/lib/src/sign.dart +13 -5
- package/dart-src/packages/cli-tools/lib/src/ui/ui.dart +10 -13
- package/dart-src/packages/cli-tools/lib/src/util.dart +3 -1
- package/dart-src/packages/cli-tools/pubspec.lock +69 -116
- package/dart-src/packages/cli-tools/pubspec.yaml +25 -7
- package/dart-src/packages/cli-tools/test/backends_test.dart +62 -32
- package/dart-src/packages/cli-tools/test/build_pack_test.dart +4 -4
- package/dart-src/packages/cli-tools/test/cli_test.dart +89 -42
- package/dart-src/packages/cli-tools/test/mocks/mock_aws_s3_client.dart +8 -13
- package/dart-src/packages/cli-tools/test/mocks/mock_d1_client.dart +23 -18
- package/dart-src/packages/cli-tools/test/mocks/mock_pocketbase_client.dart +197 -0
- package/dart-src/packages/cli-tools/test/mocks/mock_postgres_client.dart +70 -46
- package/dart-src/packages/cli-tools/test/pocketbase_installer_test.dart +72 -0
- package/dart-src/packages/cli-tools/test/pocketbase_schema_test.dart +107 -0
- package/dart-src/packages/cli-tools/test/pocketbase_smoke_test.dart +59 -0
- package/dart-src/packages/core/CHANGELOG.md +9 -0
- package/dart-src/packages/core/README.md +2 -2
- package/dart-src/packages/core/example/lib/main.dart +69 -0
- package/dart-src/packages/core/lib/flutter_ota_kit_core.dart +1 -1
- package/dart-src/packages/core/lib/src/app_update_info.dart +17 -15
- package/dart-src/packages/core/lib/src/bundle.dart +102 -94
- package/dart-src/packages/core/lib/src/bundle_artifacts.dart +1 -2
- package/dart-src/packages/core/lib/src/bundle_patch_artifact.dart +15 -16
- package/dart-src/packages/core/lib/src/changed_asset.dart +24 -22
- package/dart-src/packages/core/lib/src/get_bundles_args.dart +13 -13
- package/dart-src/packages/core/lib/src/metadata.dart +9 -7
- package/dart-src/packages/core/lib/src/patch_info.dart +8 -7
- package/dart-src/packages/core/lib/src/platform.dart +4 -3
- package/dart-src/packages/core/lib/src/rollout.dart +14 -11
- package/dart-src/packages/core/lib/src/semver_range.dart +49 -39
- package/dart-src/packages/core/lib/src/semver_version.dart +8 -7
- package/dart-src/packages/core/lib/src/status.dart +4 -3
- package/dart-src/packages/core/lib/src/update_bundle_params.dart +7 -7
- package/dart-src/packages/core/lib/src/uuid.dart +1 -2
- package/dart-src/packages/core/pubspec.yaml +6 -7
- package/dart-src/packages/core/test/rollout_test.dart +15 -8
- package/dart-src/packages/core/test/semver_test.dart +5 -2
- package/dart-src/packages/core/test/types_test.dart +26 -24
- package/dart-src/packages/core/test/uuid_test.dart +3 -1
- package/dart-src/packages/core/tool/dbg.dart +1 -0
- package/dart-src/plugins/aws/CHANGELOG.md +15 -0
- package/dart-src/plugins/aws/example/lib/main.dart +60 -0
- package/dart-src/plugins/aws/lib/flutter_ota_kit_aws.dart +5 -1
- package/dart-src/plugins/aws/lib/src/aws_cloudfront_client.dart +11 -16
- package/dart-src/plugins/aws/lib/src/aws_cloudfront_signer.dart +7 -2
- package/dart-src/plugins/aws/lib/src/aws_database.dart +14 -18
- package/dart-src/plugins/aws/lib/src/aws_s3_client.dart +23 -18
- package/dart-src/plugins/aws/lib/src/aws_ssm_client.dart +5 -4
- package/dart-src/plugins/aws/lib/src/aws_storage.dart +2 -3
- package/dart-src/plugins/aws/lib/src/aws_storage_profile.dart +10 -16
- package/dart-src/plugins/aws/lib/src/with_cloudfront_signed_url.dart +6 -9
- package/dart-src/plugins/aws/pubspec.yaml +15 -10
- package/dart-src/plugins/aws/test/aws_database_test.dart +51 -57
- package/dart-src/plugins/aws/test/mock_aws_s3_client.dart +8 -13
- package/dart-src/plugins/cloudflare/CHANGELOG.md +15 -0
- package/dart-src/plugins/cloudflare/example/lib/main.dart +62 -0
- package/dart-src/plugins/cloudflare/lib/flutter_ota_kit_cloudflare.dart +4 -2
- package/dart-src/plugins/cloudflare/lib/src/cloudflare_worker_database.dart +3 -3
- package/dart-src/plugins/cloudflare/lib/src/d1_build_where.dart +3 -2
- package/dart-src/plugins/cloudflare/lib/src/d1_bundle_mapper.dart +24 -27
- package/dart-src/plugins/cloudflare/lib/src/d1_database_plugin.dart +22 -30
- package/dart-src/plugins/cloudflare/lib/src/r2_config.dart +1 -1
- package/dart-src/plugins/cloudflare/lib/src/r2_s3_client.dart +21 -29
- package/dart-src/plugins/cloudflare/lib/src/r2_storage.dart +7 -7
- package/dart-src/plugins/cloudflare/lib/src/r2_storage_profile.dart +7 -15
- package/dart-src/plugins/cloudflare/pubspec.yaml +14 -9
- package/dart-src/plugins/cloudflare/test/cloudflare_worker_database_test.dart +46 -42
- package/dart-src/plugins/cloudflare/test/d1_database_test.dart +100 -90
- package/dart-src/plugins/cloudflare/test/mock_d1_client.dart +23 -18
- package/dart-src/plugins/cloudflare/test/mock_r2_client.dart +8 -13
- package/dart-src/plugins/cloudflare/test/r2_storage_test.dart +1 -4
- package/dart-src/plugins/plugin-core/CHANGELOG.md +15 -1
- package/dart-src/plugins/plugin-core/example/lib/main.dart +61 -0
- package/dart-src/plugins/plugin-core/lib/flutter_ota_kit_plugin_core.dart +3 -7
- package/dart-src/plugins/plugin-core/lib/src/asset_storage_layout.dart +5 -5
- package/dart-src/plugins/plugin-core/lib/src/bundle_helpers.dart +23 -0
- package/dart-src/plugins/plugin-core/lib/src/bundle_storage_layout.dart +16 -10
- package/dart-src/plugins/plugin-core/lib/src/bundle_unit_of_work.dart +31 -26
- package/dart-src/plugins/plugin-core/lib/src/calculate_pagination.dart +5 -1
- package/dart-src/plugins/plugin-core/lib/src/content_addressed_assets.dart +1 -1
- package/dart-src/plugins/plugin-core/lib/src/create_blob_database_plugin.dart +78 -71
- package/dart-src/plugins/plugin-core/lib/src/create_database_plugin.dart +56 -35
- package/dart-src/plugins/plugin-core/lib/src/create_storage_plugin.dart +10 -13
- package/dart-src/plugins/plugin-core/lib/src/paginate_bundles.dart +30 -17
- package/dart-src/plugins/plugin-core/lib/src/parse_storage_uri.dart +3 -1
- package/dart-src/plugins/plugin-core/lib/src/query_bundles.dart +5 -3
- package/dart-src/plugins/plugin-core/lib/src/request_update_bundle_state.dart +2 -4
- package/dart-src/plugins/plugin-core/lib/src/storage_helpers.dart +18 -0
- package/dart-src/plugins/plugin-core/lib/src/types.dart +7 -6
- package/dart-src/plugins/plugin-core/pubspec.yaml +12 -9
- package/dart-src/plugins/plugin-core/test/asset_storage_layout_test.dart +13 -9
- package/dart-src/plugins/plugin-core/test/bundle_unit_of_work_test.dart +28 -15
- package/dart-src/plugins/plugin-core/test/create_blob_database_plugin_test.dart +254 -122
- package/dart-src/plugins/plugin-core/test/create_database_plugin_test.dart +36 -32
- package/dart-src/plugins/plugin-core/test/create_storage_plugin_test.dart +18 -15
- package/dart-src/plugins/plugin-core/test/generate_min_bundle_id_test.dart +8 -3
- package/dart-src/plugins/plugin-core/test/get_update_info_test.dart +682 -693
- package/dart-src/plugins/plugin-core/test/helpers_test.dart +45 -21
- package/dart-src/plugins/plugin-core/test/query_bundles_test.dart +76 -13
- package/dart-src/plugins/plugin-core/test/uuidv7_test.dart +20 -9
- package/dart-src/plugins/pocketbase/CHANGELOG.md +8 -0
- package/dart-src/plugins/pocketbase/LICENSE +21 -0
- package/dart-src/plugins/pocketbase/README.md +54 -0
- package/dart-src/plugins/pocketbase/example/lib/main.dart +62 -0
- package/dart-src/plugins/pocketbase/lib/flutter_ota_kit_pocketbase.dart +28 -0
- package/dart-src/plugins/pocketbase/lib/src/pocketbase_bundle_mapper.dart +121 -0
- package/dart-src/plugins/pocketbase/lib/src/pocketbase_client.dart +349 -0
- package/dart-src/plugins/pocketbase/lib/src/pocketbase_config.dart +61 -0
- package/dart-src/plugins/pocketbase/lib/src/pocketbase_database.dart +278 -0
- package/dart-src/plugins/pocketbase/lib/src/pocketbase_storage.dart +255 -0
- package/dart-src/plugins/pocketbase/pubspec.yaml +26 -0
- package/dart-src/plugins/pocketbase/test/pb_uri_test.dart +12 -0
- package/dart-src/plugins/postgres/CHANGELOG.md +16 -0
- package/dart-src/plugins/postgres/example/lib/main.dart +67 -0
- package/dart-src/plugins/postgres/lib/flutter_ota_kit_postgres.dart +3 -6
- package/dart-src/plugins/postgres/lib/src/postgres_bundle_mapper.dart +32 -52
- package/dart-src/plugins/postgres/lib/src/postgres_config.dart +3 -1
- package/dart-src/plugins/postgres/lib/src/postgres_database.dart +28 -38
- package/dart-src/plugins/postgres/lib/src/postgres_get_update_info.dart +16 -14
- package/dart-src/plugins/postgres/lib/src/postgres_storage.dart +26 -14
- package/dart-src/plugins/postgres/lib/src/postgres_types.dart +27 -28
- package/dart-src/plugins/postgres/pubspec.yaml +14 -9
- package/dart-src/plugins/postgres/test/mock_postgres_client.dart +62 -39
- package/dart-src/plugins/postgres/test/postgres_bundle_mapper_test.dart +3 -4
- package/dart-src/plugins/postgres/test/postgres_database_test.dart +102 -73
- package/dart-src/plugins/postgres/test/postgres_storage_runtime_test.dart +60 -0
- package/dart-src/plugins/supabase/CHANGELOG.md +20 -0
- package/dart-src/plugins/supabase/README.md +2 -2
- package/dart-src/plugins/supabase/example/lib/main.dart +63 -0
- package/dart-src/plugins/supabase/lib/flutter_ota_kit_supabase.dart +2 -0
- package/dart-src/plugins/supabase/lib/src/error_message.dart +11 -0
- package/dart-src/plugins/supabase/lib/src/supabase_bundle_mapper.dart +34 -58
- package/dart-src/plugins/supabase/lib/src/supabase_client_adapter.dart +3 -13
- package/dart-src/plugins/supabase/lib/src/supabase_client_http.dart +34 -52
- package/dart-src/plugins/supabase/lib/src/supabase_database.dart +38 -30
- package/dart-src/plugins/supabase/lib/src/supabase_edge_function_storage.dart +21 -29
- package/dart-src/plugins/supabase/lib/src/supabase_signed_url_batcher.dart +7 -19
- package/dart-src/plugins/supabase/lib/src/supabase_storage.dart +18 -29
- package/dart-src/plugins/supabase/lib/src/types.dart +26 -26
- package/dart-src/plugins/supabase/pubspec.yaml +14 -9
- package/dart-src/plugins/supabase/test/mock_supabase_client.dart +57 -57
- package/dart-src/plugins/supabase/test/supabase_bundle_mapper_test.dart +30 -27
- package/dart-src/plugins/supabase/test/supabase_database_test.dart +26 -35
- package/dart-src/plugins/supabase/test/supabase_storage_test.dart +27 -34
- package/package.json +3 -3
- package/scripts/vendor.sh +1 -1
|
@@ -9,9 +9,15 @@ class ChannelCommand extends FlutterPatcherCommand {
|
|
|
9
9
|
final Backend? backendOverride;
|
|
10
10
|
|
|
11
11
|
ChannelCommand({this.config, this.backendOverride}) {
|
|
12
|
-
addSubcommand(
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
addSubcommand(
|
|
13
|
+
ChannelListCommand(config: config, backendOverride: backendOverride),
|
|
14
|
+
);
|
|
15
|
+
addSubcommand(
|
|
16
|
+
ChannelGetCommand(config: config, backendOverride: backendOverride),
|
|
17
|
+
);
|
|
18
|
+
addSubcommand(
|
|
19
|
+
ChannelSetCommand(config: config, backendOverride: backendOverride),
|
|
20
|
+
);
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
@override
|
|
@@ -22,13 +28,13 @@ class ChannelCommand extends FlutterPatcherCommand {
|
|
|
22
28
|
|
|
23
29
|
@override
|
|
24
30
|
Future<int> run() => runGuarded(() async {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
print(description);
|
|
32
|
+
print('');
|
|
33
|
+
print('Subcommands:');
|
|
34
|
+
print(' list List channels');
|
|
35
|
+
print(' get <channel> Show the live bundle for a channel');
|
|
36
|
+
print(' set <c> <id> Promote a bundle to a channel');
|
|
37
|
+
});
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
class ChannelListCommand extends FlutterPatcherCommand {
|
|
@@ -44,21 +50,21 @@ class ChannelListCommand extends FlutterPatcherCommand {
|
|
|
44
50
|
String get description => 'List channels.';
|
|
45
51
|
|
|
46
52
|
@override
|
|
47
|
-
ArgParser get argParser =>
|
|
48
|
-
|
|
53
|
+
ArgParser get argParser =>
|
|
54
|
+
ArgParser()..addOption('backend', abbr: 'b', help: 'Backend provider.');
|
|
49
55
|
|
|
50
56
|
@override
|
|
51
57
|
Future<int> run() => runGuarded(() async {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
|
|
59
|
+
final backend = requireBackend(cfg, override: backendOverride);
|
|
60
|
+
banner('channel · list');
|
|
61
|
+
final channels = await listChannels(backend);
|
|
62
|
+
if (channels.isEmpty) {
|
|
63
|
+
step('(no channels)');
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
box('${channels.length} channels', channels.map((c) => ' $c').toList());
|
|
67
|
+
});
|
|
62
68
|
}
|
|
63
69
|
|
|
64
70
|
class ChannelGetCommand extends FlutterPatcherCommand {
|
|
@@ -80,26 +86,32 @@ class ChannelGetCommand extends FlutterPatcherCommand {
|
|
|
80
86
|
|
|
81
87
|
@override
|
|
82
88
|
Future<int> run() => runGuarded(() async {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
89
|
+
final channel = argResults!['channel'] as String?;
|
|
90
|
+
if (channel == null || channel.isEmpty) {
|
|
91
|
+
throw PackException(
|
|
92
|
+
'Usage: flutter_ota_kit channel get --channel <channel>',
|
|
93
|
+
64,
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
|
|
97
|
+
final backend = requireBackend(cfg, override: backendOverride);
|
|
98
|
+
banner('channel · get');
|
|
99
|
+
final bundle = await getChannel(backend, channel);
|
|
100
|
+
if (bundle == null) {
|
|
101
|
+
err('no live bundle on channel "$channel"');
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
box('channel "$channel"', [
|
|
105
|
+
kv('live bundle', cyan(bundle.id)),
|
|
106
|
+
kv('platform', bundle.platform.value),
|
|
107
|
+
kv('enabled', bundle.enabled ? green('yes') : yellow('no')),
|
|
108
|
+
kv(
|
|
109
|
+
'target',
|
|
110
|
+
bundle.targetAppVersion ?? bundle.fingerprintHash ?? dim('-'),
|
|
111
|
+
),
|
|
112
|
+
if (bundle.message != null) kv('message', bundle.message!),
|
|
113
|
+
]);
|
|
114
|
+
});
|
|
103
115
|
}
|
|
104
116
|
|
|
105
117
|
class ChannelSetCommand extends FlutterPatcherCommand {
|
|
@@ -122,28 +134,25 @@ class ChannelSetCommand extends FlutterPatcherCommand {
|
|
|
122
134
|
|
|
123
135
|
@override
|
|
124
136
|
Future<int> run() => runGuarded(() async {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
kv('bundle', cyan(bundleId)),
|
|
147
|
-
]);
|
|
148
|
-
});
|
|
137
|
+
final channel = argResults!['channel'] as String?;
|
|
138
|
+
final bundleId = argResults!['bundle-id'] as String?;
|
|
139
|
+
if (channel == null ||
|
|
140
|
+
channel.isEmpty ||
|
|
141
|
+
bundleId == null ||
|
|
142
|
+
bundleId.isEmpty) {
|
|
143
|
+
throw PackException(
|
|
144
|
+
'Usage: flutter_ota_kit channel set --channel <c> --bundle-id <id>',
|
|
145
|
+
64,
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
|
|
149
|
+
final backend = requireBackend(cfg, override: backendOverride);
|
|
150
|
+
banner('channel · set');
|
|
151
|
+
await spinner(
|
|
152
|
+
() => promoteBundle(backend, bundleId, channel),
|
|
153
|
+
'Promoting $bundleId to $channel',
|
|
154
|
+
done: 'Channel set',
|
|
155
|
+
);
|
|
156
|
+
box('channel set', [kv('channel', channel), kv('bundle', cyan(bundleId))]);
|
|
157
|
+
});
|
|
149
158
|
}
|
|
@@ -22,10 +22,14 @@ class ConfigCommand extends FlutterPatcherCommand {
|
|
|
22
22
|
|
|
23
23
|
@override
|
|
24
24
|
Future<int> run() => runGuarded(() async {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
// No subcommand selected.
|
|
26
|
+
print(description);
|
|
27
|
+
print('');
|
|
28
|
+
print('Subcommands:');
|
|
29
|
+
print(' get <key>');
|
|
30
|
+
print(' set <key> <value>');
|
|
31
|
+
print(' list');
|
|
32
|
+
});
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
Map<String, dynamic> _loadProjectJson() {
|
|
@@ -39,9 +43,7 @@ Map<String, dynamic> _loadProjectJson() {
|
|
|
39
43
|
void _saveProjectJson(Map<String, dynamic> json) {
|
|
40
44
|
final file = configCandidates().first;
|
|
41
45
|
file.parent.createSync(recursive: true);
|
|
42
|
-
file.writeAsStringSync(
|
|
43
|
-
const JsonEncoder.withIndent(' ').convert(json),
|
|
44
|
-
);
|
|
46
|
+
file.writeAsStringSync(const JsonEncoder.withIndent(' ').convert(json));
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
class ConfigGetCommand extends FlutterPatcherCommand {
|
|
@@ -49,26 +51,28 @@ class ConfigGetCommand extends FlutterPatcherCommand {
|
|
|
49
51
|
String get name => 'get';
|
|
50
52
|
|
|
51
53
|
@override
|
|
52
|
-
String get description =>
|
|
54
|
+
String get description =>
|
|
55
|
+
'Print a config value by dot-path (e.g. supabase.url).';
|
|
53
56
|
|
|
54
57
|
@override
|
|
55
|
-
ArgParser get argParser =>
|
|
58
|
+
ArgParser get argParser =>
|
|
59
|
+
ArgParser()..addOption('key', abbr: 'k', help: 'Dot-path key.');
|
|
56
60
|
|
|
57
61
|
@override
|
|
58
62
|
Future<int> run() => runGuarded(() async {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
63
|
+
final key = argResults!['key'] as String?;
|
|
64
|
+
if (key == null || key.isEmpty) {
|
|
65
|
+
throw StateError('Usage: flutter_ota_kit config get <key>');
|
|
66
|
+
}
|
|
67
|
+
final value = readPath(_loadProjectJson(), key);
|
|
68
|
+
if (value == null) {
|
|
69
|
+
stderr.writeln('(not set)');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
stdout.writeln(
|
|
73
|
+
value is String ? value : const JsonEncoder().convert(value),
|
|
74
|
+
);
|
|
75
|
+
});
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
class ConfigSetCommand extends FlutterPatcherCommand {
|
|
@@ -85,16 +89,16 @@ class ConfigSetCommand extends FlutterPatcherCommand {
|
|
|
85
89
|
|
|
86
90
|
@override
|
|
87
91
|
Future<int> run() => runGuarded(() async {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
92
|
+
final key = argResults!['key'] as String?;
|
|
93
|
+
final value = argResults!['value'] as String?;
|
|
94
|
+
if (key == null || key.isEmpty || value == null) {
|
|
95
|
+
throw StateError('Usage: flutter_ota_kit config set <key> <value>');
|
|
96
|
+
}
|
|
97
|
+
final json = _loadProjectJson();
|
|
98
|
+
writePath(json, key, value);
|
|
99
|
+
_saveProjectJson(json);
|
|
100
|
+
stdout.writeln('Set $key = $value');
|
|
101
|
+
});
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
class ConfigListCommand extends FlutterPatcherCommand {
|
|
@@ -106,7 +110,7 @@ class ConfigListCommand extends FlutterPatcherCommand {
|
|
|
106
110
|
|
|
107
111
|
@override
|
|
108
112
|
Future<int> run() => runGuarded(() async {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
113
|
+
final json = _loadProjectJson();
|
|
114
|
+
stdout.writeln(const JsonEncoder.withIndent(' ').convert(json));
|
|
115
|
+
});
|
|
112
116
|
}
|
|
@@ -16,8 +16,11 @@ class ConsoleCommand extends FlutterPatcherCommand {
|
|
|
16
16
|
|
|
17
17
|
@override
|
|
18
18
|
ArgParser get argParser => ArgParser()
|
|
19
|
-
..addFlag(
|
|
20
|
-
|
|
19
|
+
..addFlag(
|
|
20
|
+
'open',
|
|
21
|
+
help:
|
|
22
|
+
'Launch the console with `flutter run -d chrome` (requires Flutter).',
|
|
23
|
+
);
|
|
21
24
|
|
|
22
25
|
Directory? _findConsoleDir() {
|
|
23
26
|
var dir = Directory(p.dirname(Platform.script.path));
|
|
@@ -31,29 +34,29 @@ class ConsoleCommand extends FlutterPatcherCommand {
|
|
|
31
34
|
|
|
32
35
|
@override
|
|
33
36
|
Future<int> run() => runGuarded(() async {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
37
|
+
final consoleDir = _findConsoleDir();
|
|
38
|
+
if (consoleDir == null) {
|
|
39
|
+
err('Console package not found (expected packages/console).');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (argResults!['open'] as bool) {
|
|
43
|
+
step('Launching console...');
|
|
44
|
+
final process = await Process.start(
|
|
45
|
+
'flutter',
|
|
46
|
+
['run', '-d', 'chrome'],
|
|
47
|
+
workingDirectory: consoleDir.path,
|
|
48
|
+
runInShell: true,
|
|
49
|
+
mode: ProcessStartMode.inheritStdio,
|
|
50
|
+
);
|
|
51
|
+
exitCode = await process.exitCode;
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
banner('console');
|
|
55
|
+
box('flutter_ota_kit console', [
|
|
56
|
+
'Open the web console with Flutter:',
|
|
57
|
+
'',
|
|
58
|
+
kv('dir', consoleDir.path),
|
|
59
|
+
kv('run', 'flutter run -d chrome'),
|
|
60
|
+
]);
|
|
61
|
+
});
|
|
59
62
|
}
|
|
@@ -25,87 +25,103 @@ class DeployCommand extends FlutterPatcherCommand {
|
|
|
25
25
|
|
|
26
26
|
@override
|
|
27
27
|
ArgParser get argParser => ArgParser()
|
|
28
|
-
..addOption(
|
|
29
|
-
|
|
28
|
+
..addOption(
|
|
29
|
+
'backend',
|
|
30
|
+
abbr: 'b',
|
|
31
|
+
help: 'Backend provider (supabase/postgres/cloudflare/aws).',
|
|
32
|
+
)
|
|
30
33
|
..addOption('source', abbr: 's', help: 'Source directory to zip + upload.')
|
|
31
34
|
..addOption('channel', abbr: 'c', help: 'Target channel.')
|
|
32
35
|
..addOption('platform', abbr: 'p', defaultsTo: 'android', help: 'Platform.')
|
|
33
36
|
..addOption('message', abbr: 'm', help: 'Release message.')
|
|
34
37
|
..addFlag('force', abbr: 'f', help: 'Force the update on clients.')
|
|
35
|
-
..addOption(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
..addOption(
|
|
38
|
+
..addOption(
|
|
39
|
+
'target-app-version',
|
|
40
|
+
help: 'Semver range target (XOR with fingerprint-hash).',
|
|
41
|
+
)
|
|
42
|
+
..addOption(
|
|
43
|
+
'fingerprint-hash',
|
|
44
|
+
help: 'Fingerprint hash target (XOR with target-app-version).',
|
|
45
|
+
)
|
|
46
|
+
..addOption(
|
|
47
|
+
'key',
|
|
48
|
+
abbr: 'k',
|
|
49
|
+
help: 'Path to Ed25519 private key file (sign bundle).',
|
|
50
|
+
)
|
|
40
51
|
..addOption('git-commit-hash', help: 'Git commit hash (auto-detected).')
|
|
41
|
-
..addOption(
|
|
52
|
+
..addOption(
|
|
53
|
+
'bundle-id',
|
|
54
|
+
abbr: 'i',
|
|
55
|
+
help: 'Explicit bundle id (uuidv7 by default).',
|
|
56
|
+
);
|
|
42
57
|
|
|
43
58
|
@override
|
|
44
59
|
Future<int> run() => runGuarded(() async {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
60
|
+
final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
|
|
61
|
+
final backend = requireBackend(cfg, override: backendOverride);
|
|
62
|
+
final source = argResults!['source'] as String? ?? cfg?.source ?? './dist';
|
|
63
|
+
final channel =
|
|
64
|
+
argResults!['channel'] as String? ?? cfg?.channel ?? 'production';
|
|
65
|
+
final platform =
|
|
66
|
+
argResults!['platform'] as String? ?? cfg?.platform ?? 'android';
|
|
67
|
+
final message = argResults!['message'] as String?;
|
|
68
|
+
final force = argResults!['force'] as bool;
|
|
69
|
+
final targetAppVersion = argResults!['target-app-version'] as String?;
|
|
70
|
+
final fingerprintHash = argResults!['fingerprint-hash'] as String?;
|
|
71
|
+
final keyPath = argResults!['key'] as String?;
|
|
72
|
+
String? signingKey;
|
|
73
|
+
if (keyPath != null) signingKey = File(keyPath).readAsStringSync().trim();
|
|
74
|
+
final resolvedGitCommitHash =
|
|
75
|
+
argResults!['git-commit-hash'] as String? ??
|
|
76
|
+
await gitCommitHash(source);
|
|
77
|
+
final bundleId = argResults!['bundle-id'] as String?;
|
|
62
78
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
banner('deploy');
|
|
80
|
+
stdout.writeln(
|
|
81
|
+
'${gray('channel')} ${cyan(channel)} '
|
|
82
|
+
'${gray('platform')} ${cyan(platform)} '
|
|
83
|
+
'${gray('source')} ${dim(source)}',
|
|
84
|
+
);
|
|
85
|
+
final bundle = await spinner(
|
|
86
|
+
() => deployBundle(
|
|
87
|
+
backend,
|
|
88
|
+
DeployOptions(
|
|
89
|
+
source: source,
|
|
90
|
+
channel: channel,
|
|
91
|
+
platform: platform,
|
|
92
|
+
message: message,
|
|
93
|
+
force: force,
|
|
94
|
+
targetAppVersion: targetAppVersion,
|
|
95
|
+
fingerprintHash: fingerprintHash,
|
|
96
|
+
signingKeyBase64: signingKey,
|
|
97
|
+
gitCommitHash: resolvedGitCommitHash,
|
|
98
|
+
bundleId: bundleId,
|
|
99
|
+
),
|
|
100
|
+
),
|
|
101
|
+
'Uploading & registering bundle',
|
|
102
|
+
done: 'Bundle deployed',
|
|
103
|
+
);
|
|
88
104
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
105
|
+
final lines = <String>[
|
|
106
|
+
kv('bundle id', cyan(bundle.id)),
|
|
107
|
+
kv('channel', bundle.channel),
|
|
108
|
+
kv('platform', bundle.platform.value),
|
|
109
|
+
kv('enabled', bundle.enabled ? green('true') : yellow('false')),
|
|
110
|
+
kv('storage uri', gray(bundle.storageUri)),
|
|
111
|
+
];
|
|
112
|
+
if (bundle.targetAppVersion != null) {
|
|
113
|
+
lines.add(kv('target app', bundle.targetAppVersion!));
|
|
114
|
+
}
|
|
115
|
+
if (bundle.fingerprintHash != null) {
|
|
116
|
+
lines.add(kv('fingerprint', bundle.fingerprintHash!));
|
|
117
|
+
}
|
|
118
|
+
if (bundle.gitCommitHash != null) {
|
|
119
|
+
lines.add(kv('git commit', bundle.gitCommitHash!));
|
|
120
|
+
}
|
|
121
|
+
if (bundle.message != null) lines.add(kv('message', bundle.message!));
|
|
122
|
+
if (bundle.metadata?.signature != null) {
|
|
123
|
+
lines.add(kv('signature', dim('✓ signed')));
|
|
124
|
+
}
|
|
125
|
+
box('deployed', lines);
|
|
126
|
+
});
|
|
111
127
|
}
|
|
@@ -20,37 +20,74 @@ class DoctorCommand extends FlutterPatcherCommand {
|
|
|
20
20
|
'Diagnose the local environment and backend connection.';
|
|
21
21
|
|
|
22
22
|
@override
|
|
23
|
-
ArgParser get argParser =>
|
|
24
|
-
|
|
23
|
+
ArgParser get argParser =>
|
|
24
|
+
ArgParser()..addOption('backend', abbr: 'b', help: 'Backend provider.');
|
|
25
25
|
|
|
26
26
|
@override
|
|
27
27
|
Future<int> run() => runGuarded(() async {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
banner('doctor');
|
|
29
|
+
final lines = <String>[
|
|
30
|
+
kv('dart', Platform.version.split(' ').first),
|
|
31
|
+
kv(
|
|
32
|
+
'os',
|
|
33
|
+
'${Platform.operatingSystem} '
|
|
34
34
|
'${Platform.operatingSystemVersion.split('\n').first}',
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
35
|
+
),
|
|
36
|
+
];
|
|
37
|
+
final cfg = effectiveConfig(config ?? loadConfig(), argResults!);
|
|
38
|
+
if (cfg == null) {
|
|
39
|
+
lines.add(kv('config', yellow('not found — run `flutter_ota_kit init`')));
|
|
40
|
+
box('doctor', lines);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
lines
|
|
44
|
+
..add(kv('provider', cfg.provider))
|
|
45
|
+
..add(kv('channel', cfg.channel))
|
|
46
|
+
..add(kv('platform', cfg.platform));
|
|
47
|
+
|
|
48
|
+
// PocketBase-specific: show binary + health endpoint status.
|
|
49
|
+
if (cfg.provider == 'pocketbase') {
|
|
50
|
+
await _checkPocketBase(cfg, lines);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
final backend = requireBackend(cfg, override: backendOverride);
|
|
55
|
+
final channels = await backend.db.getChannels();
|
|
56
|
+
lines.add(kv('backend', green('reachable — ${channels.join(', ')}')));
|
|
57
|
+
} catch (e) {
|
|
58
|
+
lines.add(kv('backend', red('unreachable — $e')));
|
|
59
|
+
}
|
|
60
|
+
box('doctor', lines);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
Future<void> _checkPocketBase(
|
|
64
|
+
FlutterPatcherConfig cfg,
|
|
65
|
+
List<String> lines,
|
|
66
|
+
) async {
|
|
67
|
+
final paths = PocketBaseInstallPaths.resolve();
|
|
68
|
+
final installed = await paths.binaryPath.exists();
|
|
69
|
+
lines.add(
|
|
70
|
+
kv(
|
|
71
|
+
'pocketbase binary',
|
|
72
|
+
installed
|
|
73
|
+
? green('installed at ${paths.binaryPath.path}')
|
|
74
|
+
: yellow(
|
|
75
|
+
'not installed — run `flutter_ota_kit pocketbase install`',
|
|
76
|
+
),
|
|
77
|
+
),
|
|
78
|
+
);
|
|
79
|
+
// Probe the health endpoint if a URL is configured.
|
|
80
|
+
final url = cfg.pocketbase.url;
|
|
81
|
+
if (url != null && url.isNotEmpty) {
|
|
82
|
+
try {
|
|
83
|
+
final client = PocketBaseClient(url);
|
|
84
|
+
final ok = await client.health();
|
|
85
|
+
lines.add(
|
|
86
|
+
kv('pocketbase health', ok ? green('reachable') : red('unreachable')),
|
|
87
|
+
);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
lines.add(kv('pocketbase health', red('unreachable — $e')));
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
56
93
|
}
|