From 46820b0fed760d861c98d07024c069dffe46bf66 Mon Sep 17 00:00:00 2001 From: openhands Date: Mon, 2 Nov 2026 23:07:23 +0000 Subject: [PATCH 1/2] fix(cli): add --help/-h flag and print usage on no args The CLI rejected --help with "Could not find an option named \"--help\"". Add a --help/-h flag that prints the full usage, print usage instead of a bare one-liner when no arguments are given, and print usage to stderr alongside the error when parsing fails. Also add regression tests and bump the version to 3.9.8. Co-authored-by: openhands --- README.md | 3 +++ VERSION | 2 +- core/bin/openrom.dart | 32 ++++++++++++++++++---- core/pubspec.yaml | 2 +- core/test/cli_help_test.dart | 49 ++++++++++++++++++++++++++++++++++ docs/DEVELOPER_ONBOARDING.md | 6 ++--- gui/lib/utils/app_version.dart | 4 +-- gui/pubspec.lock | 2 +- gui/pubspec.yaml | 4 +-- gui/test/app_version_test.dart | 2 +- 10 files changed, 90 insertions(+), 16 deletions(-) create mode 100644 core/test/cli_help_test.dart diff --git a/README.md b/README.md index fa5caca..886ec3a 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,9 @@ not supported and fail fast. ## 💻 CLI Usage ```bash +# Show all options +openrom-core --help + # Detect file format and platform openrom-core --detect game.iso diff --git a/VERSION b/VERSION index 1ac154b..4953086 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.9.7 \ No newline at end of file +3.9.8 \ No newline at end of file diff --git a/core/bin/openrom.dart b/core/bin/openrom.dart index 1828885..4f668af 100644 --- a/core/bin/openrom.dart +++ b/core/bin/openrom.dart @@ -185,11 +185,26 @@ ArgParser buildParser() { negatable: false, help: 'suppress per-job log output', ) + ..addFlag( + 'help', + abbr: 'h', + negatable: false, + help: 'show this help message', + ) ..addFlag('version', abbr: 'v', negatable: false, help: 'show version'); return parser; } +void printUsage(ArgParser parser, {bool toStderr = false}) { + final out = toStderr ? stderr : stdout; + out.writeln('OpenROM CLI — Universal ROM Compression Suite'); + out.writeln(); + out.writeln('Usage: openrom-core [options]'); + out.writeln(); + out.writeln(parser.usage); +} + Future main(List args) async { // The Dart VM ignores an `int` returned from `main` (both JIT and AOT), so // propagate the exit code explicitly. @@ -197,23 +212,30 @@ Future main(List args) async { } Future _runCli(List args) async { + final parser = buildParser(); + if (args.isEmpty) { - print('OpenROM CLI — Universal ROM Toolkit\nUsage: openrom [options]'); + printUsage(parser); return 0; } - // Auto-load installed plugins - await PluginManager.instance.loadInstalledPlugins(); - - final parser = buildParser(); final ArgResults results; try { results = parser.parse(args); } catch (e) { stderr.writeln('Error parsing arguments: $e'); + printUsage(parser, toStderr: true); return 2; } + if (results['help'] == true) { + printUsage(parser); + return 0; + } + + // Auto-load installed plugins + await PluginManager.instance.loadInstalledPlugins(); + if (results['version'] == true) { final version = readAppVersion(); print(version == 'unknown' ? 'OpenROM' : 'OpenROM v$version'); diff --git a/core/pubspec.yaml b/core/pubspec.yaml index bf3b19e..55e69b1 100644 --- a/core/pubspec.yaml +++ b/core/pubspec.yaml @@ -1,6 +1,6 @@ name: openrom_core description: OpenROM Pure Dart Backend Core & Toolkit Library -version: 3.9.7 +version: 3.9.8 publish_to: 'none' environment: diff --git a/core/test/cli_help_test.dart b/core/test/cli_help_test.dart new file mode 100644 index 0000000..bfd2bf8 --- /dev/null +++ b/core/test/cli_help_test.dart @@ -0,0 +1,49 @@ +import 'dart:io'; + +import 'package:test/test.dart'; + +/// Runs the real CLI entrypoint and captures its output. +ProcessResult _runCli(List args) { + return Process.runSync( + Platform.resolvedExecutable, + ['bin/openrom.dart', ...args], + ); +} + +void main() { + group('CLI --help', () { + test('--help prints usage and exits 0', () { + final r = _runCli(['--help']); + expect(r.exitCode, 0); + final out = r.stdout as String; + expect(out, contains('Usage: openrom-core [options]')); + expect(out, contains('--help')); + expect(out, contains('--input')); + }); + + test('-h prints usage and exits 0', () { + final r = _runCli(['-h']); + expect(r.exitCode, 0); + expect(r.stdout as String, contains('Usage: openrom-core [options]')); + }); + + test('no arguments prints usage and exits 0', () { + final r = _runCli([]); + expect(r.exitCode, 0); + expect(r.stdout as String, contains('Usage: openrom-core [options]')); + }); + + test('unknown option exits 2 with an error and usage on stderr', () { + final r = _runCli(['--not-a-real-option']); + expect(r.exitCode, 2); + expect(r.stderr as String, contains('Error parsing arguments')); + expect(r.stderr as String, contains('Usage: openrom-core [options]')); + }); + + test('--version still exits 0', () { + final r = _runCli(['--version']); + expect(r.exitCode, 0); + expect(r.stdout as String, startsWith('OpenROM')); + }); + }); +} diff --git a/docs/DEVELOPER_ONBOARDING.md b/docs/DEVELOPER_ONBOARDING.md index 040112f..1c12de6 100644 --- a/docs/DEVELOPER_ONBOARDING.md +++ b/docs/DEVELOPER_ONBOARDING.md @@ -4,8 +4,8 @@ > wrapped around a pure-Dart backend engine (`openrom-core`) that orchestrates > native third-party tools (`chdman`, `maxcso`, `xdelta3`, …). -Version at time of writing: **3.9.7** (`VERSION`, `core/pubspec.yaml`, -`gui/pubspec.yaml` = `3.9.7+1`). +Version at time of writing: **3.9.8** (`VERSION`, `core/pubspec.yaml`, +`gui/pubspec.yaml` = `3.9.8+1`). --- @@ -528,7 +528,7 @@ At runtime, `main.dart` queries the native library directory over a `config.getToolPath()` returns `lib.so` inside that dir — this is the only platform where tools are shared libraries rather than executables. -Android is **omitted from the v3.9.7 release**. The `build-android` job is guarded +Android is **omitted from the v3.9.8 release**. The `build-android` job is guarded so the `release: published` trigger no longer fires it; re-enable by dispatching `Android.yml` manually or setting the repository variable `ENABLE_ANDROID_RELEASE=true`. diff --git a/gui/lib/utils/app_version.dart b/gui/lib/utils/app_version.dart index a91a161..c567cd0 100644 --- a/gui/lib/utils/app_version.dart +++ b/gui/lib/utils/app_version.dart @@ -5,13 +5,13 @@ import 'package:openrom_core/openrom_core.dart'; class AppVersion { /// Default fallback version matching current release tag. - static const String fallback = '3.9.7'; + static const String fallback = '3.9.8'; /// Returns the resolved app version. /// Priority: /// 1. Compile-time environment variable (--dart-define=APP_VERSION=x.y.z) /// 2. Version file read via `readAppVersion()` from `openrom_core` - /// 3. Fallback string ('3.9.7') + /// 3. Fallback string ('3.9.8') static String get current { const definedVersion = String.fromEnvironment('APP_VERSION'); if (definedVersion.isNotEmpty) { diff --git a/gui/pubspec.lock b/gui/pubspec.lock index ad8822a..df13d85 100644 --- a/gui/pubspec.lock +++ b/gui/pubspec.lock @@ -331,7 +331,7 @@ packages: path: "../core" relative: true source: path - version: "3.9.7" + version: "3.9.8" package_config: dependency: transitive description: diff --git a/gui/pubspec.yaml b/gui/pubspec.yaml index 0edea34..2065f4d 100644 --- a/gui/pubspec.yaml +++ b/gui/pubspec.yaml @@ -1,7 +1,7 @@ name: gui description: OpenROM — Universal ROM Compression Suite Desktop App publish_to: 'none' -version: 3.9.7+1 +version: 3.9.8+1 environment: sdk: '>=3.0.0 <4.0.0' @@ -23,7 +23,7 @@ dependencies: path_provider: ^2.0.0 openrom_core: path: ../core - version: 3.9.7 + version: 3.9.8 dev_dependencies: flutter_test: diff --git a/gui/test/app_version_test.dart b/gui/test/app_version_test.dart index 744aa23..466ad42 100644 --- a/gui/test/app_version_test.dart +++ b/gui/test/app_version_test.dart @@ -9,7 +9,7 @@ void main() { test('AppVersion.current returns dynamic current version string', () { final version = AppVersion.current; expect(version, isNotEmpty); - expect(version, equals('3.9.7')); + expect(version, equals('3.9.8')); }); }); } From 33c4006d8b961593acdf8ab4c6791af2fe835dfc Mon Sep 17 00:00:00 2001 From: openhands Date: Mon, 2 Nov 2026 23:12:14 +0000 Subject: [PATCH 2/2] fix(cli): exit --help/--version before loading plugins loadInstalledPlugins() can log to stdout, which polluted --version output when a plugin was installed. Handle both early-exit flags before any side effects and tighten the regression test accordingly. Co-authored-by: openhands --- core/bin/openrom.dart | 8 +++++--- core/test/cli_help_test.dart | 8 ++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/core/bin/openrom.dart b/core/bin/openrom.dart index 4f668af..99a2af3 100644 --- a/core/bin/openrom.dart +++ b/core/bin/openrom.dart @@ -228,20 +228,22 @@ Future _runCli(List args) async { return 2; } + // `--help` and `--version` exit before any side effects (e.g. loading + // installed plugins) so their output stays clean. if (results['help'] == true) { printUsage(parser); return 0; } - // Auto-load installed plugins - await PluginManager.instance.loadInstalledPlugins(); - if (results['version'] == true) { final version = readAppVersion(); print(version == 'unknown' ? 'OpenROM' : 'OpenROM v$version'); return 0; } + // Auto-load installed plugins + await PluginManager.instance.loadInstalledPlugins(); + final isJson = results['json'] == true; if (results['install-plugin'] != null) { diff --git a/core/test/cli_help_test.dart b/core/test/cli_help_test.dart index bfd2bf8..2aa0057 100644 --- a/core/test/cli_help_test.dart +++ b/core/test/cli_help_test.dart @@ -40,10 +40,14 @@ void main() { expect(r.stderr as String, contains('Usage: openrom-core [options]')); }); - test('--version still exits 0', () { + test('--version exits 0 and prints only the version line', () { final r = _runCli(['--version']); expect(r.exitCode, 0); - expect(r.stdout as String, startsWith('OpenROM')); + // Plugin loading must not run for `--version`, so nothing may precede it. + expect( + (r.stdout as String).trim(), + matches(RegExp(r'^OpenROM( v[0-9][0-9.]*)?$')), + ); }); }); }