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 { ...@@ -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 // Wait for stdout and stderr to be fully processed, because process.exitCode
// may complete first. // may complete first.
try { try {
await Future.wait<void>(<Future<void>>[ await Future.wait<void>(<Future<void>>[
_stdio.addStdoutStream(process.stdout), _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) { } on Exception catch (err, stack) {
_logger.printTrace('Echoing stdout or stderr from the license subprocess failed:'); _logger.printTrace('Echoing stdout or stderr from the license subprocess failed:');
...@@ -403,11 +407,7 @@ class AndroidLicenseValidator extends DoctorValidator { ...@@ -403,11 +407,7 @@ class AndroidLicenseValidator extends DoctorValidator {
final int exitCode = await process.exitCode; final int exitCode = await process.exitCode;
if (exitCode != 0) { if (exitCode != 0) {
throwToolExit(_userMessages.androidCannotRunSdkManager( throwToolExit(_messageForSdkManagerError(stderrLines, exitCode));
_androidSdk.sdkManagerPath ?? '',
'exited code $exitCode',
_platform,
));
} }
return true; return true;
} on ProcessException catch (e) { } on ProcessException catch (e) {
...@@ -426,4 +426,30 @@ class AndroidLicenseValidator extends DoctorValidator { ...@@ -426,4 +426,30 @@ class AndroidLicenseValidator extends DoctorValidator {
} }
return _processManager.canRun(sdkManagerPath); 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 { ...@@ -102,7 +102,7 @@ class UserMessages {
'Unable to locate Android SDK.\n' 'Unable to locate Android SDK.\n'
'Install Android Studio from: https://developer.android.com/studio/index.html\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' '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' 'If the Android SDK has been installed to a custom location, please use\n'
'`flutter config --android-sdk` to update to that location.\n'; '`flutter config --android-sdk` to update to that location.\n';
String androidSdkLocation(String directory) => 'Android SDK at $directory'; String androidSdkLocation(String directory) => 'Android SDK at $directory';
...@@ -110,7 +110,7 @@ class UserMessages { ...@@ -110,7 +110,7 @@ class UserMessages {
'Platform $platform, build-tools $tools'; 'Platform $platform, build-tools $tools';
String androidSdkInstallHelp(Platform platform) => String androidSdkInstallHelp(Platform platform) =>
'Try re-installing or updating your Android SDK,\n' '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 // Also occurs in AndroidLicenseValidator
String androidStatusInfo(String version) => 'Android SDK version $version'; String androidStatusInfo(String version) => 'Android SDK version $version';
...@@ -126,7 +126,7 @@ class UserMessages { ...@@ -126,7 +126,7 @@ class UserMessages {
String androidLicensesUnknown(Platform platform) => String androidLicensesUnknown(Platform platform) =>
'Android license status unknown.\n' 'Android license status unknown.\n'
'Run `flutter doctor --android-licenses` to accept the SDK licenses.\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) => String androidSdkManagerOutdated(String managerPath) =>
'A newer version of the Android SDK is required. To update, run:\n' 'A newer version of the Android SDK is required. To update, run:\n'
'$managerPath --update\n'; '$managerPath --update\n';
...@@ -135,14 +135,14 @@ class UserMessages { ...@@ -135,14 +135,14 @@ class UserMessages {
String androidMissingSdkManager(String sdkManagerPath, Platform platform) => String androidMissingSdkManager(String sdkManagerPath, Platform platform) =>
'Android sdkmanager tool not found ($sdkManagerPath).\n' 'Android sdkmanager tool not found ($sdkManagerPath).\n'
'Try re-installing or updating your Android SDK,\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) => String androidCannotRunSdkManager(String sdkManagerPath, String error, Platform platform) =>
'Android sdkmanager tool was found, but failed to run ($sdkManagerPath): "$error".\n' 'Android sdkmanager tool was found, but failed to run ($sdkManagerPath): "$error".\n'
'Try re-installing or updating your Android SDK,\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) => String androidSdkBuildToolsOutdated(int sdkMinVersion, String buildToolsMinVersion, Platform platform) =>
'Flutter requires Android SDK $sdkMinVersion and the Android BuildTools $buildToolsMinVersion\n' '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' String get androidMissingCmdTools => 'cmdline-tools component is missing\n'
'Run `path/to/sdkmanager --install "cmdline-tools;latest"`\n' 'Run `path/to/sdkmanager --install "cmdline-tools;latest"`\n'
'See https://developer.android.com/studio/command-line for more details.'; 'See https://developer.android.com/studio/command-line for more details.';
...@@ -163,7 +163,7 @@ class UserMessages { ...@@ -163,7 +163,7 @@ class UserMessages {
'but Android Studio not found at this location.'; 'but Android Studio not found at this location.';
String androidStudioInstallation(Platform platform) => String androidStudioInstallation(Platform platform) =>
'Android Studio not found; download from https://developer.android.com/studio/index.html\n' '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 // Messages used in XcodeValidator
String xcodeLocation(String location) => 'Xcode at $location'; String xcodeLocation(String location) => 'Xcode at $location';
...@@ -351,7 +351,7 @@ class UserMessages { ...@@ -351,7 +351,7 @@ class UserMessages {
'Read more about iOS versioning at\n' 'Read more about iOS versioning at\n'
'https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html\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 baseUrl = 'https://flutter.dev/docs/get-started/install';
const String fragment = '#android-setup'; const String fragment = '#android-setup';
if (platform.isMacOS) { if (platform.isMacOS) {
......
...@@ -578,6 +578,42 @@ Review licenses that have not been accepted (y/N)? ...@@ -578,6 +578,42 @@ Review licenses that have not been accepted (y/N)?
true, 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 { 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