Unverified Commit 5b2f658f authored by Andrew Kolos's avatar Andrew Kolos Committed by GitHub

Revert "[tool] Move Java functions to their own file" (#126569)

Reverts flutter/flutter#126086.

This PR changed the interfaces of some classes, namely `AndroidSdk`, and deleted a global.

These classes had custom overrides in g3 that were not updated with a g3fix, so this PR has broken tests. See https://b.corp.google.com/issues/281945232 (non-public link)
parent 37fe1e9d
...@@ -2,13 +2,17 @@ ...@@ -2,13 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:meta/meta.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/os.dart';
import '../base/platform.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../base/version.dart'; import '../base/version.dart';
import '../convert.dart'; import '../convert.dart';
import '../globals.dart' as globals; import '../globals.dart' as globals;
import 'java.dart'; import 'android_studio.dart';
// ANDROID_HOME is deprecated. // ANDROID_HOME is deprecated.
// See https://developer.android.com/studio/command-line/variables.html#envar // See https://developer.android.com/studio/command-line/variables.html#envar
...@@ -32,18 +36,16 @@ final RegExp _sdkVersionRe = RegExp(r'^ro.build.version.sdk=([0-9]+)$'); ...@@ -32,18 +36,16 @@ final RegExp _sdkVersionRe = RegExp(r'^ro.build.version.sdk=([0-9]+)$');
// $ANDROID_SDK_ROOT/platforms/android-23/android.jar // $ANDROID_SDK_ROOT/platforms/android-23/android.jar
// $ANDROID_SDK_ROOT/platforms/android-N/android.jar // $ANDROID_SDK_ROOT/platforms/android-N/android.jar
class AndroidSdk { class AndroidSdk {
AndroidSdk(this.directory, { AndroidSdk(this.directory) {
Java? java,
}): _java = java {
reinitialize(); reinitialize();
} }
static const String javaHomeEnvironmentVariable = 'JAVA_HOME'; static const String javaHomeEnvironmentVariable = 'JAVA_HOME';
static const String _javaExecutable = 'java';
/// The Android SDK root directory. /// The Android SDK root directory.
final Directory directory; final Directory directory;
final Java? _java;
List<AndroidSdkVersion> _sdkVersions = <AndroidSdkVersion>[]; List<AndroidSdkVersion> _sdkVersions = <AndroidSdkVersion>[];
AndroidSdkVersion? _latestVersion; AndroidSdkVersion? _latestVersion;
...@@ -409,6 +411,162 @@ class AndroidSdk { ...@@ -409,6 +411,162 @@ class AndroidSdk {
return null; return null;
} }
/// Returns the version of java in the format \d(.\d)+(.\d)+
/// Returns null if version not found.
String? getJavaVersion({
required AndroidStudio? androidStudio,
required FileSystem fileSystem,
required OperatingSystemUtils operatingSystemUtils,
required Platform platform,
required ProcessUtils processUtils,
}) {
final String? javaBinary = findJavaBinary(
androidStudio: androidStudio,
fileSystem: fileSystem,
operatingSystemUtils: operatingSystemUtils,
platform: platform,
);
if (javaBinary == null) {
globals.printTrace('Could not find java binary to get version.');
return null;
}
final RunResult result = processUtils.runSync(
<String>[javaBinary, '--version'],
environment: sdkManagerEnv,
);
if (result.exitCode != 0) {
globals.printTrace(
'java --version failed: exitCode: ${result.exitCode} stdout: ${result.stdout} stderr: ${result.stderr}');
return null;
}
return parseJavaVersion(result.stdout);
}
/// Extracts JDK version from the output of java --version.
@visibleForTesting
static String? parseJavaVersion(String rawVersionOutput) {
// The contents that matter come in the format '11.0.18' or '1.8.0_202'.
final RegExp jdkVersionRegex = RegExp(r'\d+\.\d+(\.\d+(?:_\d+)?)?');
final Iterable<RegExpMatch> matches =
jdkVersionRegex.allMatches(rawVersionOutput);
if (matches.isEmpty) {
globals.logger.printWarning(_formatJavaVersionWarning(rawVersionOutput));
return null;
}
final String? versionString = matches.first.group(0);
if (versionString == null || versionString.split('_').isEmpty) {
globals.logger.printWarning(_formatJavaVersionWarning(rawVersionOutput));
return null;
}
// Trim away _d+ from versions 1.8 and below.
return versionString.split('_').first;
}
/// A value that would be appropriate to use as JAVA_HOME.
///
/// This method considers jdk in the following order:
/// * the JDK bundled with Android Studio, if one is found;
/// * the JAVA_HOME in the ambient environment, if set;
String? get javaHome {
return findJavaHome(
androidStudio: globals.androidStudio,
fileSystem: globals.fs,
operatingSystemUtils: globals.os,
platform: globals.platform,
);
}
static String? findJavaHome({
required AndroidStudio? androidStudio,
required FileSystem fileSystem,
required OperatingSystemUtils operatingSystemUtils,
required Platform platform,
}) {
if (androidStudio?.javaPath != null) {
globals.printTrace("Using Android Studio's java.");
return androidStudio!.javaPath!;
}
final String? javaHomeEnv = platform.environment[javaHomeEnvironmentVariable];
if (javaHomeEnv != null) {
globals.printTrace('Using JAVA_HOME from environment valuables.');
return javaHomeEnv;
}
return null;
}
/// Finds the java binary that is used for all operations across the tool.
///
/// This comes from [findJavaHome] if that method returns non-null;
/// otherwise, it gets from searching PATH.
// TODO(andrewkolos): To prevent confusion when debugging Android-related
// issues (see https://github.com/flutter/flutter/issues/122609 for an example),
// this logic should be consistently followed by any Java-dependent operation
// across the the tool (building Android apps, interacting with the Android SDK, etc.).
// Currently, this consistency is fragile since the logic used for building
// Android apps exists independently of this method.
// See https://github.com/flutter/flutter/issues/124252.
static String? findJavaBinary({
required AndroidStudio? androidStudio,
required FileSystem fileSystem,
required OperatingSystemUtils operatingSystemUtils,
required Platform platform,
}) {
final String? javaHome = findJavaHome(
androidStudio: androidStudio,
fileSystem: fileSystem,
operatingSystemUtils: operatingSystemUtils,
platform: platform,
);
if (javaHome != null) {
return fileSystem.path.join(javaHome, 'bin', 'java');
}
// Fallback to PATH based lookup.
final String? pathJava = operatingSystemUtils.which(_javaExecutable)?.path;
if (pathJava != null) {
globals.printTrace('Using java from PATH.');
} else {
globals.printTrace('Could not find java path.');
}
return pathJava;
}
// Returns a user visible String that says the tool failed to parse
// the version of java along with the output.
static String _formatJavaVersionWarning(String javaVersionRaw) {
return 'Could not parse java version from: \n'
'$javaVersionRaw \n'
'If there is a version please look for an existing bug '
'https://github.com/flutter/flutter/issues/'
' and if one does not exist file a new issue.';
}
Map<String, String>? _sdkManagerEnv;
/// Returns an environment with the Java folder added to PATH for use in calling
/// Java-based Android SDK commands such as sdkmanager and avdmanager.
Map<String, String> get sdkManagerEnv {
if (_sdkManagerEnv == null) {
// If we can locate Java, then add it to the path used to run the Android SDK manager.
_sdkManagerEnv = <String, String>{};
final String? javaBinary = findJavaBinary(
androidStudio: globals.androidStudio,
fileSystem: globals.fs,
operatingSystemUtils: globals.os,
platform: globals.platform,
);
if (javaBinary != null && globals.platform.environment['PATH'] != null) {
_sdkManagerEnv!['PATH'] = globals.fs.path.dirname(javaBinary) +
globals.os.pathVarSeparator +
globals.platform.environment['PATH']!;
}
}
return _sdkManagerEnv!;
}
/// Returns the version of the Android SDK manager tool or null if not found. /// Returns the version of the Android SDK manager tool or null if not found.
String? get sdkManagerVersion { String? get sdkManagerVersion {
if (sdkManagerPath == null || !globals.processManager.canRun(sdkManagerPath)) { if (sdkManagerPath == null || !globals.processManager.canRun(sdkManagerPath)) {
...@@ -419,7 +577,7 @@ class AndroidSdk { ...@@ -419,7 +577,7 @@ class AndroidSdk {
} }
final RunResult result = globals.processUtils.runSync( final RunResult result = globals.processUtils.runSync(
<String>[sdkManagerPath!, '--version'], <String>[sdkManagerPath!, '--version'],
environment: _java?.environment, environment: sdkManagerEnv,
); );
if (result.exitCode != 0) { if (result.exitCode != 0) {
globals.printTrace('sdkmanager --version failed: exitCode: ${result.exitCode} stdout: ${result.stdout} stderr: ${result.stderr}'); globals.printTrace('sdkmanager --version failed: exitCode: ${result.exitCode} stdout: ${result.stdout} stderr: ${result.stderr}');
......
...@@ -11,6 +11,7 @@ import '../base/context.dart'; ...@@ -11,6 +11,7 @@ import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/os.dart';
import '../base/platform.dart'; import '../base/platform.dart';
import '../base/user_messages.dart' hide userMessages; import '../base/user_messages.dart' hide userMessages;
import '../base/version.dart'; import '../base/version.dart';
...@@ -19,7 +20,6 @@ import '../doctor_validator.dart'; ...@@ -19,7 +20,6 @@ import '../doctor_validator.dart';
import '../features.dart'; import '../features.dart';
import 'android_sdk.dart'; import 'android_sdk.dart';
import 'android_studio.dart'; import 'android_studio.dart';
import 'java.dart';
const int kAndroidSdkMinVersion = 29; const int kAndroidSdkMinVersion = 29;
final Version kAndroidJavaMinVersion = Version(1, 8, 0); final Version kAndroidJavaMinVersion = Version(1, 8, 0);
...@@ -86,6 +86,12 @@ class AndroidValidator extends DoctorValidator { ...@@ -86,6 +86,12 @@ class AndroidValidator extends DoctorValidator {
_androidStudio = androidStudio, _androidStudio = androidStudio,
_fileSystem = fileSystem, _fileSystem = fileSystem,
_logger = logger, _logger = logger,
_operatingSystemUtils = OperatingSystemUtils(
fileSystem: fileSystem,
logger: logger,
platform: platform,
processManager: processManager,
),
_platform = platform, _platform = platform,
_processManager = processManager, _processManager = processManager,
_userMessages = userMessages, _userMessages = userMessages,
...@@ -95,6 +101,7 @@ class AndroidValidator extends DoctorValidator { ...@@ -95,6 +101,7 @@ class AndroidValidator extends DoctorValidator {
final AndroidStudio? _androidStudio; final AndroidStudio? _androidStudio;
final FileSystem _fileSystem; final FileSystem _fileSystem;
final Logger _logger; final Logger _logger;
final OperatingSystemUtils _operatingSystemUtils;
final Platform _platform; final Platform _platform;
final ProcessManager _processManager; final ProcessManager _processManager;
final UserMessages _userMessages; final UserMessages _userMessages;
...@@ -131,8 +138,6 @@ class AndroidValidator extends DoctorValidator { ...@@ -131,8 +138,6 @@ class AndroidValidator extends DoctorValidator {
} }
String? javaVersionText; String? javaVersionText;
try { try {
// TODO(andrewkolos): Use Java class to find version instead of using duplicate
// code. See https://github.com/flutter/flutter/issues/124252.
_logger.printTrace('java -version'); _logger.printTrace('java -version');
final ProcessResult result = await _processManager.run(<String>[javaBinary, '-version']); final ProcessResult result = await _processManager.run(<String>[javaBinary, '-version']);
if (result.exitCode == 0) { if (result.exitCode == 0) {
...@@ -235,13 +240,12 @@ class AndroidValidator extends DoctorValidator { ...@@ -235,13 +240,12 @@ class AndroidValidator extends DoctorValidator {
_task = 'Finding Java binary'; _task = 'Finding Java binary';
// Now check for the JDK. // Now check for the JDK.
final String? javaBinary = Java.find( final String? javaBinary = AndroidSdk.findJavaBinary(
logger: _logger,
androidStudio: _androidStudio, androidStudio: _androidStudio,
fileSystem: _fileSystem, fileSystem: _fileSystem,
operatingSystemUtils: _operatingSystemUtils,
platform: _platform, platform: _platform,
processManager: _processManager, );
)?.binaryPath;
if (javaBinary == null) { if (javaBinary == null) {
messages.add(ValidationMessage.error(_userMessages.androidMissingJdk)); messages.add(ValidationMessage.error(_userMessages.androidMissingJdk));
return ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText); return ValidationResult(ValidationType.partial, messages, statusInfo: sdkVersionText);
...@@ -262,18 +266,18 @@ class AndroidValidator extends DoctorValidator { ...@@ -262,18 +266,18 @@ class AndroidValidator extends DoctorValidator {
/// SDK have been accepted. /// SDK have been accepted.
class AndroidLicenseValidator extends DoctorValidator { class AndroidLicenseValidator extends DoctorValidator {
AndroidLicenseValidator({ AndroidLicenseValidator({
required Java? java,
required AndroidSdk? androidSdk, required AndroidSdk? androidSdk,
required Platform platform, required Platform platform,
required OperatingSystemUtils operatingSystemUtils,
required FileSystem fileSystem, required FileSystem fileSystem,
required ProcessManager processManager, required ProcessManager processManager,
required Logger logger, required Logger logger,
required AndroidStudio? androidStudio, required AndroidStudio? androidStudio,
required Stdio stdio, required Stdio stdio,
required UserMessages userMessages, required UserMessages userMessages,
}) : _java = java, }) : _androidSdk = androidSdk,
_androidSdk = androidSdk,
_platform = platform, _platform = platform,
_operatingSystemUtils = operatingSystemUtils,
_fileSystem = fileSystem, _fileSystem = fileSystem,
_processManager = processManager, _processManager = processManager,
_logger = logger, _logger = logger,
...@@ -282,10 +286,10 @@ class AndroidLicenseValidator extends DoctorValidator { ...@@ -282,10 +286,10 @@ class AndroidLicenseValidator extends DoctorValidator {
_userMessages = userMessages, _userMessages = userMessages,
super('Android license subvalidator'); super('Android license subvalidator');
final Java? _java;
final AndroidSdk? _androidSdk; final AndroidSdk? _androidSdk;
final AndroidStudio? _androidStudio; final AndroidStudio? _androidStudio;
final Stdio _stdio; final Stdio _stdio;
final OperatingSystemUtils _operatingSystemUtils;
final Platform _platform; final Platform _platform;
final FileSystem _fileSystem; final FileSystem _fileSystem;
final ProcessManager _processManager; final ProcessManager _processManager;
...@@ -326,13 +330,12 @@ class AndroidLicenseValidator extends DoctorValidator { ...@@ -326,13 +330,12 @@ class AndroidLicenseValidator extends DoctorValidator {
} }
Future<bool> _checkJavaVersionNoOutput() async { Future<bool> _checkJavaVersionNoOutput() async {
final String? javaBinary = Java.find( final String? javaBinary = AndroidSdk.findJavaBinary(
logger: _logger,
androidStudio: _androidStudio, androidStudio: _androidStudio,
fileSystem: _fileSystem, fileSystem: _fileSystem,
operatingSystemUtils: _operatingSystemUtils,
platform: _platform, platform: _platform,
processManager: _processManager, );
)?.binaryPath;
if (javaBinary == null) { if (javaBinary == null) {
return false; return false;
} }
...@@ -384,7 +387,7 @@ class AndroidLicenseValidator extends DoctorValidator { ...@@ -384,7 +387,7 @@ class AndroidLicenseValidator extends DoctorValidator {
try { try {
final Process process = await _processManager.start( final Process process = await _processManager.start(
<String>[_androidSdk!.sdkManagerPath!, '--licenses'], <String>[_androidSdk!.sdkManagerPath!, '--licenses'],
environment: _java?.environment, environment: _androidSdk!.sdkManagerEnv,
); );
process.stdin.write('n\n'); process.stdin.write('n\n');
// We expect logcat streams to occasionally contain invalid utf-8, // We expect logcat streams to occasionally contain invalid utf-8,
...@@ -424,7 +427,7 @@ class AndroidLicenseValidator extends DoctorValidator { ...@@ -424,7 +427,7 @@ class AndroidLicenseValidator extends DoctorValidator {
try { try {
final Process process = await _processManager.start( final Process process = await _processManager.start(
<String>[_androidSdk!.sdkManagerPath!, '--licenses'], <String>[_androidSdk!.sdkManagerPath!, '--licenses'],
environment: _java?.environment, environment: _androidSdk!.sdkManagerEnv,
); );
// The real stdin will never finish streaming. Pipe until the child process // The real stdin will never finish streaming. Pipe until the child process
......
...@@ -147,7 +147,8 @@ class AndroidGradleBuilder implements AndroidBuilder { ...@@ -147,7 +147,8 @@ class AndroidGradleBuilder implements AndroidBuilder {
_gradleUtils = gradleUtils, _gradleUtils = gradleUtils,
_androidStudio = androidStudio, _androidStudio = androidStudio,
_fileSystemUtils = FileSystemUtils(fileSystem: fileSystem, platform: platform), _fileSystemUtils = FileSystemUtils(fileSystem: fileSystem, platform: platform),
_processUtils = ProcessUtils(logger: logger, processManager: processManager); _processUtils = ProcessUtils(logger: logger, processManager: processManager),
_platform = platform;
final Logger _logger; final Logger _logger;
final ProcessUtils _processUtils; final ProcessUtils _processUtils;
...@@ -157,6 +158,7 @@ class AndroidGradleBuilder implements AndroidBuilder { ...@@ -157,6 +158,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
final GradleUtils _gradleUtils; final GradleUtils _gradleUtils;
final FileSystemUtils _fileSystemUtils; final FileSystemUtils _fileSystemUtils;
final AndroidStudio? _androidStudio; final AndroidStudio? _androidStudio;
final Platform _platform;
/// Builds the AAR and POM files for the current Flutter module or plugin. /// Builds the AAR and POM files for the current Flutter module or plugin.
@override @override
...@@ -266,7 +268,11 @@ class AndroidGradleBuilder implements AndroidBuilder { ...@@ -266,7 +268,11 @@ class AndroidGradleBuilder implements AndroidBuilder {
AndroidStudioJavaGradleConflictMigration(_logger, AndroidStudioJavaGradleConflictMigration(_logger,
project: project.android, project: project.android,
androidStudio: _androidStudio, androidStudio: _androidStudio,
java: globals.java) fileSystem: _fileSystem,
processUtils: _processUtils,
platform: _platform,
os: globals.os,
androidSdk: globals.androidSdk)
, ,
]; ];
...@@ -422,7 +428,7 @@ class AndroidGradleBuilder implements AndroidBuilder { ...@@ -422,7 +428,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
..start(); ..start();
int exitCode = 1; int exitCode = 1;
try { try {
final String? javaHome = globals.java?.javaHome; final String? javaHome = globals.androidSdk?.javaHome;
exitCode = await _processUtils.stream( exitCode = await _processUtils.stream(
command, command,
workingDirectory: project.android.hostAppGradleRoot.path, workingDirectory: project.android.hostAppGradleRoot.path,
...@@ -692,7 +698,7 @@ class AndroidGradleBuilder implements AndroidBuilder { ...@@ -692,7 +698,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
..start(); ..start();
RunResult result; RunResult result;
try { try {
final String? javaHome = globals.java?.javaHome; final String? javaHome = globals.androidSdk?.javaHome;
result = await _processUtils.run( result = await _processUtils.run(
command, command,
workingDirectory: project.android.hostAppGradleRoot.path, workingDirectory: project.android.hostAppGradleRoot.path,
...@@ -745,7 +751,7 @@ class AndroidGradleBuilder implements AndroidBuilder { ...@@ -745,7 +751,7 @@ class AndroidGradleBuilder implements AndroidBuilder {
..start(); ..start();
RunResult result; RunResult result;
try { try {
final String? javaHome = globals.java?.javaHome; final String? javaHome = globals.androidSdk?.javaHome;
result = await _processUtils.run( result = await _processUtils.run(
command, command,
workingDirectory: project.android.hostAppGradleRoot.path, workingDirectory: project.android.hostAppGradleRoot.path,
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:process/process.dart';
import '../base/file_system.dart';
import '../base/logger.dart';
import '../base/os.dart';
import '../base/platform.dart';
import '../base/process.dart';
import 'android_studio.dart';
const String _javaHomeEnvironmentVariable = 'JAVA_HOME';
const String _kJavaExecutable = 'java';
/// Represents an installation of Java.
class Java {
Java({
required this.javaHome,
required this.binaryPath,
required Logger logger,
required FileSystem fileSystem,
required OperatingSystemUtils os,
required Platform platform,
required ProcessManager processManager,
}): _logger = logger,
_fileSystem = fileSystem,
_os = os,
_platform = platform,
_processManager = processManager,
_processUtils = ProcessUtils(processManager: processManager, logger: logger);
/// Finds the Java runtime environment that should be used for all java-dependent
/// operations across the tool.
///
/// This searches for Java in the following places, in order:
///
/// 1. the runtime environment bundled with Android Studio;
/// 2. the runtime environment found in the JAVA_HOME env variable, if set; or
/// 3. the java binary found on PATH.
///
/// Returns null if no java binary could be found.
// TODO(andrewkolos): To prevent confusion when debugging Android-related
// issues (see https://github.com/flutter/flutter/issues/122609 for an example),
// this logic should be consistently followed by any Java-dependent operation
// across the the tool (building Android apps, interacting with the Android SDK, etc.).
// Currently, this consistency is fragile since the logic used for building
// Android apps exists independently of this method.
// See https://github.com/flutter/flutter/issues/124252.
static Java? find({
required AndroidStudio? androidStudio,
required Logger logger,
required FileSystem fileSystem,
required Platform platform,
required ProcessManager processManager,
}) {
final OperatingSystemUtils os = OperatingSystemUtils(
fileSystem: fileSystem,
logger: logger,
platform: platform,
processManager: processManager
);
final String? home = _findJavaHome(
logger: logger,
androidStudio: androidStudio,
platform: platform
);
final String? binary = _findJavaBinary(
logger: logger,
javaHome: home,
fileSystem: fileSystem,
operatingSystemUtils: os,
platform: platform
);
if (binary == null) {
return null;
}
return Java(
javaHome: home,
binaryPath: binary,
logger: logger,
fileSystem: fileSystem,
os: os,
platform: platform,
processManager: processManager,
);
}
/// The path of the runtime's home directory.
///
/// This should only be used for logging and validation purposes.
/// If you need to set JAVA_HOME when starting a process, consider
/// using [environment] instead.
/// If you need to inspect the files of the runtime, considering adding
/// a new method to this class instead.
final String? javaHome;
/// The path of the runtime's java binary.
///
/// This should be only used for logging and validation purposes.
/// If you need to invoke the binary directly, consider adding a new method
/// to this class instead.
final String binaryPath;
final Logger _logger;
final FileSystem _fileSystem;
final OperatingSystemUtils _os;
final Platform _platform;
final ProcessManager _processManager;
final ProcessUtils _processUtils;
/// Returns an environment variable map with
/// 1. JAVA_HOME set if this object has a known home directory, and
/// 2. The java binary folder appended onto PATH, if the binary location is known.
///
/// This map should be used as the environment when invoking any Java-dependent
/// processes, such as Gradle or Android SDK tools (avdmanager, sdkmanager, etc.)
Map<String, String> get environment {
return <String, String>{
if (javaHome != null) _javaHomeEnvironmentVariable: javaHome!,
'PATH': _fileSystem.path.dirname(binaryPath) +
_os.pathVarSeparator +
_platform.environment['PATH']!,
};
}
/// Returns the version of java in the format \d(.\d)+(.\d)+
/// Returns null if version could not be determined.
late final JavaVersion? version = (() {
final RunResult result = _processUtils.runSync(
<String>[binaryPath, '--version'],
environment: environment,
);
if (result.exitCode != 0) {
_logger.printTrace('java --version failed: exitCode: ${result.exitCode}'
' stdout: ${result.stdout} stderr: ${result.stderr}');
}
return JavaVersion.tryParseFromJavaOutput(result.stdout, logger: _logger);
})();
bool canRun() {
return _processManager.canRun(binaryPath);
}
}
String? _findJavaHome({
required Logger logger,
required AndroidStudio? androidStudio,
required Platform platform,
}) {
final String? androidStudioJavaPath = androidStudio?.javaPath;
if (androidStudioJavaPath != null) {
return androidStudioJavaPath;
}
final String? javaHomeEnv = platform.environment[_javaHomeEnvironmentVariable];
if (javaHomeEnv != null) {
return javaHomeEnv;
}
return null;
}
String? _findJavaBinary({
required Logger logger,
required String? javaHome,
required FileSystem fileSystem,
required OperatingSystemUtils operatingSystemUtils,
required Platform platform,
}) {
if (javaHome != null) {
return fileSystem.path.join(javaHome, 'bin', 'java');
}
// Fallback to PATH based lookup.
return operatingSystemUtils.which(_kJavaExecutable)?.path;
}
// Returns a user visible String that says the tool failed to parse
// the version of java along with the output.
String _formatJavaVersionWarning(String javaVersionRaw) {
return 'Could not parse java version from: \n'
'$javaVersionRaw \n'
'If there is a version please look for an existing bug '
'https://github.com/flutter/flutter/issues/ '
'and if one does not exist file a new issue.';
}
class JavaVersion {
JavaVersion({
required this.longText,
required this.number
});
/// Typically the first line of the output from `java --version`.
/// For example, `"openjdk 19.0.2 2023-01-17"`.
final String longText;
/// The version number. For example, `"19.0.2."`.
final String number;
/// Extracts JDK version from the output of java --version.
static JavaVersion? tryParseFromJavaOutput(String rawVersionOutput, {
required Logger logger,
}) {
final List<String> versionLines = rawVersionOutput.split('\n');
final String longText = versionLines.length >= 2 ? versionLines[1] : versionLines[0];
// The contents that matter come in the format '11.0.18' or '1.8.0_202'.
final RegExp jdkVersionRegex = RegExp(r'\d+\.\d+(\.\d+(?:_\d+)?)?');
final Iterable<RegExpMatch> matches =
jdkVersionRegex.allMatches(rawVersionOutput);
if (matches.isEmpty) {
logger.printWarning(_formatJavaVersionWarning(rawVersionOutput));
return null;
}
final String? rawShortText = matches.first.group(0);
if (rawShortText == null || rawShortText.split('_').isEmpty) {
logger.printWarning(_formatJavaVersionWarning(rawVersionOutput));
return null;
}
// Trim away _d+ from versions 1.8 and below.
final String shortText = rawShortText.split('_').first;
return JavaVersion(longText: longText, number: shortText);
}
}
...@@ -5,12 +5,15 @@ ...@@ -5,12 +5,15 @@
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import '../../base/file_system.dart'; import '../../base/file_system.dart';
import '../../base/os.dart';
import '../../base/platform.dart';
import '../../base/process.dart';
import '../../base/project_migrator.dart'; import '../../base/project_migrator.dart';
import '../../base/version.dart'; import '../../base/version.dart';
import '../../project.dart'; import '../../project.dart';
import '../android_sdk.dart';
import '../android_studio.dart'; import '../android_studio.dart';
import '../gradle_utils.dart'; import '../gradle_utils.dart';
import '../java.dart';
// Android Studio 2022.2 "Flamingo" is the first to bundle a Java 17 JDK. // Android Studio 2022.2 "Flamingo" is the first to bundle a Java 17 JDK.
// Previous versions bundled a Java 11 JDK. // Previous versions bundled a Java 11 JDK.
...@@ -74,14 +77,25 @@ class AndroidStudioJavaGradleConflictMigration extends ProjectMigrator { ...@@ -74,14 +77,25 @@ class AndroidStudioJavaGradleConflictMigration extends ProjectMigrator {
super.logger, super.logger,
{required AndroidProject project, {required AndroidProject project,
AndroidStudio? androidStudio, AndroidStudio? androidStudio,
required Java? java, required FileSystem fileSystem,
required ProcessUtils processUtils,
required Platform platform,
required OperatingSystemUtils os,
AndroidSdk? androidSdk,
}) : _gradleWrapperPropertiesFile = getGradleWrapperFile(project.hostAppGradleRoot), }) : _gradleWrapperPropertiesFile = getGradleWrapperFile(project.hostAppGradleRoot),
_androidStudio = androidStudio, _androidStudio = androidStudio,
_java = java; _fileSystem = fileSystem,
_processUtils = processUtils,
_platform = platform,
_os = os,
_androidSdk = androidSdk;
final File _gradleWrapperPropertiesFile; final File _gradleWrapperPropertiesFile;
final AndroidStudio? _androidStudio; final AndroidStudio? _androidStudio;
final Java? _java; final FileSystem _fileSystem;
final ProcessUtils _processUtils;
final Platform _platform;
final OperatingSystemUtils _os;
final AndroidSdk? _androidSdk;
@override @override
void migrate() { void migrate() {
...@@ -99,7 +113,13 @@ class AndroidStudioJavaGradleConflictMigration extends ProjectMigrator { ...@@ -99,7 +113,13 @@ class AndroidStudioJavaGradleConflictMigration extends ProjectMigrator {
return; return;
} }
final String? javaVersionString = _java?.version?.number; final String? javaVersionString = _androidSdk?.getJavaVersion(
androidStudio: _androidStudio,
fileSystem: _fileSystem,
operatingSystemUtils: _os,
platform: _platform,
processUtils: _processUtils,
);
final Version? javaVersion = Version.parse(javaVersionString); final Version? javaVersion = Version.parse(javaVersionString);
if (javaVersion == null) { if (javaVersion == null) {
logger.printTrace(javaVersionNotFound); logger.printTrace(javaVersionNotFound);
......
...@@ -1360,7 +1360,6 @@ class EmulatorDomain extends Domain { ...@@ -1360,7 +1360,6 @@ class EmulatorDomain extends Domain {
EmulatorManager emulators = EmulatorManager( EmulatorManager emulators = EmulatorManager(
fileSystem: globals.fs, fileSystem: globals.fs,
logger: globals.logger, logger: globals.logger,
java: globals.java,
androidSdk: globals.androidSdk, androidSdk: globals.androidSdk,
processManager: globals.processManager, processManager: globals.processManager,
androidWorkflow: androidWorkflow!, androidWorkflow: androidWorkflow!,
......
...@@ -14,7 +14,6 @@ import 'android/android_studio.dart'; ...@@ -14,7 +14,6 @@ import 'android/android_studio.dart';
import 'android/android_workflow.dart'; import 'android/android_workflow.dart';
import 'android/gradle.dart'; import 'android/gradle.dart';
import 'android/gradle_utils.dart'; import 'android/gradle_utils.dart';
import 'android/java.dart';
import 'application_package.dart'; import 'application_package.dart';
import 'artifacts.dart'; import 'artifacts.dart';
import 'asset.dart'; import 'asset.dart';
...@@ -98,11 +97,11 @@ Future<T> runInContext<T>( ...@@ -98,11 +97,11 @@ Future<T> runInContext<T>(
androidStudio: globals.androidStudio, androidStudio: globals.androidStudio,
), ),
AndroidLicenseValidator: () => AndroidLicenseValidator( AndroidLicenseValidator: () => AndroidLicenseValidator(
operatingSystemUtils: globals.os,
platform: globals.platform, platform: globals.platform,
userMessages: globals.userMessages, userMessages: globals.userMessages,
processManager: globals.processManager, processManager: globals.processManager,
androidStudio: globals.androidStudio, androidStudio: globals.androidStudio,
java: globals.java,
androidSdk: globals.androidSdk, androidSdk: globals.androidSdk,
logger: globals.logger, logger: globals.logger,
fileSystem: globals.fs, fileSystem: globals.fs,
...@@ -217,7 +216,6 @@ Future<T> runInContext<T>( ...@@ -217,7 +216,6 @@ Future<T> runInContext<T>(
Doctor: () => Doctor(logger: globals.logger), Doctor: () => Doctor(logger: globals.logger),
DoctorValidatorsProvider: () => DoctorValidatorsProvider.defaultInstance, DoctorValidatorsProvider: () => DoctorValidatorsProvider.defaultInstance,
EmulatorManager: () => EmulatorManager( EmulatorManager: () => EmulatorManager(
java: globals.java,
androidSdk: globals.androidSdk, androidSdk: globals.androidSdk,
processManager: globals.processManager, processManager: globals.processManager,
logger: globals.logger, logger: globals.logger,
...@@ -255,13 +253,6 @@ Future<T> runInContext<T>( ...@@ -255,13 +253,6 @@ Future<T> runInContext<T>(
xcode: globals.xcode!, xcode: globals.xcode!,
platform: globals.platform, platform: globals.platform,
), ),
Java: () => Java.find(
androidStudio: globals.androidStudio,
logger: globals.logger,
fileSystem: globals.fs,
platform: globals.platform,
processManager: globals.processManager
),
LocalEngineLocator: () => LocalEngineLocator( LocalEngineLocator: () => LocalEngineLocator(
userMessages: userMessages, userMessages: userMessages,
logger: globals.logger, logger: globals.logger,
......
...@@ -10,7 +10,6 @@ import 'package:process/process.dart'; ...@@ -10,7 +10,6 @@ import 'package:process/process.dart';
import 'android/android_emulator.dart'; import 'android/android_emulator.dart';
import 'android/android_sdk.dart'; import 'android/android_sdk.dart';
import 'android/android_workflow.dart'; import 'android/android_workflow.dart';
import 'android/java.dart';
import 'base/context.dart'; import 'base/context.dart';
import 'base/file_system.dart'; import 'base/file_system.dart';
import 'base/logger.dart'; import 'base/logger.dart';
...@@ -23,14 +22,12 @@ EmulatorManager? get emulatorManager => context.get<EmulatorManager>(); ...@@ -23,14 +22,12 @@ EmulatorManager? get emulatorManager => context.get<EmulatorManager>();
/// A class to get all available emulators. /// A class to get all available emulators.
class EmulatorManager { class EmulatorManager {
EmulatorManager({ EmulatorManager({
required Java? java,
AndroidSdk? androidSdk, AndroidSdk? androidSdk,
required Logger logger, required Logger logger,
required ProcessManager processManager, required ProcessManager processManager,
required AndroidWorkflow androidWorkflow, required AndroidWorkflow androidWorkflow,
required FileSystem fileSystem, required FileSystem fileSystem,
}) : _java = java, }) : _androidSdk = androidSdk,
_androidSdk = androidSdk,
_processUtils = ProcessUtils(logger: logger, processManager: processManager), _processUtils = ProcessUtils(logger: logger, processManager: processManager),
_androidEmulators = AndroidEmulators( _androidEmulators = AndroidEmulators(
androidSdk: androidSdk, androidSdk: androidSdk,
...@@ -42,7 +39,6 @@ class EmulatorManager { ...@@ -42,7 +39,6 @@ class EmulatorManager {
_emulatorDiscoverers.add(_androidEmulators); _emulatorDiscoverers.add(_androidEmulators);
} }
final Java? _java;
final AndroidSdk? _androidSdk; final AndroidSdk? _androidSdk;
final AndroidEmulators _androidEmulators; final AndroidEmulators _androidEmulators;
final ProcessUtils _processUtils; final ProcessUtils _processUtils;
...@@ -156,7 +152,7 @@ class EmulatorManager { ...@@ -156,7 +152,7 @@ class EmulatorManager {
'-n', emulatorName, '-n', emulatorName,
'-k', sdkId, '-k', sdkId,
'-d', device, '-d', device,
], environment: _java?.environment, ], environment: _androidSdk?.sdkManagerEnv,
); );
return CreateEmulatorResult( return CreateEmulatorResult(
emulatorName, emulatorName,
...@@ -179,7 +175,7 @@ class EmulatorManager { ...@@ -179,7 +175,7 @@ class EmulatorManager {
'-c', '-c',
]; ];
final RunResult runResult = await _processUtils.run(args, final RunResult runResult = await _processUtils.run(args,
environment: _java?.environment); environment: _androidSdk?.sdkManagerEnv);
if (runResult.exitCode != 0) { if (runResult.exitCode != 0) {
return null; return null;
} }
...@@ -209,7 +205,7 @@ class EmulatorManager { ...@@ -209,7 +205,7 @@ class EmulatorManager {
'-n', 'temp', '-n', 'temp',
]; ];
final RunResult runResult = await _processUtils.run(args, final RunResult runResult = await _processUtils.run(args,
environment: _java?.environment); environment: _androidSdk?.sdkManagerEnv);
// Get the list of IDs that match our criteria // Get the list of IDs that match our criteria
final List<String> availableIDs = runResult.stderr final List<String> availableIDs = runResult.stderr
......
...@@ -9,7 +9,6 @@ import 'package:unified_analytics/unified_analytics.dart'; ...@@ -9,7 +9,6 @@ import 'package:unified_analytics/unified_analytics.dart';
import 'android/android_sdk.dart'; import 'android/android_sdk.dart';
import 'android/android_studio.dart'; import 'android/android_studio.dart';
import 'android/gradle_utils.dart'; import 'android/gradle_utils.dart';
import 'android/java.dart';
import 'artifacts.dart'; import 'artifacts.dart';
import 'base/bot_detector.dart'; import 'base/bot_detector.dart';
import 'base/config.dart'; import 'base/config.dart';
...@@ -309,9 +308,3 @@ final RegExp kVMServiceMessageRegExp = RegExp(r'The Dart VM service is listening ...@@ -309,9 +308,3 @@ final RegExp kVMServiceMessageRegExp = RegExp(r'The Dart VM service is listening
// The official tool no longer allows non-null safe builds. This can be // The official tool no longer allows non-null safe builds. This can be
// overridden in other clients. // overridden in other clients.
NonNullSafeBuilds get nonNullSafeBuilds => context.get<NonNullSafeBuilds>() ?? NonNullSafeBuilds.notAllowed; NonNullSafeBuilds get nonNullSafeBuilds => context.get<NonNullSafeBuilds>() ?? NonNullSafeBuilds.notAllowed;
/// Contains information about the JRE/JDK to use for Java-dependent operations.
///
/// A value of [null] indicates that no installation of java could be found on
/// the host machine.
Java? get java => context.get<Java>();
...@@ -568,7 +568,13 @@ class AndroidProject extends FlutterProjectPlatform { ...@@ -568,7 +568,13 @@ class AndroidProject extends FlutterProjectPlatform {
hostAppGradleRoot, globals.logger, globals.processManager); hostAppGradleRoot, globals.logger, globals.processManager);
final String? agpVersion = final String? agpVersion =
gradle.getAgpVersion(hostAppGradleRoot, globals.logger); gradle.getAgpVersion(hostAppGradleRoot, globals.logger);
final String? javaVersion = globals.java?.version?.number; final String? javaVersion = globals.androidSdk?.getJavaVersion(
androidStudio: globals.androidStudio,
fileSystem: globals.fs,
operatingSystemUtils: globals.os,
platform: globals.platform,
processUtils: globals.processUtils,
);
// Assume valid configuration. // Assume valid configuration.
String description = validJavaGradleAgpString; String description = validJavaGradleAgpString;
......
...@@ -6,7 +6,6 @@ import 'dart:async'; ...@@ -6,7 +6,6 @@ import 'dart:async';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_device.dart'; import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/android/java.dart';
import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/application_package.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
...@@ -21,7 +20,6 @@ import 'package:test/fake.dart'; ...@@ -21,7 +20,6 @@ import 'package:test/fake.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/fake_devices.dart'; import '../../src/fake_devices.dart';
import '../../src/fakes.dart';
void main() { void main() {
Daemon? daemon; Daemon? daemon;
...@@ -106,8 +104,6 @@ void main() { ...@@ -106,8 +104,6 @@ void main() {
final bool supportsRuntimeMode = await device.supportsRuntimeMode(BuildMode.release); final bool supportsRuntimeMode = await device.supportsRuntimeMode(BuildMode.release);
expect(fakeDevice.supportsRuntimeModeCalledBuildMode, BuildMode.release); expect(fakeDevice.supportsRuntimeModeCalledBuildMode, BuildMode.release);
expect(supportsRuntimeMode, true); expect(supportsRuntimeMode, true);
}, overrides: <Type, Generator>{
Java: () => FakeJava(),
}); });
testUsingContext('redirects logs', () async { testUsingContext('redirects logs', () async {
...@@ -187,7 +183,6 @@ void main() { ...@@ -187,7 +183,6 @@ void main() {
expect(fakeDevice.stopAppPackage, applicationPackage); expect(fakeDevice.stopAppPackage, applicationPackage);
expect(stopAppResult, true); expect(stopAppResult, true);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Java: () => FakeJava(),
ApplicationPackageFactory: () => applicationPackageFactory, ApplicationPackageFactory: () => applicationPackageFactory,
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
...@@ -217,7 +212,6 @@ void main() { ...@@ -217,7 +212,6 @@ void main() {
expect(await screenshotOutputFile.readAsBytes(), screenshot); expect(await screenshotOutputFile.readAsBytes(), screenshot);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Java: () => FakeJava(),
FileSystem: () => memoryFileSystem, FileSystem: () => memoryFileSystem,
ProcessManager: () => fakeProcessManager, ProcessManager: () => fakeProcessManager,
}); });
......
...@@ -447,6 +447,9 @@ class FakeAndroidSdk extends Fake implements AndroidSdk { ...@@ -447,6 +447,9 @@ class FakeAndroidSdk extends Fake implements AndroidSdk {
@override @override
final Directory directory; final Directory directory;
@override
String? get javaHome => 'java';
} }
class FakeAndroidStudio extends Fake implements AndroidStudio { class FakeAndroidStudio extends Fake implements AndroidStudio {
......
...@@ -230,4 +230,7 @@ class FakeAndroidSdk extends Fake implements AndroidSdk { ...@@ -230,4 +230,7 @@ class FakeAndroidSdk extends Fake implements AndroidSdk {
@override @override
final Directory directory; final Directory directory;
@override
String? get javaHome => 'java';
} }
...@@ -389,6 +389,8 @@ class FakeDoctor extends Fake implements Doctor { ...@@ -389,6 +389,8 @@ class FakeDoctor extends Fake implements Doctor {
} }
} }
class FakeAndroidStudio extends Fake implements AndroidStudio {}
class FakeClock extends Fake implements SystemClock { class FakeClock extends Fake implements SystemClock {
List<int> times = <int>[]; List<int> times = <int>[];
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/android/android_studio.dart'; import 'package:flutter_tools/src/android/android_studio.dart';
import 'package:flutter_tools/src/android/gradle_utils.dart'; import 'package:flutter_tools/src/android/gradle_utils.dart';
import 'package:flutter_tools/src/android/java.dart';
import 'package:flutter_tools/src/android/migrations/android_studio_java_gradle_conflict_migration.dart'; import 'package:flutter_tools/src/android/migrations/android_studio_java_gradle_conflict_migration.dart';
import 'package:flutter_tools/src/android/migrations/top_level_gradle_build_file_migration.dart'; import 'package:flutter_tools/src/android/migrations/top_level_gradle_build_file_migration.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
...@@ -19,7 +19,6 @@ import 'package:test/fake.dart'; ...@@ -19,7 +19,6 @@ import 'package:test/fake.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/fakes.dart';
const String otherGradleVersionWrapper = r''' const String otherGradleVersionWrapper = r'''
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
...@@ -47,9 +46,6 @@ zipStorePath=wrapper/dists ...@@ -47,9 +46,6 @@ zipStorePath=wrapper/dists
final Version androidStudioDolphin = Version(2021, 3, 1); final Version androidStudioDolphin = Version(2021, 3, 1);
final JavaVersion _javaVersion17 = JavaVersion(longText: 'openjdk 17.0.2', number: '17.0.2');
final JavaVersion _javaVersion16 = JavaVersion(longText: 'openjdk 16.0.2', number: '16.0.2');
void main() { void main() {
group('Android migration', () { group('Android migration', () {
group('migrate the Gradle "clean" task to lazy declaration', () { group('migrate the Gradle "clean" task to lazy declaration', () {
...@@ -140,10 +136,14 @@ tasks.register("clean", Delete) { ...@@ -140,10 +136,14 @@ tasks.register("clean", Delete) {
testWithoutContext('skipped if files are missing', () { testWithoutContext('skipped if files are missing', () {
final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration( final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration(
java: FakeJava(version: _javaVersion17),
bufferLogger, bufferLogger,
project: project, project: project,
androidStudio: FakeAndroidStudio(version: androidStudioDolphin), androidStudio: FakeAndroidStudio(version: androidStudioDolphin),
fileSystem: FakeFileSystem(),
processUtils: FakeProcessUtils(),
platform: FakePlatform(),
os: FakeOperatingSystemUtils(),
androidSdk: FakeAndroidSdk(javaVersion: '17'),
); );
migration.migrate(); migration.migrate();
expect(gradleWrapperPropertiesFile.existsSync(), isFalse); expect(gradleWrapperPropertiesFile.existsSync(), isFalse);
...@@ -153,9 +153,13 @@ tasks.register("clean", Delete) { ...@@ -153,9 +153,13 @@ tasks.register("clean", Delete) {
testWithoutContext('skipped if android studio is null', () { testWithoutContext('skipped if android studio is null', () {
final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration( final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration(
java: FakeJava(version: _javaVersion17),
bufferLogger, bufferLogger,
project: project, project: project,
fileSystem: FakeFileSystem(),
processUtils: FakeProcessUtils(),
platform: FakePlatform(),
os: FakeOperatingSystemUtils(),
androidSdk: FakeAndroidSdk(javaVersion: '17'),
); );
gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate); gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate);
migration.migrate(); migration.migrate();
...@@ -166,10 +170,14 @@ tasks.register("clean", Delete) { ...@@ -166,10 +170,14 @@ tasks.register("clean", Delete) {
testWithoutContext('skipped if android studio version is null', () { testWithoutContext('skipped if android studio version is null', () {
final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration( final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration(
java: FakeJava(version: _javaVersion17),
bufferLogger, bufferLogger,
project: project, project: project,
androidStudio: FakeAndroidStudio(version: null), androidStudio: FakeAndroidStudio(version: null),
fileSystem: FakeFileSystem(),
processUtils: FakeProcessUtils(),
platform: FakePlatform(),
os: FakeOperatingSystemUtils(),
androidSdk: FakeAndroidSdk(javaVersion: '17'),
); );
gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate); gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate);
migration.migrate(); migration.migrate();
...@@ -180,10 +188,14 @@ tasks.register("clean", Delete) { ...@@ -180,10 +188,14 @@ tasks.register("clean", Delete) {
testWithoutContext('skipped if error is encountered in migrate()', () { testWithoutContext('skipped if error is encountered in migrate()', () {
final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration( final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration(
java: FakeErroringJava(),
bufferLogger, bufferLogger,
project: project, project: project,
androidStudio: FakeAndroidStudio(version: androidStudioFlamingo), androidStudio: FakeAndroidStudio(version: androidStudioFlamingo),
fileSystem: FakeFileSystem(),
processUtils: FakeProcessUtils(),
platform: FakePlatform(),
os: FakeOperatingSystemUtils(),
androidSdk: FakeErroringAndroidSdk(),
); );
gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate); gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate);
migration.migrate(); migration.migrate();
...@@ -194,10 +206,14 @@ tasks.register("clean", Delete) { ...@@ -194,10 +206,14 @@ tasks.register("clean", Delete) {
testWithoutContext('skipped if android studio version is less than flamingo', () { testWithoutContext('skipped if android studio version is less than flamingo', () {
final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration( final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration(
java: FakeJava(),
bufferLogger, bufferLogger,
project: project, project: project,
androidStudio: FakeAndroidStudio(version: androidStudioDolphin), androidStudio: FakeAndroidStudio(version: androidStudioDolphin),
fileSystem: FakeFileSystem(),
processUtils: FakeProcessUtils(),
platform: FakePlatform(),
os: FakeOperatingSystemUtils(),
androidSdk: FakeAndroidSdk(javaVersion: '17'),
); );
gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate); gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate);
migration.migrate(); migration.migrate();
...@@ -207,10 +223,14 @@ tasks.register("clean", Delete) { ...@@ -207,10 +223,14 @@ tasks.register("clean", Delete) {
testWithoutContext('skipped if bundled java version is less than 17', () { testWithoutContext('skipped if bundled java version is less than 17', () {
final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration( final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration(
java: FakeJava(version: _javaVersion16),
bufferLogger, bufferLogger,
project: project, project: project,
androidStudio: FakeAndroidStudio(version: androidStudioFlamingo), androidStudio: FakeAndroidStudio(version: androidStudioFlamingo),
fileSystem: FakeFileSystem(),
processUtils: FakeProcessUtils(),
platform: FakePlatform(),
os: FakeOperatingSystemUtils(),
androidSdk: FakeAndroidSdk(javaVersion: '16'),
); );
gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate); gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate);
migration.migrate(); migration.migrate();
...@@ -221,10 +241,14 @@ tasks.register("clean", Delete) { ...@@ -221,10 +241,14 @@ tasks.register("clean", Delete) {
testWithoutContext('nothing is changed if gradle version not one that was ' testWithoutContext('nothing is changed if gradle version not one that was '
'used by flutter create', () { 'used by flutter create', () {
final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration( final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration(
java: FakeJava(version: _javaVersion17),
bufferLogger, bufferLogger,
project: project, project: project,
androidStudio: FakeAndroidStudio(version: androidStudioFlamingo), androidStudio: FakeAndroidStudio(version: androidStudioFlamingo),
fileSystem: FakeFileSystem(),
processUtils: FakeProcessUtils(),
platform: FakePlatform(),
os: FakeOperatingSystemUtils(),
androidSdk: FakeAndroidSdk(javaVersion: '17'),
); );
gradleWrapperPropertiesFile.writeAsStringSync(otherGradleVersionWrapper); gradleWrapperPropertiesFile.writeAsStringSync(otherGradleVersionWrapper);
migration.migrate(); migration.migrate();
...@@ -235,10 +259,14 @@ tasks.register("clean", Delete) { ...@@ -235,10 +259,14 @@ tasks.register("clean", Delete) {
testWithoutContext('change is made with one of the specific gradle versions' testWithoutContext('change is made with one of the specific gradle versions'
' we migrate for', () { ' we migrate for', () {
final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration( final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration(
java: FakeJava(version: _javaVersion17),
bufferLogger, bufferLogger,
project: project, project: project,
androidStudio: FakeAndroidStudio(version: androidStudioFlamingo), androidStudio: FakeAndroidStudio(version: androidStudioFlamingo),
fileSystem: FakeFileSystem(),
processUtils: FakeProcessUtils(),
platform: FakePlatform(),
os: FakeOperatingSystemUtils(),
androidSdk: FakeAndroidSdk(javaVersion: '17'),
); );
gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate); gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate);
migration.migrate(); migration.migrate();
...@@ -250,10 +278,14 @@ tasks.register("clean", Delete) { ...@@ -250,10 +278,14 @@ tasks.register("clean", Delete) {
testWithoutContext('change is not made when opt out flag is set', () { testWithoutContext('change is not made when opt out flag is set', () {
final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration( final AndroidStudioJavaGradleConflictMigration migration = AndroidStudioJavaGradleConflictMigration(
java: FakeJava(version: _javaVersion17),
bufferLogger, bufferLogger,
project: project, project: project,
androidStudio: FakeAndroidStudio(version: androidStudioFlamingo), androidStudio: FakeAndroidStudio(version: androidStudioFlamingo),
fileSystem: FakeFileSystem(),
processUtils: FakeProcessUtils(),
platform: FakePlatform(),
os: FakeOperatingSystemUtils(),
androidSdk: FakeAndroidSdk(javaVersion: '17'),
); );
gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate + optOutFlag); gradleWrapperPropertiesFile.writeAsStringSync(gradleWrapperToMigrate + optOutFlag);
migration.migrate(); migration.migrate();
...@@ -282,10 +314,37 @@ class FakeAndroidStudio extends Fake implements AndroidStudio { ...@@ -282,10 +314,37 @@ class FakeAndroidStudio extends Fake implements AndroidStudio {
Version? get version => _version; Version? get version => _version;
} }
class FakeErroringJava extends FakeJava { class FakeAndroidSdk extends Fake implements AndroidSdk {
FakeAndroidSdk({required String javaVersion}) {
_javaVersion = javaVersion;
}
late String _javaVersion;
@override
String? getJavaVersion({
required AndroidStudio? androidStudio,
required FileSystem fileSystem,
required OperatingSystemUtils operatingSystemUtils,
required Platform platform,
required ProcessUtils processUtils,
}) {
return _javaVersion;
}
}
class FakeErroringAndroidSdk extends Fake implements AndroidSdk {
FakeErroringAndroidSdk();
@override @override
JavaVersion get version { String? getJavaVersion({
throw Exception('How did this happen?'); required AndroidStudio? androidStudio,
required FileSystem fileSystem,
required OperatingSystemUtils operatingSystemUtils,
required Platform platform,
required ProcessUtils processUtils,
}) {
throw const FileSystemException();
} }
} }
......
...@@ -122,7 +122,6 @@ void main() { ...@@ -122,7 +122,6 @@ void main() {
sdk.sdkManagerPath = '/foo/bar/sdkmanager'; sdk.sdkManagerPath = '/foo/bar/sdkmanager';
processManager.excludedExecutables.add('/foo/bar/sdkmanager'); processManager.excludedExecutables.add('/foo/bar/sdkmanager');
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -131,6 +130,7 @@ void main() { ...@@ -131,6 +130,7 @@ void main() {
logger: BufferLogger.test(), logger: BufferLogger.test(),
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
final LicensesAccepted licenseStatus = await licenseValidator.licensesAccepted; final LicensesAccepted licenseStatus = await licenseValidator.licensesAccepted;
...@@ -141,7 +141,6 @@ void main() { ...@@ -141,7 +141,6 @@ void main() {
sdk.sdkManagerPath = '/foo/bar/sdkmanager'; sdk.sdkManagerPath = '/foo/bar/sdkmanager';
processManager.excludedExecutables.add('/foo/bar/sdkmanager'); processManager.excludedExecutables.add('/foo/bar/sdkmanager');
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -150,6 +149,7 @@ void main() { ...@@ -150,6 +149,7 @@ void main() {
logger: BufferLogger.test(), logger: BufferLogger.test(),
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
final LicensesAccepted licenseStatus = await licenseValidator.licensesAccepted; final LicensesAccepted licenseStatus = await licenseValidator.licensesAccepted;
...@@ -165,7 +165,6 @@ void main() { ...@@ -165,7 +165,6 @@ void main() {
], stdout: 'asdasassad', ], stdout: 'asdasassad',
)); ));
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -174,6 +173,7 @@ void main() { ...@@ -174,6 +173,7 @@ void main() {
logger: BufferLogger.test(), logger: BufferLogger.test(),
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
final LicensesAccepted result = await licenseValidator.licensesAccepted; final LicensesAccepted result = await licenseValidator.licensesAccepted;
...@@ -194,7 +194,6 @@ All SDK package licenses accepted. ...@@ -194,7 +194,6 @@ All SDK package licenses accepted.
)); ));
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -203,6 +202,7 @@ All SDK package licenses accepted. ...@@ -203,6 +202,7 @@ All SDK package licenses accepted.
logger: BufferLogger.test(), logger: BufferLogger.test(),
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
final LicensesAccepted result = await licenseValidator.licensesAccepted; final LicensesAccepted result = await licenseValidator.licensesAccepted;
...@@ -224,7 +224,6 @@ Review licenses that have not been accepted (y/N)? ...@@ -224,7 +224,6 @@ Review licenses that have not been accepted (y/N)?
)); ));
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -233,6 +232,7 @@ Review licenses that have not been accepted (y/N)? ...@@ -233,6 +232,7 @@ Review licenses that have not been accepted (y/N)?
logger: BufferLogger.test(), logger: BufferLogger.test(),
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
final LicensesAccepted result = await licenseValidator.licensesAccepted; final LicensesAccepted result = await licenseValidator.licensesAccepted;
...@@ -254,7 +254,6 @@ Review licenses that have not been accepted (y/N)? ...@@ -254,7 +254,6 @@ Review licenses that have not been accepted (y/N)?
)); ));
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -263,6 +262,7 @@ Review licenses that have not been accepted (y/N)? ...@@ -263,6 +262,7 @@ Review licenses that have not been accepted (y/N)?
logger: BufferLogger.test(), logger: BufferLogger.test(),
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
final LicensesAccepted result = await licenseValidator.licensesAccepted; final LicensesAccepted result = await licenseValidator.licensesAccepted;
...@@ -280,7 +280,6 @@ Review licenses that have not been accepted (y/N)? ...@@ -280,7 +280,6 @@ Review licenses that have not been accepted (y/N)?
)); ));
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -289,6 +288,7 @@ Review licenses that have not been accepted (y/N)? ...@@ -289,6 +288,7 @@ Review licenses that have not been accepted (y/N)?
logger: BufferLogger.test(), logger: BufferLogger.test(),
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
expect(await licenseValidator.runLicenseManager(), isTrue); expect(await licenseValidator.runLicenseManager(), isTrue);
...@@ -299,7 +299,6 @@ Review licenses that have not been accepted (y/N)? ...@@ -299,7 +299,6 @@ Review licenses that have not been accepted (y/N)?
processManager.excludedExecutables.add('/foo/bar/sdkmanager'); processManager.excludedExecutables.add('/foo/bar/sdkmanager');
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -308,6 +307,7 @@ Review licenses that have not been accepted (y/N)? ...@@ -308,6 +307,7 @@ Review licenses that have not been accepted (y/N)?
logger: BufferLogger.test(), logger: BufferLogger.test(),
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
expect(licenseValidator.runLicenseManager(), throwsToolExit()); expect(licenseValidator.runLicenseManager(), throwsToolExit());
...@@ -328,7 +328,6 @@ Review licenses that have not been accepted (y/N)? ...@@ -328,7 +328,6 @@ Review licenses that have not been accepted (y/N)?
final BufferLogger logger = BufferLogger.test(); final BufferLogger logger = BufferLogger.test();
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -337,6 +336,7 @@ Review licenses that have not been accepted (y/N)? ...@@ -337,6 +336,7 @@ Review licenses that have not been accepted (y/N)?
logger: logger, logger: logger,
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
await licenseValidator.runLicenseManager(); await licenseValidator.runLicenseManager();
...@@ -349,7 +349,6 @@ Review licenses that have not been accepted (y/N)? ...@@ -349,7 +349,6 @@ Review licenses that have not been accepted (y/N)?
processManager.excludedExecutables.add('/foo/bar/sdkmanager'); processManager.excludedExecutables.add('/foo/bar/sdkmanager');
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -358,6 +357,7 @@ Review licenses that have not been accepted (y/N)? ...@@ -358,6 +357,7 @@ Review licenses that have not been accepted (y/N)?
logger: BufferLogger.test(), logger: BufferLogger.test(),
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
expect(licenseValidator.runLicenseManager(), throwsToolExit()); expect(licenseValidator.runLicenseManager(), throwsToolExit());
...@@ -376,7 +376,6 @@ Review licenses that have not been accepted (y/N)? ...@@ -376,7 +376,6 @@ Review licenses that have not been accepted (y/N)?
); );
final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator( final AndroidLicenseValidator licenseValidator = AndroidLicenseValidator(
java: FakeJava(),
androidSdk: sdk, androidSdk: sdk,
fileSystem: fileSystem, fileSystem: fileSystem,
processManager: processManager, processManager: processManager,
...@@ -385,6 +384,7 @@ Review licenses that have not been accepted (y/N)? ...@@ -385,6 +384,7 @@ Review licenses that have not been accepted (y/N)?
logger: logger, logger: logger,
userMessages: UserMessages(), userMessages: UserMessages(),
androidStudio: FakeAndroidStudio(), androidStudio: FakeAndroidStudio(),
operatingSystemUtils: FakeOperatingSystemUtils(),
); );
await expectLater( await expectLater(
...@@ -620,6 +620,9 @@ class FakeAndroidSdk extends Fake implements AndroidSdk { ...@@ -620,6 +620,9 @@ class FakeAndroidSdk extends Fake implements AndroidSdk {
@override @override
List<String> validateSdkWellFormed() => <String>[]; List<String> validateSdkWellFormed() => <String>[];
@override
Map<String, String> get sdkManagerEnv => <String, String>{};
} }
class FakeAndroidSdkVersion extends Fake implements AndroidSdkVersion { class FakeAndroidSdkVersion extends Fake implements AndroidSdkVersion {
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_studio.dart';
import 'package:flutter_tools/src/android/java.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/os.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:test/fake.dart';
import 'package:webdriver/async_io.dart';
import '../../integration.shard/test_utils.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
void main() {
late Logger logger;
late FileSystem fs;
late Platform platform;
late FakeProcessManager processManager;
setUp(() {
logger = BufferLogger.test();
fs = MemoryFileSystem.test();
platform = FakePlatform(environment: <String, String>{
'PATH': '',
});
processManager = FakeProcessManager.empty();
});
group(Java, () {
group('find', () {
testWithoutContext('finds the JDK bundled with Android Studio, if it exists', () {
final AndroidStudio androidStudio = _FakeAndroidStudioWithJdk();
final String androidStudioBundledJdkHome = androidStudio.javaPath!;
final String expectedJavaBinaryPath = fs.path.join(androidStudioBundledJdkHome, 'bin', 'java');
processManager.addCommand(FakeCommand(
command: <String>[
expectedJavaBinaryPath,
'--version',
],
stdout: '''
openjdk 19.0.2 2023-01-17
OpenJDK Runtime Environment Zulu19.32+15-CA (build 19.0.2+7)
OpenJDK 64-Bit Server VM Zulu19.32+15-CA (build 19.0.2+7, mixed mode, sharing)
'''
));
final Java java = Java.find(
androidStudio: androidStudio,
logger: logger,
fileSystem: fs,
platform: platform,
processManager: processManager,
)!;
final JavaVersion version = java.version!;
expect(java.javaHome, androidStudioBundledJdkHome);
expect(java.binaryPath, expectedJavaBinaryPath);
expect(version.longText, 'OpenJDK Runtime Environment Zulu19.32+15-CA (build 19.0.2+7)');
expect(version.number, '19.0.2');
});
testWithoutContext('finds JAVA_HOME if it is set and the JDK bundled with Android Studio could not be found', () {
final AndroidStudio androidStudio = _FakeAndroidStudioWithoutJdk();
const String javaHome = '/java/home';
final String expectedJavaBinaryPath = fs.path.join(javaHome, 'bin', 'java');
final Java java = Java.find(
androidStudio: androidStudio,
logger: logger,
fileSystem: fs,
platform: FakePlatform(environment: <String, String>{
'JAVA_HOME': javaHome,
}),
processManager: processManager,
)!;
expect(java.javaHome, javaHome);
expect(java.binaryPath, expectedJavaBinaryPath);
});
testWithoutContext('returns the java binary found on PATH if no other can be found', () {
final AndroidStudio androidStudio = _FakeAndroidStudioWithoutJdk();
final OperatingSystemUtils os = _FakeOperatingSystemUtilsWithJava(fileSystem);
processManager.addCommand(
const FakeCommand(
command: <String>['which', 'java'],
stdout: '/fake/which/java/path',
),
);
final Java java = Java.find(
androidStudio: androidStudio,
logger: logger,
fileSystem: fs,
platform: platform,
processManager: processManager,
)!;
expect(java.binaryPath, os.which('java')!.path);
expect(java.javaHome, isNull);
});
testWithoutContext('returns null if no java could be found', () {
final AndroidStudio androidStudio = _FakeAndroidStudioWithoutJdk();
processManager.addCommand(
const FakeCommand(
command: <String>['which', 'java'],
exitCode: 1,
),
);
final Java? java = Java.find(
androidStudio: androidStudio,
logger: logger,
fileSystem: fs,
platform: platform,
processManager: processManager,
);
expect(java, isNull);
});
});
group('getVersionString', () {
late Java java;
setUp(() {
processManager = FakeProcessManager.empty();
java = Java(
fileSystem: fs,
logger: logger,
os: FakeOperatingSystemUtils(),
platform: platform,
processManager: processManager,
binaryPath: 'javaHome/bin/java',
javaHome: 'javaHome',
);
});
void addJavaVersionCommand(String output) {
processManager.addCommand(
FakeCommand(
command: <String>[java.binaryPath, '--version'],
stdout: output,
),
);
}
testWithoutContext('parses jdk 8', () {
addJavaVersionCommand('''
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b10, mixed mode)
''');
final JavaVersion version = java.version!;
expect(version.longText, 'Java(TM) SE Runtime Environment (build 1.8.0_202-b10)');
expect(version.number, '1.8.0');
});
testWithoutContext('parses jdk 11 windows', () {
addJavaVersionCommand('''
java version "11.0.14"
Java(TM) SE Runtime Environment (build 11.0.14+10-b13)
Java HotSpot(TM) 64-Bit Server VM (build 11.0.14+10-b13, mixed mode)
''');
final JavaVersion version = java.version!;
expect(version.longText, 'Java(TM) SE Runtime Environment (build 11.0.14+10-b13)');
expect(version.number, '11.0.14');
});
testWithoutContext('parses jdk 11 mac/linux', () {
addJavaVersionCommand('''
openjdk version "11.0.18" 2023-01-17 LTS
OpenJDK Runtime Environment Zulu11.62+17-CA (build 11.0.18+10-LTS)
OpenJDK 64-Bit Server VM Zulu11.62+17-CA (build 11.0.18+10-LTS, mixed mode)
''');
final JavaVersion version = java.version!;
expect(version.longText, 'OpenJDK Runtime Environment Zulu11.62+17-CA (build 11.0.18+10-LTS)');
expect(version.number, '11.0.18');
});
testWithoutContext('parses jdk 17', () {
addJavaVersionCommand('''
openjdk 17.0.6 2023-01-17
OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)
OpenJDK 64-Bit Server VM (build 17.0.6+0-17.0.6b802.4-9586694, mixed mode)
''');
final JavaVersion version = java.version!;
expect(version.longText, 'OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)');
expect(version.number, '17.0.6');
});
testWithoutContext('parses jdk 19', () {
addJavaVersionCommand('''
openjdk 19.0.2 2023-01-17
OpenJDK Runtime Environment Homebrew (build 19.0.2)
OpenJDK 64-Bit Server VM Homebrew (build 19.0.2, mixed mode, sharing)
''');
final JavaVersion version = java.version!;
expect(version.longText, 'OpenJDK Runtime Environment Homebrew (build 19.0.2)');
expect(version.number, '19.0.2');
});
// https://chrome-infra-packages.appspot.com/p/flutter/java/openjdk/
testWithoutContext('parses jdk output from ci', () {
addJavaVersionCommand('''
openjdk 11.0.2 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)
''');
final JavaVersion version = java.version!;
expect(version.longText, 'OpenJDK Runtime Environment 18.9 (build 11.0.2+9)');
expect(version.number, '11.0.2');
});
testWithoutContext('parses jdk two number versions', () {
addJavaVersionCommand('openjdk 19.0 2023-01-17');
final JavaVersion version = java.version!;
expect(version.longText, 'openjdk 19.0 2023-01-17');
expect(version.number, '19.0');
});
});
});
}
class _FakeAndroidStudioWithJdk extends Fake implements AndroidStudio {
@override
String? get javaPath => '/fake/android_studio/java/path/';
}
class _FakeAndroidStudioWithoutJdk extends Fake implements AndroidStudio {
@override
String? get javaPath => null;
}
class _FakeOperatingSystemUtilsWithJava extends FakeOperatingSystemUtils {
_FakeOperatingSystemUtilsWithJava(this._fileSystem);
final FileSystem _fileSystem;
@override
File? which(String execName) {
if (execName == 'java') {
return _fileSystem.file('/fake/which/java/path');
}
throw const InvalidArgumentException(null, null);
}
}
...@@ -67,7 +67,6 @@ void main() { ...@@ -67,7 +67,6 @@ void main() {
testUsingContext('getEmulators', () async { testUsingContext('getEmulators', () async {
// Test that EmulatorManager.getEmulators() doesn't throw. // Test that EmulatorManager.getEmulators() doesn't throw.
final EmulatorManager emulatorManager = EmulatorManager( final EmulatorManager emulatorManager = EmulatorManager(
java: FakeJava(),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: FakeProcessManager.list(<FakeCommand>[ processManager: FakeProcessManager.list(<FakeCommand>[
...@@ -90,7 +89,6 @@ void main() { ...@@ -90,7 +89,6 @@ void main() {
testUsingContext('getEmulators with no Android SDK', () async { testUsingContext('getEmulators with no Android SDK', () async {
// Test that EmulatorManager.getEmulators() doesn't throw when there's no Android SDK. // Test that EmulatorManager.getEmulators() doesn't throw when there's no Android SDK.
final EmulatorManager emulatorManager = EmulatorManager( final EmulatorManager emulatorManager = EmulatorManager(
java: FakeJava(),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: FakeProcessManager.list(<FakeCommand>[ processManager: FakeProcessManager.list(<FakeCommand>[
...@@ -111,7 +109,6 @@ void main() { ...@@ -111,7 +109,6 @@ void main() {
testWithoutContext('getEmulatorsById', () async { testWithoutContext('getEmulatorsById', () async {
final TestEmulatorManager testEmulatorManager = TestEmulatorManager(emulators, final TestEmulatorManager testEmulatorManager = TestEmulatorManager(emulators,
java: FakeJava(),
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: fakeProcessManager, processManager: fakeProcessManager,
androidWorkflow: AndroidWorkflow( androidWorkflow: AndroidWorkflow(
...@@ -132,7 +129,6 @@ void main() { ...@@ -132,7 +129,6 @@ void main() {
testUsingContext('create emulator with a missing avdmanager does not crash.', () async { testUsingContext('create emulator with a missing avdmanager does not crash.', () async {
sdk.avdManagerPath = null; sdk.avdManagerPath = null;
final EmulatorManager emulatorManager = EmulatorManager( final EmulatorManager emulatorManager = EmulatorManager(
java: FakeJava(),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: FakeProcessManager.list(<FakeCommand>[ processManager: FakeProcessManager.list(<FakeCommand>[
...@@ -156,7 +152,6 @@ void main() { ...@@ -156,7 +152,6 @@ void main() {
// iOS discovery uses context. // iOS discovery uses context.
testUsingContext('create emulator with an empty name does not fail', () async { testUsingContext('create emulator with an empty name does not fail', () async {
final EmulatorManager emulatorManager = EmulatorManager( final EmulatorManager emulatorManager = EmulatorManager(
java: FakeJava(),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: FakeProcessManager.list(<FakeCommand>[ processManager: FakeProcessManager.list(<FakeCommand>[
...@@ -196,7 +191,6 @@ void main() { ...@@ -196,7 +191,6 @@ void main() {
testWithoutContext('create emulator with a unique name does not throw', () async { testWithoutContext('create emulator with a unique name does not throw', () async {
final EmulatorManager emulatorManager = EmulatorManager( final EmulatorManager emulatorManager = EmulatorManager(
java: FakeJava(),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: FakeProcessManager.list(<FakeCommand>[ processManager: FakeProcessManager.list(<FakeCommand>[
...@@ -233,7 +227,6 @@ void main() { ...@@ -233,7 +227,6 @@ void main() {
testWithoutContext('create emulator with an existing name errors', () async { testWithoutContext('create emulator with an existing name errors', () async {
final EmulatorManager emulatorManager = EmulatorManager( final EmulatorManager emulatorManager = EmulatorManager(
java: FakeJava(),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: FakeProcessManager.list(<FakeCommand>[ processManager: FakeProcessManager.list(<FakeCommand>[
...@@ -273,7 +266,6 @@ void main() { ...@@ -273,7 +266,6 @@ void main() {
// iOS discovery uses context. // iOS discovery uses context.
testUsingContext('create emulator without a name but when default exists adds a suffix', () async { testUsingContext('create emulator without a name but when default exists adds a suffix', () async {
final EmulatorManager emulatorManager = EmulatorManager( final EmulatorManager emulatorManager = EmulatorManager(
java: FakeJava(),
fileSystem: MemoryFileSystem.test(), fileSystem: MemoryFileSystem.test(),
logger: BufferLogger.test(), logger: BufferLogger.test(),
processManager: FakeProcessManager.list(<FakeCommand>[ processManager: FakeProcessManager.list(<FakeCommand>[
...@@ -350,7 +342,6 @@ void main() { ...@@ -350,7 +342,6 @@ void main() {
class TestEmulatorManager extends EmulatorManager { class TestEmulatorManager extends EmulatorManager {
TestEmulatorManager(this.allEmulators, { TestEmulatorManager(this.allEmulators, {
required super.java,
required super.logger, required super.logger,
required super.processManager, required super.processManager,
required super.androidWorkflow, required super.androidWorkflow,
...@@ -402,4 +393,7 @@ class FakeAndroidSdk extends Fake implements AndroidSdk { ...@@ -402,4 +393,7 @@ class FakeAndroidSdk extends Fake implements AndroidSdk {
@override @override
String getAvdPath() => 'avd'; String getAvdPath() => 'avd';
@override
Map<String, String> get sdkManagerEnv => <String, String>{};
} }
...@@ -7,7 +7,6 @@ import 'dart:io' as io show IOSink, ProcessSignal, Stdout, StdoutException; ...@@ -7,7 +7,6 @@ import 'dart:io' as io show IOSink, ProcessSignal, Stdout, StdoutException;
import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/android/android_sdk.dart';
import 'package:flutter_tools/src/android/android_studio.dart'; import 'package:flutter_tools/src/android/android_studio.dart';
import 'package:flutter_tools/src/android/java.dart';
import 'package:flutter_tools/src/base/bot_detector.dart'; import 'package:flutter_tools/src/base/bot_detector.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
...@@ -589,7 +588,6 @@ class FakeFlutterProjectFactory implements FlutterProjectFactory { ...@@ -589,7 +588,6 @@ class FakeFlutterProjectFactory implements FlutterProjectFactory {
} }
class FakeAndroidSdk extends Fake implements AndroidSdk { class FakeAndroidSdk extends Fake implements AndroidSdk {
@override @override
late bool platformToolsAvailable; late bool platformToolsAvailable;
...@@ -604,41 +602,3 @@ class FakeAndroidStudio extends Fake implements AndroidStudio { ...@@ -604,41 +602,3 @@ class FakeAndroidStudio extends Fake implements AndroidStudio {
@override @override
String get javaPath => 'java'; String get javaPath => 'java';
} }
class FakeJava extends Fake implements Java {
FakeJava({
this.javaHome = '/android-studio/jbr',
String binary = '/android-studio/jbr/bin/java',
JavaVersion? version,
bool canRun = true,
}): binaryPath = binary,
version = version ?? JavaVersion(
longText: 'openjdk 19.0.2 2023-01-17',
number: '19.0.2',
),
_environment = <String, String>{
if (javaHome != null) 'JAVA_HOME': javaHome,
'PATH': '/android-studio/jbr/bin',
},
_canRun = canRun;
@override
String? javaHome;
@override
String binaryPath;
final Map<String, String> _environment;
final bool _canRun;
@override
Map<String, String> get environment => _environment;
@override
JavaVersion? version;
@override
bool canRun() {
return _canRun;
}
}
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