Unverified Commit fb68d074 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Migrate android_studio to null safety (#79504)

parent d5671739
...@@ -13,7 +13,7 @@ import '../base/platform.dart'; ...@@ -13,7 +13,7 @@ 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_null_migrated.dart' as globals;
import 'android_studio.dart'; import 'android_studio.dart';
// ANDROID_HOME is deprecated. // ANDROID_HOME is deprecated.
......
...@@ -2,9 +2,6 @@ ...@@ -2,9 +2,6 @@
// 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.
// @dart = 2.8
import '../base/context.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
import '../base/process.dart'; import '../base/process.dart';
...@@ -13,8 +10,6 @@ import '../base/version.dart'; ...@@ -13,8 +10,6 @@ import '../base/version.dart';
import '../globals_null_migrated.dart' as globals; import '../globals_null_migrated.dart' as globals;
import '../ios/plist_parser.dart'; import '../ios/plist_parser.dart';
AndroidStudio get androidStudio => context.get<AndroidStudio>();
// Android Studio layout: // Android Studio layout:
// Linux/Windows: // Linux/Windows:
...@@ -30,12 +25,12 @@ AndroidStudio get androidStudio => context.get<AndroidStudio>(); ...@@ -30,12 +25,12 @@ AndroidStudio get androidStudio => context.get<AndroidStudio>();
final RegExp _dotHomeStudioVersionMatcher = final RegExp _dotHomeStudioVersionMatcher =
RegExp(r'^\.?(AndroidStudio[^\d]*)([\d.]+)'); RegExp(r'^\.?(AndroidStudio[^\d]*)([\d.]+)');
String get javaPath => androidStudio?.javaPath; String? get javaPath => globals.androidStudio?.javaPath;
class AndroidStudio implements Comparable<AndroidStudio> { class AndroidStudio implements Comparable<AndroidStudio> {
AndroidStudio( AndroidStudio(
this.directory, { this.directory, {
Version version, Version? version,
this.configured, this.configured,
this.studioAppName = 'AndroidStudio', this.studioAppName = 'AndroidStudio',
this.presetPluginsPath, this.presetPluginsPath,
...@@ -58,27 +53,28 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -58,27 +53,28 @@ class AndroidStudio implements Comparable<AndroidStudio> {
final String versionString = plistValues[PlistParser.kCFBundleShortVersionStringKey] as String; final String versionString = plistValues[PlistParser.kCFBundleShortVersionStringKey] as String;
Version version; Version? version;
if (versionString != null) { if (versionString != null) {
version = Version.parse(versionString); version = Version.parse(versionString);
} }
String pathsSelectorValue; String? pathsSelectorValue;
final Map<String, dynamic> jvmOptions = castStringKeyedMap(plistValues['JVMOptions']); final Map<String, dynamic>? jvmOptions = castStringKeyedMap(plistValues['JVMOptions']);
if (jvmOptions != null) { if (jvmOptions != null) {
final Map<String, dynamic> jvmProperties = castStringKeyedMap(jvmOptions['Properties']); final Map<String, dynamic>? jvmProperties = castStringKeyedMap(jvmOptions['Properties']);
if (jvmProperties != null) { if (jvmProperties != null) {
pathsSelectorValue = jvmProperties['idea.paths.selector'] as String; pathsSelectorValue = jvmProperties['idea.paths.selector'] as String;
} }
} }
final int major = version?.major; final int? major = version?.major;
final int minor = version?.minor; final int? minor = version?.minor;
String presetPluginsPath; String? presetPluginsPath;
if (pathsSelectorValue != null) { final String? homeDirPath = globals.fsUtils.homeDirPath;
if (homeDirPath != null && pathsSelectorValue != null) {
if (major != null && major >= 4 && minor != null && minor >= 1) { if (major != null && major >= 4 && minor != null && minor >= 1) {
presetPluginsPath = globals.fs.path.join( presetPluginsPath = globals.fs.path.join(
globals.fsUtils.homeDirPath, homeDirPath,
'Library', 'Library',
'Application Support', 'Application Support',
'Google', 'Google',
...@@ -86,7 +82,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -86,7 +82,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
); );
} else { } else {
presetPluginsPath = globals.fs.path.join( presetPluginsPath = globals.fs.path.join(
globals.fsUtils.homeDirPath, homeDirPath,
'Library', 'Library',
'Application Support', 'Application Support',
pathsSelectorValue, pathsSelectorValue,
...@@ -96,20 +92,20 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -96,20 +92,20 @@ class AndroidStudio implements Comparable<AndroidStudio> {
return AndroidStudio(studioPath, version: version, presetPluginsPath: presetPluginsPath); return AndroidStudio(studioPath, version: version, presetPluginsPath: presetPluginsPath);
} }
factory AndroidStudio.fromHomeDot(Directory homeDotDir) { static AndroidStudio? fromHomeDot(Directory homeDotDir) {
final Match versionMatch = final Match? versionMatch =
_dotHomeStudioVersionMatcher.firstMatch(homeDotDir.basename); _dotHomeStudioVersionMatcher.firstMatch(homeDotDir.basename);
if (versionMatch?.groupCount != 2) { if (versionMatch?.groupCount != 2) {
return null; return null;
} }
final Version version = Version.parse(versionMatch[2]); final Version? version = Version.parse(versionMatch![2]);
final String studioAppName = versionMatch[1]; final String? studioAppName = versionMatch[1];
if (studioAppName == null || version == null) { if (studioAppName == null || version == null) {
return null; return null;
} }
final int major = version?.major; final int major = version.major;
final int minor = version?.minor; final int minor = version.minor;
// The install path is written in a .home text file, // The install path is written in a .home text file,
// it location is in <base dir>/.home for Android Studio >= 4.1 // it location is in <base dir>/.home for Android Studio >= 4.1
...@@ -123,7 +119,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -123,7 +119,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
globals.fs.path.join(homeDotDir.path, 'system', '.home'); globals.fs.path.join(homeDotDir.path, 'system', '.home');
} }
String installPath; String? installPath;
try { try {
installPath = globals.fs.file(dotHomeFilePath).readAsStringSync(); installPath = globals.fs.file(dotHomeFilePath).readAsStringSync();
...@@ -144,28 +140,32 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -144,28 +140,32 @@ class AndroidStudio implements Comparable<AndroidStudio> {
final String directory; final String directory;
final String studioAppName; final String studioAppName;
final Version version; final Version version;
final String configured; final String? configured;
final String presetPluginsPath; final String? presetPluginsPath;
String _javaPath; String? _javaPath;
bool _isValid = false; bool _isValid = false;
final List<String> _validationMessages = <String>[]; final List<String> _validationMessages = <String>[];
String get javaPath => _javaPath; String? get javaPath => _javaPath;
bool get isValid => _isValid; bool get isValid => _isValid;
String get pluginsPath { String? get pluginsPath {
if (presetPluginsPath != null) { if (presetPluginsPath != null) {
return presetPluginsPath; return presetPluginsPath!;
}
final int major = version.major;
final int minor = version.minor;
final String? homeDirPath = globals.fsUtils.homeDirPath;
if (homeDirPath == null) {
return null;
} }
final int major = version?.major;
final int minor = version?.minor;
if (globals.platform.isMacOS) { if (globals.platform.isMacOS) {
/// plugin path of Android Studio has been changed after version 4.1. /// plugin path of Android Studio has been changed after version 4.1.
if (major != null && major >= 4 && minor != null && minor >= 1) { if (major != null && major >= 4 && minor != null && minor >= 1) {
return globals.fs.path.join( return globals.fs.path.join(
globals.fsUtils.homeDirPath, homeDirPath,
'Library', 'Library',
'Application Support', 'Application Support',
'Google', 'Google',
...@@ -173,7 +173,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -173,7 +173,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
); );
} else { } else {
return globals.fs.path.join( return globals.fs.path.join(
globals.fsUtils.homeDirPath, homeDirPath,
'Library', 'Library',
'Application Support', 'Application Support',
'AndroidStudio$major.$minor', 'AndroidStudio$major.$minor',
...@@ -190,7 +190,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -190,7 +190,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
if (major != null && major >= 4 && minor != null && minor >= 1 && if (major != null && major >= 4 && minor != null && minor >= 1 &&
globals.platform.isLinux) { globals.platform.isLinux) {
return globals.fs.path.join( return globals.fs.path.join(
globals.fsUtils.homeDirPath, homeDirPath,
'.local', '.local',
'share', 'share',
'Google', 'Google',
...@@ -199,7 +199,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -199,7 +199,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
} }
return globals.fs.path.join( return globals.fs.path.join(
globals.fsUtils.homeDirPath, homeDirPath,
'.$studioAppName$major.$minor', '.$studioAppName$major.$minor',
'config', 'config',
'plugins', 'plugins',
...@@ -219,7 +219,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -219,7 +219,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
} }
/// Locates the newest, valid version of Android Studio. /// Locates the newest, valid version of Android Studio.
static AndroidStudio latestValid() { static AndroidStudio? latestValid() {
final String configuredStudio = globals.config.getValue('android-studio-dir') as String; final String configuredStudio = globals.config.getValue('android-studio-dir') as String;
if (configuredStudio != null) { if (configuredStudio != null) {
String configuredStudioPath = configuredStudio; String configuredStudioPath = configuredStudio;
...@@ -235,9 +235,14 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -235,9 +235,14 @@ class AndroidStudio implements Comparable<AndroidStudio> {
if (studios.isEmpty) { if (studios.isEmpty) {
return null; return null;
} }
studios.sort(); AndroidStudio? newest;
return studios.lastWhere((AndroidStudio s) => s.isValid, for (final AndroidStudio studio in studios.where((AndroidStudio s) => s.isValid)) {
orElse: () => null); if (newest == null || studio.compareTo(newest) > 0) {
newest = studio;
}
}
return newest;
} }
static List<AndroidStudio> allInstalled() => static List<AndroidStudio> allInstalled() =>
...@@ -270,10 +275,13 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -270,10 +275,13 @@ class AndroidStudio implements Comparable<AndroidStudio> {
} }
_checkForStudio('/Applications'); _checkForStudio('/Applications');
_checkForStudio(globals.fs.path.join( final String? homeDirPath = globals.fsUtils.homeDirPath;
globals.fsUtils.homeDirPath, if (homeDirPath != null) {
'Applications', _checkForStudio(globals.fs.path.join(
)); homeDirPath,
'Applications',
));
}
final String configuredStudioDir = globals.config.getValue('android-studio-dir') as String; final String configuredStudioDir = globals.config.getValue('android-studio-dir') as String;
if (configuredStudioDir != null) { if (configuredStudioDir != null) {
...@@ -296,7 +304,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -296,7 +304,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
static List<AndroidStudio> _allLinuxOrWindows() { static List<AndroidStudio> _allLinuxOrWindows() {
final List<AndroidStudio> studios = <AndroidStudio>[]; final List<AndroidStudio> studios = <AndroidStudio>[];
bool _hasStudioAt(String path, { Version newerThan }) { bool _hasStudioAt(String path, { Version? newerThan }) {
return studios.any((AndroidStudio studio) { return studios.any((AndroidStudio studio) {
if (studio.directory != path) { if (studio.directory != path) {
return false; return false;
...@@ -312,7 +320,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -312,7 +320,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
// or $HOME/.cache/Google/AndroidStudio*/.home files. // or $HOME/.cache/Google/AndroidStudio*/.home files.
// There may be several pointing to the same installation, // There may be several pointing to the same installation,
// so we grab only the latest one. // so we grab only the latest one.
final String homeDirPath = globals.fsUtils.homeDirPath; final String? homeDirPath = globals.fsUtils.homeDirPath;
if (homeDirPath != null && globals.fs.directory(homeDirPath).existsSync()) { if (homeDirPath != null && globals.fs.directory(homeDirPath).existsSync()) {
final Directory homeDir = globals.fs.directory(homeDirPath); final Directory homeDir = globals.fs.directory(homeDirPath);
...@@ -337,7 +345,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -337,7 +345,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
} }
for (final Directory entity in entities) { for (final Directory entity in entities) {
final AndroidStudio studio = AndroidStudio.fromHomeDot(entity); final AndroidStudio? studio = AndroidStudio.fromHomeDot(entity);
if (studio != null && !_hasStudioAt(studio.directory, newerThan: studio.version)) { if (studio != null && !_hasStudioAt(studio.directory, newerThan: studio.version)) {
studios.removeWhere((AndroidStudio other) => other.directory == studio.directory); studios.removeWhere((AndroidStudio other) => other.directory == studio.directory);
studios.add(studio); studios.add(studio);
...@@ -348,7 +356,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -348,7 +356,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
// 4.1 has a different location for AndroidStudio installs on Windows. // 4.1 has a different location for AndroidStudio installs on Windows.
if (globals.platform.isWindows && globals.platform.environment.containsKey('LOCALAPPDATA')) { if (globals.platform.isWindows && globals.platform.environment.containsKey('LOCALAPPDATA')) {
final File homeDot = globals.fs.file(globals.fs.path.join( final File homeDot = globals.fs.file(globals.fs.path.join(
globals.platform.environment['LOCALAPPDATA'], globals.platform.environment['LOCALAPPDATA']!,
'Google', 'Google',
'AndroidStudio4.1', 'AndroidStudio4.1',
'.home', '.home',
...@@ -389,11 +397,11 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -389,11 +397,11 @@ class AndroidStudio implements Comparable<AndroidStudio> {
return studios; return studios;
} }
static String extractStudioPlistValueWithMatcher(String plistValue, RegExp keyMatcher) { static String? extractStudioPlistValueWithMatcher(String plistValue, RegExp keyMatcher) {
if (plistValue == null || keyMatcher == null) { if (plistValue == null || keyMatcher == null) {
return null; return null;
} }
return keyMatcher?.stringMatch(plistValue)?.split('=')?.last?.trim()?.replaceAll('"', ''); return keyMatcher.stringMatch(plistValue)?.split('=').last.trim().replaceAll('"', '');
} }
void _init() { void _init() {
...@@ -416,7 +424,7 @@ class AndroidStudio implements Comparable<AndroidStudio> { ...@@ -416,7 +424,7 @@ class AndroidStudio implements Comparable<AndroidStudio> {
if (!globals.processManager.canRun(javaExecutable)) { if (!globals.processManager.canRun(javaExecutable)) {
_validationMessages.add('Unable to find bundled Java version.'); _validationMessages.add('Unable to find bundled Java version.');
} else { } else {
RunResult result; RunResult? result;
try { try {
result = globals.processUtils.runSync(<String>[javaExecutable, '-version']); result = globals.processUtils.runSync(<String>[javaExecutable, '-version']);
} on ProcessException catch (e) { } on ProcessException catch (e) {
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
// @dart = 2.8 // @dart = 2.8
import '../android/android_studio.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../convert.dart'; import '../convert.dart';
import '../features.dart'; import '../features.dart';
...@@ -176,8 +175,8 @@ class ConfigCommand extends FlutterCommand { ...@@ -176,8 +175,8 @@ class ConfigCommand extends FlutterCommand {
} }
// Ensure we send any calculated ones, if overrides don't exist. // Ensure we send any calculated ones, if overrides don't exist.
if (results['android-studio-dir'] == null && androidStudio != null) { if (results['android-studio-dir'] == null && globals.androidStudio != null) {
results['android-studio-dir'] = androidStudio.directory; results['android-studio-dir'] = globals.androidStudio.directory;
} }
if (results['android-sdk'] == null && globals.androidSdk != null) { if (results['android-sdk'] == null && globals.androidSdk != null) {
results['android-sdk'] = globals.androidSdk.directory.path; results['android-sdk'] = globals.androidSdk.directory.path;
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
// @dart = 2.8 // @dart = 2.8
import 'android/android_sdk.dart'; import 'android/android_sdk.dart';
import 'android/android_studio.dart';
import 'android/gradle_utils.dart'; import 'android/gradle_utils.dart';
import 'artifacts.dart'; import 'artifacts.dart';
import 'base/bot_detector.dart'; import 'base/bot_detector.dart';
...@@ -52,7 +51,6 @@ CocoaPodsValidator get cocoapodsValidator => context.get<CocoaPodsValidator>(); ...@@ -52,7 +51,6 @@ CocoaPodsValidator get cocoapodsValidator => context.get<CocoaPodsValidator>();
LocalEngineLocator get localEngineLocator => context.get<LocalEngineLocator>(); LocalEngineLocator get localEngineLocator => context.get<LocalEngineLocator>();
AndroidStudio get androidStudio => context.get<AndroidStudio>();
AndroidSdk get androidSdk => context.get<AndroidSdk>(); AndroidSdk get androidSdk => context.get<AndroidSdk>();
CocoaPods get cocoaPods => context.get<CocoaPods>(); CocoaPods get cocoaPods => context.get<CocoaPods>();
FlutterVersion get flutterVersion => context.get<FlutterVersion>(); FlutterVersion get flutterVersion => context.get<FlutterVersion>();
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'android/android_studio.dart';
import 'base/config.dart'; import 'base/config.dart';
import 'base/context.dart'; import 'base/context.dart';
import 'base/error_handling_io.dart'; import 'base/error_handling_io.dart';
...@@ -26,6 +27,7 @@ HttpClientFactory get httpClientFactory => context.get<HttpClientFactory>()!; ...@@ -26,6 +27,7 @@ HttpClientFactory get httpClientFactory => context.get<HttpClientFactory>()!;
Logger get logger => context.get<Logger>()!; Logger get logger => context.get<Logger>()!;
OperatingSystemUtils get os => context.get<OperatingSystemUtils>()!; OperatingSystemUtils get os => context.get<OperatingSystemUtils>()!;
Signals get signals => context.get<Signals>() ?? LocalSignals.instance; Signals get signals => context.get<Signals>() ?? LocalSignals.instance;
AndroidStudio? get androidStudio => context.get<AndroidStudio>();
/// Currently active implementation of the file system. /// Currently active implementation of the file system.
/// ///
......
...@@ -174,6 +174,39 @@ void main() { ...@@ -174,6 +174,39 @@ void main() {
PlistParser: () => plistUtils, PlistParser: () => plistUtils,
}); });
testUsingContext('finds latest valid install', () {
final String applicationPlistFolder = globals.fs.path.join(
'/',
'Applications',
'Android Studio.app',
'Contents',
);
globals.fs.directory(applicationPlistFolder).createSync(recursive: true);
final String applicationsPlistFilePath = globals.fs.path.join(applicationPlistFolder, 'Info.plist');
plistUtils.fileContents[applicationsPlistFilePath] = macStudioInfoPlist;
final String homeDirectoryPlistFolder = globals.fs.path.join(
globals.fsUtils.homeDirPath,
'Applications',
'Android Studio.app',
'Contents',
);
globals.fs.directory(homeDirectoryPlistFolder).createSync(recursive: true);
final String homeDirectoryPlistFilePath = globals.fs.path.join(homeDirectoryPlistFolder, 'Info.plist');
plistUtils.fileContents[homeDirectoryPlistFilePath] = macStudioInfoPlist4_1;
expect(AndroidStudio.allInstalled().length, 2);
expect(AndroidStudio.latestValid().version, Version(4, 1, 0));
}, overrides: <Type, Generator>{
FileSystem: () => fileSystem,
FileSystemUtils: () => fsUtils,
ProcessManager: () => FakeProcessManager.any(),
Platform: () => platform,
PlistParser: () => plistUtils,
});
testUsingContext('extracts custom paths for directly downloaded Android Studio on Mac', () { testUsingContext('extracts custom paths for directly downloaded Android Studio on Mac', () {
final String studioInApplicationPlistFolder = globals.fs.path.join( final String studioInApplicationPlistFolder = globals.fs.path.join(
'/', '/',
......
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