Commit 2148e9af authored by John McCutchan's avatar John McCutchan Committed by GitHub

Improvements to flutter doctor JDK search. (#8745)

- [x] Add custom logic on MacOS to determine if Java is installed before invoking `java`.
- [x] Check JAVA_HOME, platform specific logic, and finally PATH to locate the `java` executable.
- [x] Improved doctor messages.

Fixes #8508
Fixes #8521
parent e22d0e60
......@@ -5,7 +5,10 @@
import 'dart:async';
import '../base/io.dart';
import '../base/file_system.dart';
import '../base/os.dart';
import '../base/platform.dart';
import '../base/process.dart';
import '../base/process_manager.dart';
import '../doctor.dart';
import '../globals.dart';
......@@ -23,13 +26,71 @@ class AndroidWorkflow extends DoctorValidator implements Workflow {
@override
bool get canLaunchDevices => androidSdk != null && androidSdk.validateSdkWellFormed().isEmpty;
static const String _kJavaHomeEnvironmentVariable = 'JAVA_HOME';
static const String _kJavaExecutable = 'java';
static const String _kJdkDownload = 'https://www.oracle.com/technetwork/java/javase/downloads/';
/// First sniff JAVA_HOME, then fallback to PATH.
String _findJavaBinary() {
final String javaHomeEnv = platform.environment[_kJavaHomeEnvironmentVariable];
if (javaHomeEnv != null) {
// Trust JAVA_HOME.
return fs.path.join(javaHomeEnv, 'bin', 'java');
}
// MacOS specific logic to avoid popping up a dialog window.
// See: http://stackoverflow.com/questions/14292698/how-do-i-check-if-the-java-jdk-is-installed-on-mac.
if (platform.isMacOS) {
try {
final String javaHomeOutput = runCheckedSync(<String>['/usr/libexec/java_home'], hideStdout: true);
if (javaHomeOutput != null) {
final List<String> javaHomeOutputSplit = javaHomeOutput.split('\n');
if ((javaHomeOutputSplit != null) && (javaHomeOutputSplit.length > 0)) {
final String javaHome = javaHomeOutputSplit[0].trim();
return fs.path.join(javaHome, 'bin', 'java');
}
}
} catch (_) { /* ignore */ }
}
// Fallback to PATH based lookup.
return os.which(_kJavaExecutable)?.path;
}
/// Returns false if we cannot determine the Java version or if the version
/// is not compatible.
bool _checkJavaVersion(String javaBinary, List<ValidationMessage> messages) {
if (!processManager.canRun(javaBinary)) {
messages.add(new ValidationMessage.error('Cannot execute $javaBinary to determine the version'));
return false;
}
String javaVersion;
try {
printTrace('java -version');
final ProcessResult result = processManager.runSync(<String>[javaBinary, '-version']);
if (result.exitCode == 0) {
final List<String> versionLines = result.stderr.split('\n');
javaVersion = versionLines.length >= 2 ? versionLines[1] : versionLines[0];
}
} catch (_) { /* ignore */ }
if (javaVersion == null) {
// Could not determine the java version.
messages.add(new ValidationMessage.error('Could not determine java version'));
return false;
}
messages.add(new ValidationMessage('Java version: $javaVersion'));
// TODO(johnmccutchan): Validate version.
return true;
}
@override
Future<ValidationResult> validate() async {
final List<ValidationMessage> messages = <ValidationMessage>[];
ValidationType type = ValidationType.missing;
String sdkVersionText;
if (androidSdk == null) {
// No Android SDK found.
if (platform.environment.containsKey(kAndroidHome)) {
final String androidHomeDir = platform.environment[kAndroidHome];
messages.add(new ValidationMessage.error(
......@@ -42,11 +103,13 @@ class AndroidWorkflow extends DoctorValidator implements Workflow {
'(or visit https://flutter.io/setup/#android-setup for detailed instructions).'
));
}
} else {
type = ValidationType.partial;
return new ValidationResult(ValidationType.missing, messages);
}
messages.add(new ValidationMessage('Android SDK at ${androidSdk.directory}'));
String sdkVersionText;
if (androidSdk.latestVersion != null) {
sdkVersionText = 'Android SDK ${androidSdk.latestVersion.buildToolsVersionName}';
......@@ -63,42 +126,34 @@ class AndroidWorkflow extends DoctorValidator implements Workflow {
final List<String> validationResult = androidSdk.validateSdkWellFormed();
if (validationResult.isEmpty) {
// Empty result means SDK is well formed.
// The SDK also requires a valid Java JDK installation.
const String _kJdkDownload = 'https://www.oracle.com/technetwork/java/javase/downloads/';
String javaVersion;
try {
printTrace('java -version');
final ProcessResult result = processManager.runSync(<String>['java', '-version']);
if (result.exitCode == 0) {
javaVersion = result.stderr;
final List<String> versionLines = javaVersion.split('\n');
javaVersion = versionLines.length >= 2 ? versionLines[1] : versionLines[0];
}
} catch (error) {
}
if (javaVersion == null) {
messages.add(new ValidationMessage.error(
'No Java Development Kit (JDK) found; you can download the JDK from $_kJdkDownload.'
));
} else {
messages.add(new ValidationMessage(javaVersion));
type = ValidationType.installed;
}
} else {
if (validationResult.isNotEmpty) {
// Android SDK is not functional.
messages.addAll(validationResult.map((String message) {
return new ValidationMessage.error(message);
}));
messages.add(new ValidationMessage(
'Try re-installing or updating your Android SDK,\n'
'visit https://flutter.io/setup/#android-setup for detailed instructions.'));
return new ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText);
}
// Now check for the JDK.
final String javaBinary = _findJavaBinary();
if (javaBinary == null) {
messages.add(new ValidationMessage.error(
'No Java Development Kit (JDK) found; You must have the environment '
'variable JAVA_HOME set and the java binary in your PATH. '
'You can download the JDK from $_kJdkDownload.'));
return new ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText);
}
messages.add(new ValidationMessage('Java binary at: $javaBinary'));
// Check JDK version.
if (!_checkJavaVersion(javaBinary, messages)) {
return new ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText);
}
return new ValidationResult(type, messages, statusInfo: sdkVersionText);
// Success.
return new ValidationResult(ValidationType.installed, messages, statusInfo: sdkVersionText);
}
}
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