Commit f44ba8b9 authored by Jason Simmons's avatar Jason Simmons Committed by GitHub

Add a flutter doctor --android-licenses command that locates and runs the...

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
parent 5cec1080
...@@ -32,7 +32,7 @@ class AndroidWorkflow extends DoctorValidator implements Workflow { ...@@ -32,7 +32,7 @@ class AndroidWorkflow extends DoctorValidator implements Workflow {
static const String _kJdkDownload = 'https://www.oracle.com/technetwork/java/javase/downloads/'; 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. /// 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) if (android_studio.javaPath != null)
return fs.path.join(android_studio.javaPath, 'bin', 'java'); return fs.path.join(android_studio.javaPath, 'bin', 'java');
...@@ -163,4 +163,32 @@ class AndroidWorkflow extends DoctorValidator implements Workflow { ...@@ -163,4 +163,32 @@ class AndroidWorkflow extends DoctorValidator implements Workflow {
// Success. // Success.
return new ValidationResult(ValidationType.installed, messages, statusInfo: sdkVersionText); return new ValidationResult(ValidationType.installed, messages, statusInfo: sdkVersionText);
} }
/// Run the Android SDK manager tool in order to accept SDK licenses.
static Future<bool> 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<String, String> sdkManagerEnv = <String, String>{};
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'),
<String>['--licenses'],
environment: sdkManagerEnv,
);
stdout.addStream(process.stdout);
stderr.addStream(process.stderr);
process.stdin.addStream(stdin);
final int exitCode = await process.exitCode;
return exitCode == 0;
}
} }
...@@ -61,6 +61,9 @@ abstract class OperatingSystemUtils { ...@@ -61,6 +61,9 @@ abstract class OperatingSystemUtils {
} }
List<File> _which(String execName, {bool all: false}); List<File> _which(String execName, {bool all: false});
/// Returns the separator between items in the PATH environment variable.
String get pathVarSeparator;
} }
class _PosixUtils extends OperatingSystemUtils { class _PosixUtils extends OperatingSystemUtils {
...@@ -120,6 +123,9 @@ class _PosixUtils extends OperatingSystemUtils { ...@@ -120,6 +123,9 @@ class _PosixUtils extends OperatingSystemUtils {
} }
return _name; return _name;
} }
@override
String get pathVarSeparator => ':';
} }
class _WindowsUtils extends OperatingSystemUtils { class _WindowsUtils extends OperatingSystemUtils {
...@@ -193,6 +199,9 @@ class _WindowsUtils extends OperatingSystemUtils { ...@@ -193,6 +199,9 @@ class _WindowsUtils extends OperatingSystemUtils {
} }
return _name; return _name;
} }
@override
String get pathVarSeparator => ';';
} }
/// Find and return the project root directory relative to the specified /// Find and return the project root directory relative to the specified
......
...@@ -8,6 +8,13 @@ import '../doctor.dart'; ...@@ -8,6 +8,13 @@ import '../doctor.dart';
import '../runner/flutter_command.dart'; import '../runner/flutter_command.dart';
class DoctorCommand extends FlutterCommand { 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 @override
final String name = 'doctor'; final String name = 'doctor';
...@@ -16,7 +23,7 @@ class DoctorCommand extends FlutterCommand { ...@@ -16,7 +23,7 @@ class DoctorCommand extends FlutterCommand {
@override @override
Future<FlutterCommandResult> runCommand() async { Future<FlutterCommandResult> 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); return new FlutterCommandResult(success ? ExitStatus.success : ExitStatus.warning);
} }
} }
...@@ -106,7 +106,10 @@ class Doctor { ...@@ -106,7 +106,10 @@ class Doctor {
} }
/// Print verbose information about the state of installed tooling. /// Print verbose information about the state of installed tooling.
Future<bool> diagnose() async { Future<bool> diagnose({ bool androidLicenses: false }) async {
if (androidLicenses)
return AndroidWorkflow.runLicenseManager();
bool doctorResult = true; bool doctorResult = true;
for (DoctorValidator validator in validators) { for (DoctorValidator validator in validators) {
......
...@@ -93,7 +93,7 @@ void main() { ...@@ -93,7 +93,7 @@ void main() {
testUsingContext('flutter commands send timing events', () async { testUsingContext('flutter commands send timing events', () async {
mockTimes = <int>[1000, 2000]; mockTimes = <int>[1000, 2000];
when(mockDoctor.diagnose()).thenReturn(true); when(mockDoctor.diagnose(androidLicenses: false)).thenReturn(true);
final DoctorCommand command = new DoctorCommand(); final DoctorCommand command = new DoctorCommand();
final CommandRunner<Null> runner = createTestCommandRunner(command); final CommandRunner<Null> runner = createTestCommandRunner(command);
await runner.run(<String>['doctor']); await runner.run(<String>['doctor']);
...@@ -112,7 +112,7 @@ void main() { ...@@ -112,7 +112,7 @@ void main() {
testUsingContext('doctor fail sends warning', () async { testUsingContext('doctor fail sends warning', () async {
mockTimes = <int>[1000, 2000]; mockTimes = <int>[1000, 2000];
when(mockDoctor.diagnose()).thenReturn(false); when(mockDoctor.diagnose(androidLicenses: false)).thenReturn(false);
final DoctorCommand command = new DoctorCommand(); final DoctorCommand command = new DoctorCommand();
final CommandRunner<Null> runner = createTestCommandRunner(command); final CommandRunner<Null> runner = createTestCommandRunner(command);
await runner.run(<String>['doctor']); await runner.run(<String>['doctor']);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment