Refactor flutter command exit code - part 1 (#6803) * convert flutter commands to use ToolExit for non-zero exit code * add convenience method throwToolExit * print ToolExit message iff not null
diff --git a/packages/flutter_tools/lib/executable.dart b/packages/flutter_tools/lib/executable.dart index ed7f6c0..b0dded2 100644 --- a/packages/flutter_tools/lib/executable.dart +++ b/packages/flutter_tools/lib/executable.dart
@@ -104,7 +104,8 @@ // Argument error exit code. _exit(64); } else if (error is ToolExit) { - stderr.writeln(error.message); + if (error.message != null) + stderr.writeln(error.message); if (verbose) { stderr.writeln(); stderr.writeln(chain.terse.toString());
diff --git a/packages/flutter_tools/lib/src/base/common.dart b/packages/flutter_tools/lib/src/base/common.dart index 4ed265b..f4f7c5b 100644 --- a/packages/flutter_tools/lib/src/base/common.dart +++ b/packages/flutter_tools/lib/src/base/common.dart
@@ -23,6 +23,14 @@ } String _homeDirPath; +/// Throw a specialized exception for expected situations +/// where the tool should exit with a clear message to the user +/// and no stack trace unless the --verbose option is specified. +/// For example: network errors +void throwToolExit(String message, { int exitCode }) { + throw new ToolExit(message, exitCode: exitCode); +} + /// Specialized exception for expected situations /// where the tool should exit with a clear message to the user /// and no stack trace unless the --verbose option is specified.
diff --git a/packages/flutter_tools/lib/src/base/net.dart b/packages/flutter_tools/lib/src/base/net.dart index 60dc35c..7734bde 100644 --- a/packages/flutter_tools/lib/src/base/net.dart +++ b/packages/flutter_tools/lib/src/base/net.dart
@@ -20,7 +20,7 @@ printTrace('Received response statusCode=${response.statusCode}'); if (response.statusCode != 200) { - throw new ToolExit( + throwToolExit( 'Download failed: $url\n' ' because (${response.statusCode}) ${response.reasonPhrase}', exitCode: kNetworkProblemExitCode,
diff --git a/packages/flutter_tools/lib/src/commands/analyze_continuously.dart b/packages/flutter_tools/lib/src/commands/analyze_continuously.dart index 0e4cb4c..dcd73cb 100644 --- a/packages/flutter_tools/lib/src/commands/analyze_continuously.dart +++ b/packages/flutter_tools/lib/src/commands/analyze_continuously.dart
@@ -9,6 +9,7 @@ import 'package:args/args.dart'; import 'package:path/path.dart' as path; +import '../base/common.dart'; import '../base/logger.dart'; import '../base/utils.dart'; import '../cache.dart'; @@ -53,7 +54,10 @@ await server.start(); final int exitCode = await server.onExit; - printStatus('Analysis server exited with code $exitCode.'); + String message = 'Analysis server exited with code $exitCode.'; + if (exitCode != 0) + throwToolExit(message, exitCode: exitCode); + printStatus(message); return 0; }
diff --git a/packages/flutter_tools/lib/src/commands/analyze_once.dart b/packages/flutter_tools/lib/src/commands/analyze_once.dart index 006ecd9..b7b8b61 100644 --- a/packages/flutter_tools/lib/src/commands/analyze_once.dart +++ b/packages/flutter_tools/lib/src/commands/analyze_once.dart
@@ -10,6 +10,7 @@ import 'package:path/path.dart' as path; import 'package:yaml/yaml.dart' as yaml; +import '../base/common.dart'; import '../cache.dart'; import '../dart/analysis.dart'; import '../globals.dart'; @@ -123,12 +124,18 @@ // prepare a union of all the .packages files if (dependencies.hasConflicts) { - printError(dependencies.generateConflictReport()); - printError('Make sure you have run "pub upgrade" in all the directories mentioned above.'); - if (dependencies.hasConflictsAffectingFlutterRepo) - printError('For packages in the flutter repository, try using "flutter update-packages --upgrade" to do all of them at once.'); - printError('If this does not help, to track down the conflict you can use "pub deps --style=list" and "pub upgrade --verbosity=solver" in the affected directories.'); - return 1; + StringBuffer message = new StringBuffer(); + message.writeln(dependencies.generateConflictReport()); + message.writeln('Make sure you have run "pub upgrade" in all the directories mentioned above.'); + if (dependencies.hasConflictsAffectingFlutterRepo) { + message.writeln( + 'For packages in the flutter repository, try using ' + '"flutter update-packages --upgrade" to do all of them at once.'); + } + message.write( + 'If this does not help, to track down the conflict you can use ' + '"pub deps --style=list" and "pub upgrade --verbosity=solver" in the affected directories.'); + throwToolExit(message.toString()); } Map<String, String> packages = dependencies.asPackageMap(); @@ -185,11 +192,11 @@ writeBenchmark(stopwatch, errorCount, membersMissingDocumentation); if (errorCount > 0) { + // we consider any level of error to be an error exit (we don't report different levels) if (membersMissingDocumentation > 0 && flutterRepo) - printError('[lint] $membersMissingDocumentation public ${ membersMissingDocumentation == 1 ? "member lacks" : "members lack" } documentation (ran in ${elapsed}s)'); + throwToolExit('[lint] $membersMissingDocumentation public ${ membersMissingDocumentation == 1 ? "member lacks" : "members lack" } documentation (ran in ${elapsed}s)'); else - print('(Ran in ${elapsed}s)'); - return 1; // we consider any level of error to be an error exit (we don't report different levels) + throwToolExit('(Ran in ${elapsed}s)'); } if (argResults['congratulate']) { if (membersMissingDocumentation > 0 && flutterRepo) {
diff --git a/packages/flutter_tools/lib/src/commands/channel.dart b/packages/flutter_tools/lib/src/commands/channel.dart index bc564d5..236c2a6 100644 --- a/packages/flutter_tools/lib/src/commands/channel.dart +++ b/packages/flutter_tools/lib/src/commands/channel.dart
@@ -4,6 +4,7 @@ import 'dart:async'; +import '../base/common.dart'; import '../base/process.dart'; import '../cache.dart'; import '../globals.dart'; @@ -20,16 +21,14 @@ String get invocation => '${runner.executableName} $name [<channel-name>]'; @override - Future<int> runCommand() async { + Future<int> runCommand() { switch (argResults.rest.length) { case 0: - return await _listChannels(); + return _listChannels(); case 1: - return await _switchChannel(argResults.rest[0]); + return _switchChannel(argResults.rest[0]); default: - printStatus('Too many arguments.'); - printStatus(usage); - return 2; + throw new ToolExit('Too many arguments.\n$usage'); } } @@ -39,7 +38,7 @@ workingDirectory: Cache.flutterRoot); printStatus('Flutter channels:'); - return runCommandAndStreamOutput( + int result = await runCommandAndStreamOutput( <String>['git', 'branch', '-r'], workingDirectory: Cache.flutterRoot, mapFunction: (String line) { @@ -51,13 +50,19 @@ return ' $branchName'; }, ); + if (result != 0) + throwToolExit('List channels failed: $result', exitCode: result); + return 0; } - Future<int> _switchChannel(String branchName) { + Future<int> _switchChannel(String branchName) async { printStatus('Switching to flutter channel named $branchName'); - return runCommandAndStreamOutput( + int result = await runCommandAndStreamOutput( <String>['git', 'checkout', branchName], workingDirectory: Cache.flutterRoot, ); + if (result != 0) + throwToolExit('Switch channel failed: $result', exitCode: result); + return 0; } }
diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index 781bb62..47c8d43 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart
@@ -8,6 +8,7 @@ import 'package:path/path.dart' as path; import '../android/android.dart' as android; +import '../base/common.dart'; import '../base/utils.dart'; import '../cache.dart'; import '../dart/pub.dart'; @@ -46,28 +47,23 @@ @override Future<int> runCommand() async { - if (argResults.rest.isEmpty) { - printError('No option specified for the output directory.'); - printError(usage); - return 2; - } + if (argResults.rest.isEmpty) + throwToolExit('No option specified for the output directory.\n$usage', exitCode: 2); if (argResults.rest.length > 1) { - printError('Multiple output directories specified.'); + String message = 'Multiple output directories specified.'; for (String arg in argResults.rest) { if (arg.startsWith('-')) { - printError('Try moving $arg to be immediately following $name'); + message += '\nTry moving $arg to be immediately following $name'; break; } } - return 2; + throwToolExit(message, exitCode: 2); } - if (Cache.flutterRoot == null) { - printError('Neither the --flutter-root command line flag nor the FLUTTER_ROOT environment\n' - 'variable was specified. Unable to find package:flutter.'); - return 2; - } + if (Cache.flutterRoot == null) + throwToolExit('Neither the --flutter-root command line flag nor the FLUTTER_ROOT environment\n' + 'variable was specified. Unable to find package:flutter.', exitCode: 2); await Cache.instance.updateAll(); @@ -75,16 +71,12 @@ String flutterPackagesDirectory = path.join(flutterRoot, 'packages'); String flutterPackagePath = path.join(flutterPackagesDirectory, 'flutter'); - if (!FileSystemEntity.isFileSync(path.join(flutterPackagePath, 'pubspec.yaml'))) { - printError('Unable to find package:flutter in $flutterPackagePath'); - return 2; - } + if (!FileSystemEntity.isFileSync(path.join(flutterPackagePath, 'pubspec.yaml'))) + throwToolExit('Unable to find package:flutter in $flutterPackagePath', exitCode: 2); String flutterDriverPackagePath = path.join(flutterRoot, 'packages', 'flutter_driver'); - if (!FileSystemEntity.isFileSync(path.join(flutterDriverPackagePath, 'pubspec.yaml'))) { - printError('Unable to find package:flutter_driver in $flutterDriverPackagePath'); - return 2; - } + if (!FileSystemEntity.isFileSync(path.join(flutterDriverPackagePath, 'pubspec.yaml'))) + throwToolExit('Unable to find package:flutter_driver in $flutterDriverPackagePath', exitCode: 2); Directory projectDir = new Directory(argResults.rest.first); String dirPath = path.normalize(projectDir.absolute.path); @@ -92,16 +84,12 @@ String projectName = _normalizeProjectName(path.basename(dirPath)); String error =_validateProjectDir(dirPath, flutterRoot: flutterRoot); - if (error != null) { - printError(error); - return 1; - } + if (error != null) + throwToolExit(error); error = _validateProjectName(projectName); - if (error != null) { - printError(error); - return 1; - } + if (error != null) + throwToolExit(error); int generatedCount = _renderTemplates( projectName, @@ -114,11 +102,8 @@ printStatus(''); - if (argResults['pub']) { - int code = await pubGet(directory: dirPath); - if (code != 0) - return code; - } + if (argResults['pub']) + await pubGet(directory: dirPath); printStatus(''); @@ -149,7 +134,6 @@ "directory in order to launch your app."); printStatus("Your main program file is: $relativePath/lib/main.dart"); } - return 0; }
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart index 3c5e66d..f55f6bb 100644 --- a/packages/flutter_tools/lib/src/commands/daemon.dart +++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -7,6 +7,7 @@ import 'dart:io'; import '../android/android_device.dart'; +import '../base/common.dart'; import '../base/context.dart'; import '../base/logger.dart'; import '../base/utils.dart'; @@ -51,12 +52,15 @@ Cache.releaseLockEarly(); - return appContext.runInZone(() { + return appContext.runInZone(() async { Daemon daemon = new Daemon( stdinCommandStream, stdoutCommandResponse, daemonCommand: this, notifyingLogger: notifyingLogger); - return daemon.onExit; + int code = await daemon.onExit; + if (code != null) + throwToolExit(null, exitCode: code); + return 0; }, onError: _handleError); }
diff --git a/packages/flutter_tools/lib/src/commands/devices.dart b/packages/flutter_tools/lib/src/commands/devices.dart index f8670e1..afe91a8 100644 --- a/packages/flutter_tools/lib/src/commands/devices.dart +++ b/packages/flutter_tools/lib/src/commands/devices.dart
@@ -4,6 +4,7 @@ import 'dart:async'; +import '../base/common.dart'; import '../base/utils.dart'; import '../device.dart'; import '../globals.dart'; @@ -19,9 +20,10 @@ @override Future<int> runCommand() async { if (!doctor.canListAnything) { - printError("Unable to locate a development device; please run 'flutter doctor' for " - "information about installing additional components."); - return 1; + throwToolExit( + "Unable to locate a development device; please run 'flutter doctor' for " + "information about installing additional components.", + exitCode: 1); } List<Device> devices = await deviceManager.getAllConnectedDevices(); @@ -35,7 +37,6 @@ printStatus('${devices.length} connected ${pluralize('device', devices.length)}:\n'); Device.printDevices(devices); } - return 0; } }