@_nazmiforreal/flutter-ota 0.1.4 → 0.1.5

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.
@@ -34,29 +34,46 @@ const binPath = path.join(binDir, binName);
34
34
  const sourceEntry = path.join(
35
35
  binDir, '..', 'dart-src', 'packages', 'cli-tools', 'bin', 'flutter_patcher.dart',
36
36
  );
37
+ const cliDir = path.dirname(path.dirname(sourceEntry));
37
38
 
38
- function run(bin, args, cwd) {
39
- const res = spawnSync(bin, args, { stdio: 'inherit', windowsHide: false, cwd });
39
+ function chmodIfNeeded(p) {
40
+ try {
41
+ const st = fs.statSync(p);
42
+ // Ensure owner-executable bit is set.
43
+ if (!(st.mode & 0o100)) fs.chmodSync(p, st.mode | 0o755);
44
+ } catch (_) {
45
+ // Non-fatal.
46
+ }
47
+ }
48
+
49
+ function run(bin, args) {
50
+ const res = spawnSync(bin, args, { stdio: 'inherit', windowsHide: false });
40
51
  process.exit(res.status == null ? 1 : res.status);
41
52
  }
42
53
 
43
54
  if (fs.existsSync(binPath)) {
55
+ chmodIfNeeded(binPath);
44
56
  run(binPath, process.argv.slice(2));
45
57
  } else if (
46
58
  spawnSync('dart', ['--version'], { stdio: 'ignore' }).status === 0 &&
47
59
  fs.existsSync(sourceEntry)
48
60
  ) {
49
- // Ensure dependencies are resolved before running from source.
50
- const cliDir = path.dirname(path.dirname(sourceEntry));
51
- const getRes = spawnSync('dart', ['pub', 'get'], { stdio: 'inherit', cwd: cliDir });
52
- if (getRes.status !== 0) {
53
- console.error(
54
- 'flutter-patcher: `dart pub get` failed. Install dependencies or build ' +
55
- `a prebuilt manually:\n cd ${cliDir} && dart compile exe ` +
56
- `bin/flutter_patcher.dart -o ${binPath}`,
57
- );
58
- process.exit(1);
61
+ // Ensure dependencies are resolved before running from source. We only run
62
+ // `dart pub get` when the package config is missing, so repeated invocations
63
+ // don't re-resolve dependencies on every command.
64
+ const configPath = path.join(cliDir, '.dart_tool', 'package_config.json');
65
+ if (!fs.existsSync(configPath)) {
66
+ const getRes = spawnSync('dart', ['pub', 'get'], { stdio: 'inherit', cwd: cliDir });
67
+ if (getRes.status !== 0) {
68
+ console.error(
69
+ 'flutter-patcher: `dart pub get` failed. Install dependencies or build ' +
70
+ `a prebuilt manually:\n cd ${cliDir} && dart compile exe ` +
71
+ `bin/flutter_patcher.dart -o ${binPath}`,
72
+ );
73
+ process.exit(1);
74
+ }
59
75
  }
76
+ chmodIfNeeded(binPath);
60
77
  run('dart', [sourceEntry, ...process.argv.slice(2)]);
61
78
  } else {
62
79
  console.error(
@@ -31,6 +31,7 @@ export 'src/commands/console.dart';
31
31
 
32
32
  import 'src/commands/build.dart';
33
33
  import 'src/commands/bundle.dart';
34
+ import 'src/runner.dart';
34
35
  import 'src/commands/channel.dart';
35
36
  import 'src/commands/config_command.dart';
36
37
  import 'src/commands/console.dart';
@@ -44,7 +45,7 @@ import 'src/commands/rollback.dart';
44
45
 
45
46
  /// Entry point: build the command runner and dispatch [args].
46
47
  Future<int> run(List<String> args) async {
47
- final runner = CommandRunner<int>(
48
+ final runner = FlutterPatcherRunner(
48
49
  'flutter_patcher',
49
50
  'flutter_patcher CLI — OTA code push for Flutter (hot-updater compatible).',
50
51
  )
@@ -5,6 +5,8 @@ import 'config.dart';
5
5
  import 'pack.dart';
6
6
  import 'ui/ui.dart';
7
7
 
8
+ export 'runner.dart';
9
+
8
10
  /// Run [body], mapping errors to a non-zero exit code with a clean message.
9
11
  Future<int> runGuarded(Future<void> Function() body) async {
10
12
  try {
@@ -1,4 +1,3 @@
1
- import 'package:args/command_runner.dart';
2
1
  import 'package:flutter_patcher_cli/flutter_patcher_cli.dart';
3
2
 
4
3
  import '../ui/ui.dart';
@@ -8,7 +7,7 @@ import '../ui/ui.dart';
8
7
  ///
9
8
  /// Includes every ABI found in the APK so a single bundle installs on all
10
9
  /// device architectures.
11
- class BuildCommand extends Command<int> {
10
+ class BuildCommand extends FlutterPatcherCommand {
12
11
  BuildCommand() {
13
12
  argParser
14
13
  ..addOption(
@@ -1,11 +1,10 @@
1
1
  import 'package:args/args.dart';
2
- import 'package:args/command_runner.dart';
3
2
  import 'package:flutter_patcher_cli/flutter_patcher_cli.dart';
4
3
 
5
4
  import '../ui/ui.dart';
6
5
 
7
6
  /// `flutter_patcher bundle` — manage bundles.
8
- class BundleCommand extends Command<int> {
7
+ class BundleCommand extends FlutterPatcherCommand {
9
8
  BundleCommand({this.config, this.backendOverride});
10
9
 
11
10
  final FlutterPatcherConfig? config;
@@ -28,7 +27,7 @@ class BundleCommand extends Command<int> {
28
27
  });
29
28
  }
30
29
 
31
- class BundleListCommand extends Command<int> {
30
+ class BundleListCommand extends FlutterPatcherCommand {
32
31
  BundleListCommand({this.config, this.backendOverride});
33
32
 
34
33
  final FlutterPatcherConfig? config;
@@ -94,7 +93,7 @@ class BundleListCommand extends Command<int> {
94
93
  });
95
94
  }
96
95
 
97
- class BundleDeleteCommand extends Command<int> {
96
+ class BundleDeleteCommand extends FlutterPatcherCommand {
98
97
  BundleDeleteCommand({this.config, this.backendOverride});
99
98
 
100
99
  final FlutterPatcherConfig? config;
@@ -128,7 +127,7 @@ class BundleDeleteCommand extends Command<int> {
128
127
  });
129
128
  }
130
129
 
131
- class BundlePromoteCommand extends Command<int> {
130
+ class BundlePromoteCommand extends FlutterPatcherCommand {
132
131
  BundlePromoteCommand({this.config, this.backendOverride});
133
132
 
134
133
  final FlutterPatcherConfig? config;
@@ -1,11 +1,10 @@
1
1
  import 'package:args/args.dart';
2
- import 'package:args/command_runner.dart';
3
2
  import 'package:flutter_patcher_cli/flutter_patcher_cli.dart';
4
3
 
5
4
  import '../ui/ui.dart';
6
5
 
7
6
  /// `flutter_patcher channel` — manage channels.
8
- class ChannelCommand extends Command<int> {
7
+ class ChannelCommand extends FlutterPatcherCommand {
9
8
  final FlutterPatcherConfig? config;
10
9
  final Backend? backendOverride;
11
10
 
@@ -32,7 +31,7 @@ class ChannelCommand extends Command<int> {
32
31
  });
33
32
  }
34
33
 
35
- class ChannelListCommand extends Command<int> {
34
+ class ChannelListCommand extends FlutterPatcherCommand {
36
35
  ChannelListCommand({this.config, this.backendOverride});
37
36
 
38
37
  final FlutterPatcherConfig? config;
@@ -62,7 +61,7 @@ class ChannelListCommand extends Command<int> {
62
61
  });
63
62
  }
64
63
 
65
- class ChannelGetCommand extends Command<int> {
64
+ class ChannelGetCommand extends FlutterPatcherCommand {
66
65
  ChannelGetCommand({this.config, this.backendOverride});
67
66
 
68
67
  final FlutterPatcherConfig? config;
@@ -103,7 +102,7 @@ class ChannelGetCommand extends Command<int> {
103
102
  });
104
103
  }
105
104
 
106
- class ChannelSetCommand extends Command<int> {
105
+ class ChannelSetCommand extends FlutterPatcherCommand {
107
106
  ChannelSetCommand({this.config, this.backendOverride});
108
107
 
109
108
  final FlutterPatcherConfig? config;
@@ -2,13 +2,12 @@ import 'dart:convert';
2
2
  import 'dart:io';
3
3
 
4
4
  import 'package:args/args.dart';
5
- import 'package:args/command_runner.dart';
6
5
 
7
6
  import '../cli_base.dart';
8
7
  import '../config.dart';
9
8
 
10
9
  /// `flutter_patcher config` — get/set/list config values.
11
- class ConfigCommand extends Command<int> {
10
+ class ConfigCommand extends FlutterPatcherCommand {
12
11
  ConfigCommand() {
13
12
  addSubcommand(ConfigGetCommand());
14
13
  addSubcommand(ConfigSetCommand());
@@ -45,7 +44,7 @@ void _saveProjectJson(Map<String, dynamic> json) {
45
44
  );
46
45
  }
47
46
 
48
- class ConfigGetCommand extends Command<int> {
47
+ class ConfigGetCommand extends FlutterPatcherCommand {
49
48
  @override
50
49
  String get name => 'get';
51
50
 
@@ -72,7 +71,7 @@ class ConfigGetCommand extends Command<int> {
72
71
  });
73
72
  }
74
73
 
75
- class ConfigSetCommand extends Command<int> {
74
+ class ConfigSetCommand extends FlutterPatcherCommand {
76
75
  @override
77
76
  String get name => 'set';
78
77
 
@@ -98,7 +97,7 @@ class ConfigSetCommand extends Command<int> {
98
97
  });
99
98
  }
100
99
 
101
- class ConfigListCommand extends Command<int> {
100
+ class ConfigListCommand extends FlutterPatcherCommand {
102
101
  @override
103
102
  String get name => 'list';
104
103
 
@@ -1,14 +1,13 @@
1
1
  import 'dart:io';
2
2
 
3
3
  import 'package:args/args.dart';
4
- import 'package:args/command_runner.dart';
5
4
  import 'package:flutter_patcher_cli/flutter_patcher_cli.dart';
6
5
  import 'package:path/path.dart' as p;
7
6
 
8
7
  import '../ui/ui.dart';
9
8
 
10
9
  /// `flutter_patcher console` — open the web console.
11
- class ConsoleCommand extends Command<int> {
10
+ class ConsoleCommand extends FlutterPatcherCommand {
12
11
  @override
13
12
  String get name => 'console';
14
13
 
@@ -1,7 +1,6 @@
1
1
  import 'dart:io';
2
2
 
3
3
  import 'package:args/args.dart';
4
- import 'package:args/command_runner.dart';
5
4
 
6
5
  import '../backend.dart';
7
6
  import '../cli_base.dart';
@@ -11,7 +10,7 @@ import '../ui/ui.dart';
11
10
  import '../util.dart';
12
11
 
13
12
  /// `flutter_patcher deploy` — zip + upload + register a new bundle.
14
- class DeployCommand extends Command<int> {
13
+ class DeployCommand extends FlutterPatcherCommand {
15
14
  DeployCommand({this.config, this.backendOverride});
16
15
 
17
16
  final FlutterPatcherConfig? config;
@@ -1,13 +1,12 @@
1
1
  import 'dart:io';
2
2
 
3
3
  import 'package:args/args.dart';
4
- import 'package:args/command_runner.dart';
5
4
  import 'package:flutter_patcher_cli/flutter_patcher_cli.dart';
6
5
 
7
6
  import '../ui/ui.dart';
8
7
 
9
8
  /// `flutter_patcher doctor` — environment + backend connectivity check.
10
- class DoctorCommand extends Command<int> {
9
+ class DoctorCommand extends FlutterPatcherCommand {
11
10
  DoctorCommand({this.config, this.backendOverride});
12
11
 
13
12
  final FlutterPatcherConfig? config;
@@ -1,13 +1,12 @@
1
1
  import 'dart:io';
2
2
 
3
3
  import 'package:args/args.dart';
4
- import 'package:args/command_runner.dart';
5
4
 
6
5
  import '../cli_base.dart';
7
6
  import '../util.dart';
8
7
 
9
8
  /// `flutter_patcher fingerprint` — compute a build-time fingerprint hash.
10
- class FingerprintCommand extends Command<int> {
9
+ class FingerprintCommand extends FlutterPatcherCommand {
11
10
  @override
12
11
  String get name => 'fingerprint';
13
12
 
@@ -1,7 +1,6 @@
1
1
  import 'dart:io';
2
2
 
3
3
  import 'package:args/args.dart';
4
- import 'package:args/command_runner.dart';
5
4
  import 'package:flutter_patcher_cli/flutter_patcher_cli.dart';
6
5
 
7
6
  import '../ui/ui.dart';
@@ -13,7 +12,7 @@ import '../ui/ui.dart';
13
12
  /// corresponding environment variable so CI runs can be non-interactive. The
14
13
  /// result is saved as `.flutter_patcher.json` (cwd) or the global config when
15
14
  /// `--global` is passed.
16
- class InitCommand extends Command<int> {
15
+ class InitCommand extends FlutterPatcherCommand {
17
16
  InitCommand({this.config, this.backendOverride});
18
17
 
19
18
  final FlutterPatcherConfig? config;
@@ -1,7 +1,6 @@
1
1
  import 'dart:convert';
2
2
 
3
3
  import 'package:args/args.dart';
4
- import 'package:args/command_runner.dart';
5
4
 
6
5
  import '../backend.dart';
7
6
  import '../cli_base.dart';
@@ -10,7 +9,7 @@ import '../sign.dart';
10
9
  import '../ui/ui.dart';
11
10
 
12
11
  /// `flutter_patcher keys` — generate an Ed25519 keypair for bundle signing.
13
- class KeysCommand extends Command<int> {
12
+ class KeysCommand extends FlutterPatcherCommand {
14
13
  KeysCommand({this.config, this.backendOverride});
15
14
 
16
15
  final FlutterPatcherConfig? config;
@@ -1,7 +1,6 @@
1
1
  import 'dart:io';
2
2
 
3
3
  import 'package:args/args.dart';
4
- import 'package:args/command_runner.dart';
5
4
  import 'package:flutter_patcher_cli/flutter_patcher_cli.dart';
6
5
  import 'package:path/path.dart' as p;
7
6
  import 'package:postgres/postgres.dart';
@@ -9,7 +8,7 @@ import 'package:postgres/postgres.dart';
9
8
  import '../ui/ui.dart';
10
9
 
11
10
  /// `flutter_patcher migrate` — run backend SQL migrations.
12
- class MigrateCommand extends Command<int> {
11
+ class MigrateCommand extends FlutterPatcherCommand {
13
12
  @override
14
13
  String get name => 'migrate';
15
14
 
@@ -1,12 +1,11 @@
1
1
  import 'package:args/args.dart';
2
- import 'package:args/command_runner.dart';
3
2
  import 'package:flutter_patcher_cli/flutter_patcher_cli.dart';
4
3
  import 'package:flutter_patcher_core/flutter_patcher_core.dart';
5
4
 
6
5
  import '../ui/ui.dart';
7
6
 
8
7
  /// `flutter_patcher rollback` — roll a channel back to a previous bundle.
9
- class RollbackCommand extends Command<int> {
8
+ class RollbackCommand extends FlutterPatcherCommand {
10
9
  RollbackCommand({this.config, this.backendOverride});
11
10
 
12
11
  final FlutterPatcherConfig? config;
@@ -0,0 +1,72 @@
1
+ import 'dart:io';
2
+
3
+ import 'package:args/command_runner.dart';
4
+ import 'ui/ui.dart';
5
+
6
+ /// Custom [CommandRunner] that renders a clean, colorized top-level help.
7
+ class FlutterPatcherRunner extends CommandRunner<int> {
8
+ FlutterPatcherRunner(String name, String description)
9
+ : super(name, description);
10
+
11
+ @override
12
+ String get usage {
13
+ final names = commands.keys.toList()..sort();
14
+ var maxName = 0;
15
+ for (final n in names) maxName = maxName < n.length ? n.length : maxName;
16
+ final buf = StringBuffer();
17
+ buf.writeln(' ${cyan('▶')} ${cyan(bold(executableName))} '
18
+ '${dim('·')} ${bold(description)}');
19
+ buf.writeln(' ${dim('─' * 60)}');
20
+ buf.writeln('');
21
+ buf.writeln(' ${bold('USAGE')}');
22
+ buf.writeln(' $executableName <command> [arguments]');
23
+ buf.writeln('');
24
+ buf.writeln(' ${bold('COMMANDS')}');
25
+ for (final n in names) {
26
+ final c = commands[n]!;
27
+ buf.writeln(' ${cyan(n.padRight(maxName))} ${dim(c.description)}');
28
+ }
29
+ buf.writeln('');
30
+ buf.writeln(' ${dim('Run "$executableName help <command>" for more about a command.')}');
31
+ return buf.toString();
32
+ }
33
+
34
+ @override
35
+ void printUsage([String? usage]) {
36
+ stdout.writeln(usage ?? this.usage);
37
+ }
38
+ }
39
+
40
+ String _fullName(Command<int> command) {
41
+ final parts = <String>[command.name];
42
+ var p = command.parent;
43
+ while (p != null) {
44
+ parts.insert(0, p.name);
45
+ p = p.parent;
46
+ }
47
+ return parts.join(' ');
48
+ }
49
+
50
+ /// Base class for flutter_patcher commands; renders a clean, colorized
51
+ /// per-command help (used by `flutter_patcher <cmd> --help`).
52
+ abstract class FlutterPatcherCommand extends Command<int> {
53
+ @override
54
+ String get usage {
55
+ final buf = StringBuffer();
56
+ buf.writeln(' ${cyan(bold(name))} ${dim('·')} ${description}');
57
+ buf.writeln('');
58
+ buf.writeln(' ${bold('USAGE')}');
59
+ buf.writeln(' ${_fullName(this)} [arguments]');
60
+ if (argParser.options.isNotEmpty) {
61
+ buf.writeln('');
62
+ buf.writeln(' ${bold('OPTIONS')}');
63
+ buf.writeln(' ${argParser.usage.replaceAll('\n', '\n ')}');
64
+ }
65
+ return buf.toString();
66
+ }
67
+
68
+ @override
69
+ void printUsage([String? usage]) {
70
+ stdout.writeln(usage ?? this.usage);
71
+ }
72
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_nazmiforreal/flutter-ota",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Command-line interface for flutter_patcher — an OTA code-push tool for Flutter, hot-updater compatible.",
5
5
  "bin": {
6
6
  "flutter-patcher": "./bin/flutter-patcher.js"
@@ -34,7 +34,17 @@ const binDir = path.join(pkgDir, 'bin');
34
34
  const target = path.join(binDir, `flutter-patcher-${platformName}-${archName}${ext}`);
35
35
  const cliDir = path.join(pkgDir, 'dart-src', 'packages', 'cli-tools');
36
36
 
37
+ function chmod(pathname) {
38
+ try {
39
+ const st = fs.statSync(pathname);
40
+ if (!(st.mode & 0o100)) fs.chmodSync(pathname, st.mode | 0o755);
41
+ } catch (_) {
42
+ /* non-fatal */
43
+ }
44
+ }
45
+
37
46
  if (fs.existsSync(target)) {
47
+ chmod(target);
38
48
  console.log(`flutter-patcher: prebuilt binary present (${platformName}-${archName}), skipping build.`);
39
49
  process.exit(0);
40
50
  }
@@ -57,7 +67,7 @@ if (!fs.existsSync(path.join(cliDir, 'pubspec.yaml'))) {
57
67
  console.log('flutter-patcher: resolving Dart dependencies (dart pub get)...');
58
68
  const getRes = spawnSync('dart', ['pub', 'get'], { stdio: 'inherit', cwd: cliDir });
59
69
  if (getRes.status !== 0) {
60
- console.warn(
70
+ console.error(
61
71
  'flutter-patcher: `dart pub get` failed (check your network / Dart version). ' +
62
72
  `To build manually:\n cd ${cliDir} && dart compile exe bin/flutter_patcher.dart ` +
63
73
  `-o ${target}`,
@@ -65,17 +75,18 @@ if (getRes.status !== 0) {
65
75
  process.exit(0);
66
76
  }
67
77
 
68
- console.log('flutter-patcher: building native binary with `dart compile exe`...');
78
+ console.log(`flutter-patcher: building native binary (${platformName}-${archName})...`);
69
79
  const res = spawnSync(
70
80
  'dart',
71
81
  ['compile', 'exe', 'bin/flutter_patcher.dart', '-o', target],
72
82
  { stdio: 'inherit', cwd: cliDir },
73
83
  );
74
84
  if (res.status !== 0) {
75
- console.warn(
85
+ console.error(
76
86
  'flutter-patcher: build failed. To build manually:\n cd ' +
77
87
  `${cliDir} && dart compile exe bin/flutter_patcher.dart -o ${target}`,
78
88
  );
79
89
  process.exit(0);
80
90
  }
91
+ chmod(target);
81
92
  console.log(`flutter-patcher: built ${target}`);