From f44ba8b9c94d28cf40fde938476b2a4e1392a95e Mon Sep 17 00:00:00 2001 From: Jason Simmons Date: Tue, 9 May 2017 10:18:45 -0700 Subject: [PATCH] Add a flutter doctor --android-licenses command that locates and runs the Android SDK license manager (#9892) See https://github.com/flutter/flutter/issues/8438 --- .../lib/src/android/android_workflow.dart | 30 ++++++++++++++++++- packages/flutter_tools/lib/src/base/os.dart | 9 ++++++ .../lib/src/commands/doctor.dart | 9 +++++- packages/flutter_tools/lib/src/doctor.dart | 5 +++- .../flutter_tools/test/analytics_test.dart | 4 +-- 5 files changed, 52 insertions(+), 5 deletions(-) diff --git a/packages/flutter_tools/lib/src/android/android_workflow.dart b/packages/flutter_tools/lib/src/android/android_workflow.dart index 19b39afc8f..9eada5190e 100644 --- a/packages/flutter_tools/lib/src/android/android_workflow.dart +++ b/packages/flutter_tools/lib/src/android/android_workflow.dart @@ -32,7 +32,7 @@ class AndroidWorkflow extends DoctorValidator implements Workflow { static const String _kJdkDownload = 'https://www.oracle.com/technetwork/java/javase/downloads/'; /// First try Java bundled with Android Studio, then sniff JAVA_HOME, then fallback to PATH. - String _findJavaBinary() { + static String _findJavaBinary() { if (android_studio.javaPath != null) return fs.path.join(android_studio.javaPath, 'bin', 'java'); @@ -163,4 +163,32 @@ class AndroidWorkflow extends DoctorValidator implements Workflow { // Success. return new ValidationResult(ValidationType.installed, messages, statusInfo: sdkVersionText); } + + /// Run the Android SDK manager tool in order to accept SDK licenses. + static Future runLicenseManager() async { + if (androidSdk == null) { + printStatus('Unable to locate Android SDK.'); + return false; + } + + // If we can locate Java, then add it to the path used to run the Android SDK manager. + final Map sdkManagerEnv = {}; + final String javaBinary = _findJavaBinary(); + if (javaBinary != null) { + sdkManagerEnv['PATH'] = + platform.environment['PATH'] + os.pathVarSeparator + fs.path.dirname(javaBinary); + } + + final Process process = await Process.start( + fs.path.join(androidSdk.directory, 'tools', 'bin', 'sdkmanager'), + ['--licenses'], + environment: sdkManagerEnv, + ); + stdout.addStream(process.stdout); + stderr.addStream(process.stderr); + process.stdin.addStream(stdin); + + final int exitCode = await process.exitCode; + return exitCode == 0; + } } diff --git a/packages/flutter_tools/lib/src/base/os.dart b/packages/flutter_tools/lib/src/base/os.dart index dc97811ef9..b4027ad8b3 100644 --- a/packages/flutter_tools/lib/src/base/os.dart +++ b/packages/flutter_tools/lib/src/base/os.dart @@ -61,6 +61,9 @@ abstract class OperatingSystemUtils { } List _which(String execName, {bool all: false}); + + /// Returns the separator between items in the PATH environment variable. + String get pathVarSeparator; } class _PosixUtils extends OperatingSystemUtils { @@ -120,6 +123,9 @@ class _PosixUtils extends OperatingSystemUtils { } return _name; } + + @override + String get pathVarSeparator => ':'; } class _WindowsUtils extends OperatingSystemUtils { @@ -193,6 +199,9 @@ class _WindowsUtils extends OperatingSystemUtils { } return _name; } + + @override + String get pathVarSeparator => ';'; } /// Find and return the project root directory relative to the specified diff --git a/packages/flutter_tools/lib/src/commands/doctor.dart b/packages/flutter_tools/lib/src/commands/doctor.dart index f891564705..96d9268969 100644 --- a/packages/flutter_tools/lib/src/commands/doctor.dart +++ b/packages/flutter_tools/lib/src/commands/doctor.dart @@ -8,6 +8,13 @@ import '../doctor.dart'; import '../runner/flutter_command.dart'; class DoctorCommand extends FlutterCommand { + DoctorCommand() { + argParser.addFlag('android-licenses', + defaultsTo: false, + help: 'Run the Android SDK manager tool to accept the SDK\'s licenses.', + ); + } + @override final String name = 'doctor'; @@ -16,7 +23,7 @@ class DoctorCommand extends FlutterCommand { @override Future runCommand() async { - final bool success = await doctor.diagnose(); + final bool success = await doctor.diagnose(androidLicenses: argResults['android-licenses']); return new FlutterCommandResult(success ? ExitStatus.success : ExitStatus.warning); } } diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart index 762a4d70f2..7b76ffa648 100644 --- a/packages/flutter_tools/lib/src/doctor.dart +++ b/packages/flutter_tools/lib/src/doctor.dart @@ -106,7 +106,10 @@ class Doctor { } /// Print verbose information about the state of installed tooling. - Future diagnose() async { + Future diagnose({ bool androidLicenses: false }) async { + if (androidLicenses) + return AndroidWorkflow.runLicenseManager(); + bool doctorResult = true; for (DoctorValidator validator in validators) { diff --git a/packages/flutter_tools/test/analytics_test.dart b/packages/flutter_tools/test/analytics_test.dart index d3f9ded946..f1388fa18b 100644 --- a/packages/flutter_tools/test/analytics_test.dart +++ b/packages/flutter_tools/test/analytics_test.dart @@ -93,7 +93,7 @@ void main() { testUsingContext('flutter commands send timing events', () async { mockTimes = [1000, 2000]; - when(mockDoctor.diagnose()).thenReturn(true); + when(mockDoctor.diagnose(androidLicenses: false)).thenReturn(true); final DoctorCommand command = new DoctorCommand(); final CommandRunner runner = createTestCommandRunner(command); await runner.run(['doctor']); @@ -112,7 +112,7 @@ void main() { testUsingContext('doctor fail sends warning', () async { mockTimes = [1000, 2000]; - when(mockDoctor.diagnose()).thenReturn(false); + when(mockDoctor.diagnose(androidLicenses: false)).thenReturn(false); final DoctorCommand command = new DoctorCommand(); final CommandRunner runner = createTestCommandRunner(command); await runner.run(['doctor']);