Unverified Commit cf09a8a2 authored by Andrew Kolos's avatar Andrew Kolos Committed by GitHub

In `flutter doctor -v`, when JRE is too out-of-date to run `sdkmanager`, print...

In `flutter doctor -v`, when JRE is too out-of-date to run `sdkmanager`, print a helpful error message (#138762)

Closes https://github.com/flutter/flutter/issues/138132. See this issue for more information.
parent 9d9dbb78
......@@ -389,12 +389,16 @@ class AndroidLicenseValidator extends DoctorValidator {
),
);
final List<String> stderrLines = <String>[];
// Wait for stdout and stderr to be fully processed, because process.exitCode
// may complete first.
try {
await Future.wait<void>(<Future<void>>[
_stdio.addStdoutStream(process.stdout),
_stdio.addStderrStream(process.stderr),
process.stderr.forEach((List<int> event) {
_stdio.stderr.add(event);
stderrLines.add(utf8.decode(event));
}),
]);
} on Exception catch (err, stack) {
_logger.printTrace('Echoing stdout or stderr from the license subprocess failed:');
......@@ -403,11 +407,7 @@ class AndroidLicenseValidator extends DoctorValidator {
final int exitCode = await process.exitCode;
if (exitCode != 0) {
throwToolExit(_userMessages.androidCannotRunSdkManager(
_androidSdk.sdkManagerPath ?? '',
'exited code $exitCode',
_platform,
));
throwToolExit(_messageForSdkManagerError(stderrLines, exitCode));
}
return true;
} on ProcessException catch (e) {
......@@ -426,4 +426,30 @@ class AndroidLicenseValidator extends DoctorValidator {
}
return _processManager.canRun(sdkManagerPath);
}
String _messageForSdkManagerError(
List<String> androidSdkStderr,
int exitCode,
) {
final String sdkManagerPath = _androidSdk!.sdkManagerPath!;
final bool failedDueToJdkIncompatibility = androidSdkStderr.join().contains(
RegExp(r'java\.lang\.UnsupportedClassVersionError.*SdkManagerCli '
r'has been compiled by a more recent version of the Java Runtime'));
if (failedDueToJdkIncompatibility) {
return 'Android sdkmanager tool was found, but failed to run ($sdkManagerPath): "exited code $exitCode".\n'
'It appears the version of the Java binary used (${_java!.binaryPath}) is '
'too out-of-date and is incompatible with the Android sdkmanager tool.\n'
'If the Java binary came bundled with Android Studio, consider updating '
'your installation of Android studio. Alternatively, you can uninstall '
'the Android SDK command-line tools and install an earlier version. ';
}
return _userMessages.androidCannotRunSdkManager(
sdkManagerPath,
'exited code $exitCode',
_platform,
);
}
}
......@@ -102,7 +102,7 @@ class UserMessages {
'Unable to locate Android SDK.\n'
'Install Android Studio from: https://developer.android.com/studio/index.html\n'
'On first launch it will assist you in installing the Android SDK components.\n'
'(or visit ${_androidSdkInstallUrl(platform)} for detailed instructions).\n'
'(or visit ${androidSdkInstallUrl(platform)} for detailed instructions).\n'
'If the Android SDK has been installed to a custom location, please use\n'
'`flutter config --android-sdk` to update to that location.\n';
String androidSdkLocation(String directory) => 'Android SDK at $directory';
......@@ -110,7 +110,7 @@ class UserMessages {
'Platform $platform, build-tools $tools';
String androidSdkInstallHelp(Platform platform) =>
'Try re-installing or updating your Android SDK,\n'
'visit ${_androidSdkInstallUrl(platform)} for detailed instructions.';
'visit ${androidSdkInstallUrl(platform)} for detailed instructions.';
// Also occurs in AndroidLicenseValidator
String androidStatusInfo(String version) => 'Android SDK version $version';
......@@ -126,7 +126,7 @@ class UserMessages {
String androidLicensesUnknown(Platform platform) =>
'Android license status unknown.\n'
'Run `flutter doctor --android-licenses` to accept the SDK licenses.\n'
'See ${_androidSdkInstallUrl(platform)} for more details.';
'See ${androidSdkInstallUrl(platform)} for more details.';
String androidSdkManagerOutdated(String managerPath) =>
'A newer version of the Android SDK is required. To update, run:\n'
'$managerPath --update\n';
......@@ -135,14 +135,14 @@ class UserMessages {
String androidMissingSdkManager(String sdkManagerPath, Platform platform) =>
'Android sdkmanager tool not found ($sdkManagerPath).\n'
'Try re-installing or updating your Android SDK,\n'
'visit ${_androidSdkInstallUrl(platform)} for detailed instructions.';
'visit ${androidSdkInstallUrl(platform)} for detailed instructions.';
String androidCannotRunSdkManager(String sdkManagerPath, String error, Platform platform) =>
'Android sdkmanager tool was found, but failed to run ($sdkManagerPath): "$error".\n'
'Try re-installing or updating your Android SDK,\n'
'visit ${_androidSdkInstallUrl(platform)} for detailed instructions.';
'visit ${androidSdkInstallUrl(platform)} for detailed instructions.';
String androidSdkBuildToolsOutdated(int sdkMinVersion, String buildToolsMinVersion, Platform platform) =>
'Flutter requires Android SDK $sdkMinVersion and the Android BuildTools $buildToolsMinVersion\n'
'To update the Android SDK visit ${_androidSdkInstallUrl(platform)} for detailed instructions.';
'To update the Android SDK visit ${androidSdkInstallUrl(platform)} for detailed instructions.';
String get androidMissingCmdTools => 'cmdline-tools component is missing\n'
'Run `path/to/sdkmanager --install "cmdline-tools;latest"`\n'
'See https://developer.android.com/studio/command-line for more details.';
......@@ -163,7 +163,7 @@ class UserMessages {
'but Android Studio not found at this location.';
String androidStudioInstallation(Platform platform) =>
'Android Studio not found; download from https://developer.android.com/studio/index.html\n'
'(or visit ${_androidSdkInstallUrl(platform)} for detailed instructions).';
'(or visit ${androidSdkInstallUrl(platform)} for detailed instructions).';
// Messages used in XcodeValidator
String xcodeLocation(String location) => 'Xcode at $location';
......@@ -351,7 +351,7 @@ class UserMessages {
'Read more about iOS versioning at\n'
'https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html\n';
String _androidSdkInstallUrl(Platform platform) {
String androidSdkInstallUrl(Platform platform) {
const String baseUrl = 'https://flutter.dev/docs/get-started/install';
const String fragment = '#android-setup';
if (platform.isMacOS) {
......
......@@ -578,6 +578,42 @@ Review licenses that have not been accepted (y/N)?
true,
);
});
testWithoutContext('Asks user to upgrade Android Studio when it is too far behind the Android SDK', () async {
const String sdkManagerPath = '/foo/bar/sdkmanager';
sdk.sdkManagerPath = sdkManagerPath;
final BufferLogger logger = BufferLogger.test();
processManager.addCommand(
const FakeCommand(
command: <String>[sdkManagerPath, '--licenses'],
exitCode: 1,
stderr: '''
Error: LinkageError occurred while loading main class com.android.sdklib.tool.sdkmanager.SdkManagerCli
java.lang.UnsupportedClassVersionError: com/android/sdklib/tool/sdkmanager/SdkManagerCli has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0
Android sdkmanager tool was found, but failed to run
''',
),
);
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk,
processManager: processManager,
platform: FakePlatform(environment: <String, String>{'HOME': '/home/me'}),
stdio: stdio,
logger: logger,
userMessages: UserMessages(),
);
await expectLater(
licenseValidator.runLicenseManager(),
throwsToolExit(
message: RegExp('.*consider updating your installation of Android studio. Alternatively, you.*'),
),
);
expect(processManager, hasNoRemainingExpectations);
expect(stdio.stderr.getAndClear(), contains('UnsupportedClassVersionError'));
});
}
class FakeAndroidSdk extends Fake implements AndroidSdk {
......
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