From 8983dfa5367649092d2a9c34176dee3d6b341f2a Mon Sep 17 00:00:00 2001 From: Leo Farias Date: Thu, 7 Nov 2019 19:27:05 -0500 Subject: [PATCH] Improved exception handling and error messages --- CHANGELOG.md | 6 + coverage/lcov.info | 334 +++++++++++++++++++---------------- coverage_badge.svg | 6 +- lib/commands/config.dart | 2 +- lib/commands/install.dart | 29 ++- lib/commands/list.dart | 25 ++- lib/commands/remove.dart | 2 +- lib/commands/runner.dart | 20 +++ lib/commands/use.dart | 20 ++- lib/exceptions.dart | 21 +++ lib/fvm.dart | 17 +- lib/utils/flutter_tools.dart | 2 +- lib/utils/helpers.dart | 4 +- pubspec.yaml | 17 +- test/fvm_test.dart | 13 ++ 15 files changed, 294 insertions(+), 224 deletions(-) create mode 100644 lib/commands/runner.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index 01edf203..594c4a87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.6.6 + +- Better Flutter command compatibility +- Improved error logging and --verbose behavior +- Friendlier error messages + ## 0.6.5 - Better Error handling and friendlier error message diff --git a/coverage/lcov.info b/coverage/lcov.info index 70f478cd..359903d8 100644 --- a/coverage/lcov.info +++ b/coverage/lcov.info @@ -11,20 +11,21 @@ DA:30,2 DA:32,3 DA:33,0 DA:34,0 -DA:39,1 -DA:40,2 -DA:42,0 -DA:43,0 -DA:44,0 -DA:52,1 -DA:54,1 -DA:60,1 -DA:63,3 -DA:65,2 -DA:67,4 -DA:71,1 -DA:73,2 -LF:25 +DA:35,0 +DA:40,1 +DA:41,2 +DA:43,7 +DA:44,1 +DA:45,2 +DA:53,1 +DA:55,1 +DA:61,1 +DA:64,3 +DA:66,2 +DA:68,0 +DA:71,0 +DA:72,0 +LF:26 LH:20 end_of_record SF:lib/constants.dart @@ -52,18 +53,24 @@ LF:20 LH:14 end_of_record SF:lib/exceptions.dart -DA:7,0 -DA:9,0 -DA:18,1 -DA:20,0 -DA:29,1 -DA:31,0 +DA:4,0 +DA:5,0 +DA:6,0 +DA:16,0 +DA:18,0 +DA:27,1 +DA:29,0 +DA:38,1 DA:40,0 -DA:42,0 -DA:51,1 -DA:53,0 -LF:10 -LH:3 +DA:49,0 +DA:51,0 +DA:60,1 +DA:62,0 +DA:70,1 +DA:72,0 +DA:73,0 +LF:16 +LH:4 end_of_record SF:lib/utils/logger.dart DA:4,3 @@ -122,6 +129,31 @@ DA:106,1 LF:46 LH:39 end_of_record +SF:lib/commands/install.dart +DA:16,1 +DA:18,1 +DA:19,2 +DA:20,3 +DA:21,1 +DA:23,4 +DA:24,1 +DA:26,4 +DA:28,2 +DA:30,2 +DA:32,1 +LF:11 +LH:11 +end_of_record +SF:lib/commands/runner.dart +DA:6,1 +DA:7,1 +DA:10,2 +DA:11,1 +DA:13,1 +DA:15,1 +LF:6 +LH:6 +end_of_record SF:lib/commands/config.dart DA:8,1 DA:9,0 @@ -134,10 +166,9 @@ DA:19,2 DA:21,2 DA:24,2 DA:25,2 -DA:26,2 +DA:26,1 DA:27,3 -DA:29,0 -LF:14 +LF:13 LH:12 end_of_record SF:lib/commands/flutter.dart @@ -145,47 +176,35 @@ DA:16,1 DA:17,1 DA:18,1 DA:20,1 -DA:22,1 -DA:24,1 -DA:29,1 -DA:30,2 -DA:32,0 +DA:26,1 +DA:28,1 +DA:30,1 DA:33,1 -DA:37,0 -DA:39,0 -DA:40,0 +DA:34,1 +DA:36,1 DA:41,0 -LF:14 -LH:9 -end_of_record -SF:lib/commands/install.dart -DA:15,1 -DA:17,1 -DA:19,2 -DA:20,4 -DA:21,1 -DA:23,4 -DA:25,2 -DA:27,2 -DA:29,1 -DA:30,0 -LF:10 -LH:9 +DA:42,0 +DA:44,0 +DA:45,0 +DA:49,0 +DA:51,0 +DA:52,0 +DA:53,0 +LF:18 +LH:10 end_of_record SF:lib/commands/list.dart DA:15,1 DA:17,1 -DA:19,2 -DA:20,2 -DA:21,0 +DA:18,2 +DA:20,1 DA:24,1 DA:25,2 -DA:26,0 +DA:26,1 DA:28,3 DA:31,2 -DA:32,0 -LF:11 -LH:8 +LF:9 +LH:9 end_of_record SF:lib/commands/remove.dart DA:14,1 @@ -204,122 +223,125 @@ LF:12 LH:10 end_of_record SF:lib/commands/use.dart -DA:14,1 -DA:16,1 -DA:17,3 -DA:19,2 -DA:22,0 -DA:25,3 -DA:27,2 -DA:28,1 -DA:29,0 -LF:9 -LH:7 +DA:15,1 +DA:17,1 +DA:18,3 +DA:19,0 +DA:20,0 +DA:22,3 +DA:24,2 +DA:27,0 +DA:28,0 +DA:31,3 +DA:33,2 +DA:34,4 +DA:35,1 +LF:13 +LH:9 end_of_record SF:lib/utils/flutter_tools.dart DA:10,0 DA:12,0 -DA:14,0 -DA:15,0 DA:16,0 -DA:21,1 -DA:22,4 -DA:24,1 -DA:25,2 -DA:29,2 +DA:18,0 +DA:19,0 +DA:21,0 +DA:22,0 +DA:29,1 +DA:30,4 +DA:32,1 DA:33,2 -DA:35,2 -DA:36,1 -DA:37,1 -DA:39,2 -DA:40,0 +DA:37,2 +DA:41,2 +DA:43,2 +DA:44,1 DA:45,1 -DA:47,3 +DA:47,2 DA:48,0 -DA:49,0 -DA:56,1 -DA:57,4 -DA:59,2 -DA:60,2 -DA:64,2 +DA:53,1 +DA:55,3 +DA:56,0 +DA:57,0 +DA:64,1 +DA:65,4 +DA:67,2 DA:68,2 -DA:70,2 -DA:71,2 -DA:72,1 -DA:74,2 -DA:75,0 -DA:87,1 -DA:88,4 -DA:89,2 -DA:90,0 -DA:92,3 +DA:72,2 +DA:76,2 +DA:78,2 +DA:79,2 +DA:80,1 +DA:82,2 +DA:83,0 DA:95,1 -DA:96,3 -DA:99,3 +DA:96,4 +DA:97,2 +DA:98,0 DA:100,3 -DA:104,2 -DA:105,0 -DA:108,2 -DA:113,1 -DA:115,4 -DA:117,2 -DA:118,0 -DA:121,2 -DA:123,1 -DA:124,2 -DA:125,1 -DA:127,2 -DA:128,2 -DA:136,1 -DA:137,4 -DA:138,2 -DA:139,2 +DA:103,1 +DA:104,3 +DA:107,3 +DA:108,3 +DA:112,2 +DA:113,0 +DA:116,2 +DA:121,1 +DA:123,4 +DA:125,2 +DA:126,0 +DA:129,2 +DA:131,1 +DA:132,2 +DA:133,1 +DA:135,2 +DA:136,2 DA:144,1 DA:145,4 -DA:146,3 -DA:147,3 -DA:149,2 -DA:154,4 -DA:155,2 -DA:156,1 +DA:146,2 +DA:147,2 +DA:152,1 +DA:153,4 +DA:154,3 +DA:155,3 DA:157,2 -DA:165,1 -DA:168,3 -DA:169,0 -DA:172,4 -DA:174,1 -DA:175,2 -DA:176,4 -DA:178,3 +DA:162,4 +DA:163,2 +DA:164,1 +DA:165,2 +DA:173,1 +DA:176,3 +DA:177,0 +DA:180,4 DA:182,1 -DA:184,0 +DA:183,2 +DA:184,4 +DA:186,3 DA:190,1 -DA:192,4 -DA:193,3 -LF:79 +DA:192,0 +DA:193,0 +DA:198,1 +DA:200,4 +DA:201,3 +LF:82 LH:65 end_of_record SF:lib/fvm.dart -DA:15,1 DA:16,1 +DA:17,1 DA:19,2 -DA:20,1 -DA:22,1 -DA:24,1 -DA:28,2 -DA:29,2 -DA:30,2 -DA:31,2 -DA:32,2 -DA:33,2 -DA:35,4 -DA:36,1 -DA:37,0 -DA:39,5 -DA:40,1 -DA:41,0 -DA:46,0 -DA:47,2 -LF:20 -LH:17 +DA:20,2 +DA:21,2 +DA:22,2 +DA:23,2 +DA:24,2 +DA:26,3 +DA:27,0 +DA:28,0 +DA:30,0 +DA:31,0 +DA:32,0 +DA:35,0 +DA:36,2 +LF:16 +LH:10 end_of_record diff --git a/coverage_badge.svg b/coverage_badge.svg index 1e1fb6d0..a3f566f9 100644 --- a/coverage_badge.svg +++ b/coverage_badge.svg @@ -8,13 +8,13 @@ - + coverage coverage - 79% - 79% + 76% + 76% diff --git a/lib/commands/config.dart b/lib/commands/config.dart index cb97f51f..c1d67b34 100644 --- a/lib/commands/config.dart +++ b/lib/commands/config.dart @@ -26,7 +26,7 @@ class ConfigCommand extends Command { if (configOptions.isNotEmpty) { logger.stdout(green.wrap(configOptions)); } else { - logger.stdout(yellow.wrap('No Configurations Have Been Set')); + throw 'No configuration has been set'; } } } diff --git a/lib/commands/install.dart b/lib/commands/install.dart index ba5f3ead..c9d30000 100644 --- a/lib/commands/install.dart +++ b/lib/commands/install.dart @@ -1,4 +1,5 @@ import 'package:args/command_runner.dart'; +import 'package:fvm/exceptions.dart'; import 'package:fvm/utils/flutter_tools.dart'; import 'package:fvm/utils/helpers.dart'; import 'package:fvm/utils/logger.dart'; @@ -15,23 +16,19 @@ class InstallCommand extends Command { InstallCommand(); void run() async { - try { - await checkIfGitExists(); - if (argResults.arguments.isEmpty) { - throw Exception('Need to provide a channel or a version'); - } - final version = argResults.arguments[0].toLowerCase(); - final isChannel = isValidFlutterChannel(version); + await checkIfGitExists(); + if (argResults.arguments.isEmpty) { + throw ExceptionMissingChannelVersion(); + } + final version = argResults.arguments[0].toLowerCase(); + final isChannel = isValidFlutterChannel(version); - final progress = logger.progress(green.wrap('Downloading $version')); - if (isChannel) { - await flutterChannelClone(version); - } else { - await flutterVersionClone(version); - } - finishProgress(progress); - } on Exception { - rethrow; + final progress = logger.progress(green.wrap('Downloading $version')); + if (isChannel) { + await flutterChannelClone(version); + } else { + await flutterVersionClone(version); } + finishProgress(progress); } } diff --git a/lib/commands/list.dart b/lib/commands/list.dart index 3a13c8bd..84e4cf66 100644 --- a/lib/commands/list.dart +++ b/lib/commands/list.dart @@ -15,22 +15,19 @@ class ListCommand extends Command { ListCommand(); Future run() async { - try { - final choices = await flutterListInstalledSdks(); - if (choices.isEmpty) { - logger.stdout('No SDKs have been installed yet.'); - } + final choices = await flutterListInstalledSdks(); - void printVersions(String version) async { - if (await isCurrentVersion(version)) { - version = "$version(current)"; - } - logger.stdout(green.wrap(version)); - } + if (choices.isEmpty) { + throw 'No SDKs have been installed yet.'; + } - choices.forEach(await printVersions); - } on Exception { - rethrow; + void printVersions(String version) async { + if (await isCurrentVersion(version)) { + version = "$version (current)"; + } + logger.stdout(green.wrap(version)); } + + choices.forEach(await printVersions); } } diff --git a/lib/commands/remove.dart b/lib/commands/remove.dart index e3d6a783..a82f8233 100644 --- a/lib/commands/remove.dart +++ b/lib/commands/remove.dart @@ -27,7 +27,7 @@ class RemoveCommand extends Command { final isValidInstall = await isValidFlutterInstall(version); if (!isValidInstall) { - throw Exception('Flutter SDK: $version is not installed'); + throw 'Flutter SDK: $version is not installed'; } final progress = logger.progress('Removing $version'); diff --git a/lib/commands/runner.dart b/lib/commands/runner.dart new file mode 100644 index 00000000..9327ce66 --- /dev/null +++ b/lib/commands/runner.dart @@ -0,0 +1,20 @@ +import 'package:args/command_runner.dart'; +import 'package:cli_util/cli_logging.dart'; +import 'package:fvm/utils/logger.dart'; + +/// Builds FVM Runner +CommandRunner buildRunner() { + final runner = CommandRunner('fvm', + 'Flutter Version Management: A cli to manage Flutter SDK versions.'); + + runner.argParser.addFlag('verbose', + help: 'Print verbose output.', negatable: false, callback: (verbose) { + if (verbose) { + logger = Logger.verbose(); + } else { + logger = Logger.standard(); + } + }); + + return runner; +} diff --git a/lib/commands/use.dart b/lib/commands/use.dart index db3cd668..c79e0ac6 100644 --- a/lib/commands/use.dart +++ b/lib/commands/use.dart @@ -2,6 +2,7 @@ import 'package:args/command_runner.dart'; import 'package:fvm/utils/flutter_tools.dart'; import 'package:fvm/utils/helpers.dart'; import 'package:fvm/utils/logger.dart'; +import 'package:io/ansi.dart'; /// Use an installed SDK version class UseCommand extends Command { @@ -14,20 +15,23 @@ class UseCommand extends Command { UseCommand(); Future run() async { + if (argResults.arguments.isEmpty) { + final instruction = yellow.wrap('fvm use '); + throw 'Please provide a version. $instruction'; + } final version = argResults.arguments[0]; final isValidInstall = await isValidFlutterInstall(version); if (!isValidInstall) { - throw Exception('Flutter SDK: $version is not installed'); + final instruction = yellow.wrap('fvm install first.'); + throw 'Flutter $version is not installed. Please run $instruction'; } - final progress = logger.progress('Using $version'); - try { - await linkProjectFlutterDir(version); - finishProgress(progress); - } on Exception { - rethrow; - } + final progress = logger.progress('Activating $version'); + + await linkProjectFlutterDir(version); + logger.stdout(green.wrap('$version is active')); + finishProgress(progress); } } diff --git a/lib/exceptions.dart b/lib/exceptions.dart index cb18eb37..9a591baa 100644 --- a/lib/exceptions.dart +++ b/lib/exceptions.dart @@ -1,3 +1,12 @@ +import 'package:fvm/utils/logger.dart'; + +/// Logs error for verbose output +dynamic logVerboseError(Exception err) { + if (logger.isVerbose) { + logger.stderr(err?.toString()); + } +} + /// Exception cloning channel class ExceptionCouldNotClone implements Exception { /// Version @@ -52,3 +61,15 @@ class ExceptionCouldNotReadConfig implements Exception { String toString() => 'ExceptionCouldNotReadConfig: $message'; } + +/// Provide a channel or version +class ExceptionMissingChannelVersion implements Exception { + final _message = 'Need to provide a channel or a version.'; + + /// Constructor + ExceptionMissingChannelVersion(); + + String toString() { + return _message; + } +} diff --git a/lib/fvm.dart b/lib/fvm.dart index cbd6e973..1ceb3e40 100644 --- a/lib/fvm.dart +++ b/lib/fvm.dart @@ -5,6 +5,7 @@ import 'package:fvm/commands/flutter.dart'; import 'package:fvm/commands/install.dart'; import 'package:fvm/commands/list.dart'; import 'package:fvm/commands/remove.dart'; +import 'package:fvm/commands/runner.dart'; import 'package:fvm/commands/use.dart'; import 'package:fvm/utils/logger.dart'; import 'package:cli_util/cli_logging.dart'; @@ -13,17 +14,7 @@ import 'package:io/ansi.dart'; /// Runs FVM Future fvmRunner(List args) async { - final runner = CommandRunner('fvm', - 'Flutter Version Management: A cli to manage Flutter SDK versions.'); - - runner.argParser.addFlag('verbose', - help: 'Print verbose output.', negatable: false, callback: (verbose) { - if (verbose) { - logger = Logger.verbose(); - } else { - logger = Logger.standard(); - } - }); + final runner = buildRunner(); runner..addCommand(InstallCommand()); runner..addCommand(ListCommand()); @@ -38,10 +29,8 @@ Future fvmRunner(List args) async { } else { logger.stderr("⚠️ ${yellow.wrap(exc?.message)}"); if (args.contains('--verbose')) { - logger.stderr(st); + print(st); } - - throw exc; } exitCode = 1; }).whenComplete(() {}); diff --git a/lib/utils/flutter_tools.dart b/lib/utils/flutter_tools.dart index 849893a1..798c513c 100644 --- a/lib/utils/flutter_tools.dart +++ b/lib/utils/flutter_tools.dart @@ -190,7 +190,7 @@ Future> flutterListInstalledSdks() async { installedVersions.sort(); return installedVersions; } on Exception { - rethrow; + throw Exception('Could not list installed sdks'); } } diff --git a/lib/utils/helpers.dart b/lib/utils/helpers.dart index f622b3cf..a8383faa 100644 --- a/lib/utils/helpers.dart +++ b/lib/utils/helpers.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:fvm/constants.dart'; +import 'package:fvm/exceptions.dart'; import 'package:path/path.dart' as path; import 'package:fvm/utils/flutter_tools.dart'; @@ -30,7 +31,8 @@ Future linkDir( } await source.create(target.path); } on Exception catch (err) { - throw Exception(['Could not link ${target.path}:', err]); + logVerboseError(err); + throw Exception('Sorry could not link ${target.path}'); } } diff --git a/pubspec.yaml b/pubspec.yaml index 6a769726..a256cfef 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,23 +1,22 @@ name: fvm description: A simple cli to manage Flutter SDK versions per project. -version: 0.6.5 +version: 0.6.6 homepage: https://github.com/leoafarias/fvm author: Leo Farias environment: - sdk: '>=2.5.0 <3.0.0' + sdk: ">=2.5.0 <3.0.0" executables: fvm: main dependencies: - args: ^1.5.2 - cli_util: ^0.1.3+2 - # file_utils: ^0.1.3 - console: ^3.1.0 - io: ^0.3.3 - path: ^1.6.4 - + args: ^1.5.2 + cli_util: ^0.1.3+2 + # file_utils: ^0.1.3 + console: ^3.1.0 + io: ^0.3.3 + path: ^1.6.4 dev_dependencies: pedantic: ^1.8.0 diff --git a/test/fvm_test.dart b/test/fvm_test.dart index 88d43265..e33dfed4 100644 --- a/test/fvm_test.dart +++ b/test/fvm_test.dart @@ -1,4 +1,7 @@ @Timeout(Duration(minutes: 5)) +import 'package:fvm/commands/install.dart'; +import 'package:fvm/commands/runner.dart'; +import 'package:fvm/exceptions.dart'; import 'package:fvm/fvm.dart'; import 'package:test/test.dart'; import 'package:path/path.dart' as path; @@ -20,6 +23,16 @@ void main() { await fvmTearDownAll(); }); group('Channel Flow', () { + test('Install without version', () async { + final args = ['install']; + try { + final runner = buildRunner(); + runner.addCommand(InstallCommand()); + await runner.run(args); + } on Exception catch (e) { + expect(e is ExceptionMissingChannelVersion, true); + } + }); test('Install Channel', () async { try { await fvmRunner(['install', channel, '--verbose']);