Unverified Commit 9dbd6e61 authored by Andrew Kolos's avatar Andrew Kolos Committed by GitHub

[tools] Apply Android Studio version detection logic to explicitly configured...

[tools] Apply Android Studio version detection logic to explicitly configured installation directory (`flutter config --android-studio-dir`) (#125596)

Fixes #121468 (when considered along with https://github.com/flutter/flutter/pull/125247).

This applies the pre-existing Android Studio version detection logic to the install configured with `flutter config android-studio-dir`.
parent 4b74232a
......@@ -52,7 +52,10 @@ class AndroidStudio {
_initAndValidate();
}
static AndroidStudio? fromMacOSBundle(String bundlePath) {
static AndroidStudio? fromMacOSBundle(
String bundlePath, {
String? configuredPath,
}) {
final String studioPath = globals.fs.path.join(bundlePath, 'Contents');
final String plistFile = globals.fs.path.join(studioPath, 'Info.plist');
final Map<String, dynamic> plistValues = globals.plistParser.parseFile(plistFile);
......@@ -99,7 +102,12 @@ class AndroidStudio {
);
}
}
return AndroidStudio(studioPath, version: version, presetPluginsPath: presetPluginsPath);
return AndroidStudio(
studioPath,
version: version,
presetPluginsPath: presetPluginsPath,
configuredPath: configuredPath,
);
}
static AndroidStudio? fromHomeDot(Directory homeDotDir) {
......@@ -238,24 +246,14 @@ class AndroidStudio {
/// invalid.
static AndroidStudio? latestValid() {
final String? configuredStudioPath = globals.config.getValue('android-studio-dir') as String?;
if (configuredStudioPath != null) {
String correctedConfiguredStudioPath = configuredStudioPath;
if (globals.platform.isMacOS && !correctedConfiguredStudioPath.endsWith('Contents')) {
correctedConfiguredStudioPath = globals.fs.path.join(correctedConfiguredStudioPath, 'Contents');
}
if (!globals.fs.directory(correctedConfiguredStudioPath).existsSync()) {
throwToolExit('''
if (configuredStudioPath != null && !globals.fs.directory(configuredStudioPath).existsSync()) {
throwToolExit('''
Could not find the Android Studio installation at the manually configured path "$configuredStudioPath".
Please verify that the path is correct and update it by running this command: flutter config --android-studio-dir '<path>'
To have flutter search for Android Studio installations automatically, remove
the configured path by running this command: flutter config --android-studio-dir ''
''');
}
return AndroidStudio(correctedConfiguredStudioPath,
configuredPath: configuredStudioPath);
}
// Find all available Studio installations.
......@@ -263,6 +261,17 @@ the configured path by running this command: flutter config --android-studio-dir
if (studios.isEmpty) {
return null;
}
final AndroidStudio? manuallyConfigured = studios
.where((AndroidStudio studio) => studio.configuredPath != null &&
configuredStudioPath != null &&
_pathsAreEqual(studio.configuredPath!, configuredStudioPath))
.firstOrNull;
if (manuallyConfigured != null) {
return manuallyConfigured;
}
AndroidStudio? newest;
for (final AndroidStudio studio in studios.where((AndroidStudio s) => s.isValid)) {
if (newest == null) {
......@@ -324,14 +333,15 @@ the configured path by running this command: flutter config --android-studio-dir
}
final String? configuredStudioDir = globals.config.getValue('android-studio-dir') as String?;
FileSystemEntity? configuredStudioDirAsEntity;
if (configuredStudioDir != null) {
FileSystemEntity configuredStudio = globals.fs.file(configuredStudioDir);
if (configuredStudio.basename == 'Contents') {
configuredStudio = configuredStudio.parent;
configuredStudioDirAsEntity = globals.fs.directory(configuredStudioDir);
if (configuredStudioDirAsEntity.basename == 'Contents') {
configuredStudioDirAsEntity = configuredStudioDirAsEntity.parent;
}
if (!candidatePaths
.any((FileSystemEntity e) => e.path == configuredStudio.path)) {
candidatePaths.add(configuredStudio);
.any((FileSystemEntity e) => _pathsAreEqual(e.path, configuredStudioDirAsEntity!.path))) {
candidatePaths.add(configuredStudioDirAsEntity);
}
}
......@@ -355,9 +365,18 @@ the configured path by running this command: flutter config --android-studio-dir
}
return candidatePaths
.map<AndroidStudio?>((FileSystemEntity e) => AndroidStudio.fromMacOSBundle(e.path))
.whereType<AndroidStudio>()
.toList();
.map<AndroidStudio?>((FileSystemEntity e) {
if (configuredStudioDirAsEntity == null) {
return AndroidStudio.fromMacOSBundle(e.path);
}
return AndroidStudio.fromMacOSBundle(
e.path,
configuredPath: _pathsAreEqual(configuredStudioDirAsEntity.path, e.path) ? configuredStudioDir : null,
);
})
.whereType<AndroidStudio>()
.toList();
}
static List<AndroidStudio> _allLinuxOrWindows() {
......@@ -440,7 +459,7 @@ the configured path by running this command: flutter config --android-studio-dir
studioAppName: title,
);
if (!alreadyFoundStudioAt(studio.directory, newerThan: studio.version)) {
studios.removeWhere((AndroidStudio other) => other.directory == studio.directory);
studios.removeWhere((AndroidStudio other) => _pathsAreEqual(other.directory, studio.directory));
studios.add(studio);
}
}
......@@ -450,9 +469,23 @@ the configured path by running this command: flutter config --android-studio-dir
}
final String? configuredStudioDir = globals.config.getValue('android-studio-dir') as String?;
if (configuredStudioDir != null && !alreadyFoundStudioAt(configuredStudioDir)) {
studios.add(AndroidStudio(configuredStudioDir,
if (configuredStudioDir != null) {
final AndroidStudio? matchingAlreadyFoundInstall = studios
.where((AndroidStudio other) => _pathsAreEqual(configuredStudioDir, other.directory))
.firstOrNull;
if (matchingAlreadyFoundInstall != null) {
studios.remove(matchingAlreadyFoundInstall);
studios.add(
AndroidStudio(
configuredStudioDir,
configuredPath: configuredStudioDir,
version: matchingAlreadyFoundInstall.version,
),
);
} else {
studios.add(AndroidStudio(configuredStudioDir,
configuredPath: configuredStudioDir));
}
}
if (globals.platform.isLinux) {
......@@ -528,3 +561,7 @@ the configured path by running this command: flutter config --android-studio-dir
@override
String toString() => 'Android Studio ($version)';
}
bool _pathsAreEqual(String path, String other) {
return globals.fs.path.canonicalize(path) == globals.fs.path.canonicalize(other);
}
......@@ -86,6 +86,7 @@ void main() {
},
};
late Config config;
late FileSystem fileSystem;
late FileSystemUtils fsUtils;
late Platform platform;
......@@ -93,6 +94,7 @@ void main() {
late FakeProcessManager processManager;
setUp(() {
config = Config.test();
fileSystem = MemoryFileSystem.test();
plistUtils = FakePlistUtils();
platform = FakePlatform(
......@@ -590,14 +592,6 @@ void main() {
final String jdkPathFor2022 = fileSystem.path.join(studioInApplicationPlistFolder, 'jbr', 'Contents', 'Home');
processManager.addCommand(FakeCommand(
command: <String>[
fileSystem.path.join(jdkPathFor2022, 'bin', 'java'),
'-version',
],
stderr: '123',
)
);
final AndroidStudio studio = AndroidStudio.fromMacOSBundle(
fileSystem.directory(studioInApplicationPlistFolder).parent.path,
)!;
......@@ -607,18 +601,70 @@ void main() {
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
FileSystemUtils: () => fsUtils,
ProcessManager: () => processManager,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
PlistParser: () => plistUtils,
});
testUsingContext('discovers explicitly configured Android Studio', () {
final String extractedDownloadZip = fileSystem.path.join(
'/',
'Users',
'Dash',
'Desktop',
'android-studio'
);
config.setValue('android-studio-dir', extractedDownloadZip);
final String studioInApplicationPlistFolder = fileSystem.path.join(
extractedDownloadZip,
'Contents',
);
fileSystem.directory(studioInApplicationPlistFolder).createSync(recursive: true);
final String plistFilePath = fileSystem.path.join(studioInApplicationPlistFolder, 'Info.plist');
plistUtils.fileContents[plistFilePath] = macStudioInfoPlist2022_1;
final String studioInApplicationJavaBinary = fileSystem.path.join(
extractedDownloadZip,
'Contents', 'jbr', 'Contents', 'Home', 'bin', 'java',
);
processManager.addCommands(<FakeCommand>[
FakeCommand(
command: const <String>[
'mdfind',
'kMDItemCFBundleIdentifier="com.google.android.studio*"',
],
stdout: extractedDownloadZip,
),
FakeCommand(
command: <String>[
studioInApplicationJavaBinary,
'-version',
],
),
]);
final AndroidStudio studio = AndroidStudio.allInstalled().single;
expect(studio.configuredPath, extractedDownloadZip);
expect(processManager, hasNoRemainingExpectations);
}, overrides: <Type, Generator>{
Config:() => config,
FileSystem: () => fileSystem,
FileSystemUtils: () => fsUtils,
ProcessManager: () => processManager,
Platform: () => platform,
PlistParser: () => plistUtils,
});
});
group('installation detection on Windows', () {
late Config config;
late Platform platform;
late FileSystem fileSystem;
setUp(() {
config = Config.test();
platform = FakePlatform(
operatingSystem: 'windows',
environment: <String, String>{
......@@ -800,6 +846,27 @@ void main() {
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('discovers explicitly configured Android Studio', () {
const String androidStudioDir = r'C:\Users\Dash\Desktop\android-studio';
config.setValue('android-studio-dir', androidStudioDir);
fileSystem.file(r'C:\Users\Dash\AppData\Local\Google\AndroidStudio2022.1\.home')
..createSync(recursive: true)
..writeAsStringSync(androidStudioDir);
fileSystem.directory(androidStudioDir)
.createSync(recursive: true);
final AndroidStudio studio = AndroidStudio.allInstalled().single;
expect(studio.version, equals(Version(2022, 1, null)));
expect(studio.configuredPath, androidStudioDir);
expect(studio.javaPath, fileSystem.path.join(androidStudioDir, 'jbr'));
}, overrides: <Type, Generator>{
Config: () => config,
Platform: () => platform,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
});
group('installation detection on Linux', () {
......@@ -1015,6 +1082,28 @@ void main() {
platform: platform,
),
});
testUsingContext('discovers explicitly configured Android Studio', () {
const String androidStudioDir = '/Users/Dash/Desktop/android-studio';
config.setValue('android-studio-dir', androidStudioDir);
const String studioHome = '$homeLinux/.cache/Google/AndroidStudio2022.3/.home';
fileSystem.file(studioHome)
..createSync(recursive: true)
..writeAsStringSync(androidStudioDir);
fileSystem.directory(androidStudioDir)
.createSync(recursive: true);
final AndroidStudio studio = AndroidStudio.allInstalled().single;
expect(studio.version, equals(Version(2022, 3, null)));
expect(studio.configuredPath, androidStudioDir);
expect(studio.javaPath, fileSystem.path.join(androidStudioDir, 'jbr'));
}, overrides: <Type, Generator>{
Config: () => config,
Platform: () => platform,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
});
group('latestValid', () {
......@@ -1162,6 +1251,16 @@ void main() {
}
expect(AndroidStudio.allInstalled().length, 4);
for (final String javaPath in validJavaPaths) {
(globals.processManager as FakeProcessManager).addCommand(FakeCommand(
command: <String>[
fileSystem.path.join(javaPath),
'-version',
],
));
}
final AndroidStudio chosenInstall = AndroidStudio.latestValid()!;
expect(chosenInstall.directory, configuredAndroidStudioDir);
expect(chosenInstall.isValid, false);
......
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