Unverified Commit ddfcda73 authored by Gary Qian's avatar Gary Qian Committed by GitHub

Track platform in MigratePlaformConfig and enforce metadata file being provided (#110540)

parent 0508a1de
...@@ -72,22 +72,21 @@ FlutterProjectType? stringToProjectType(String value) { ...@@ -72,22 +72,21 @@ FlutterProjectType? stringToProjectType(String value) {
/// A wrapper around the `.metadata` file. /// A wrapper around the `.metadata` file.
class FlutterProjectMetadata { class FlutterProjectMetadata {
/// Creates a MigrateConfig by parsing an existing .migrate_config yaml file. /// Creates a MigrateConfig by parsing an existing .migrate_config yaml file.
FlutterProjectMetadata(File file, Logger logger) : _metadataFile = file, FlutterProjectMetadata(this.file, Logger logger) : _logger = logger,
_logger = logger,
migrateConfig = MigrateConfig() { migrateConfig = MigrateConfig() {
if (!_metadataFile.existsSync()) { if (!file.existsSync()) {
_logger.printTrace('No .metadata file found at ${_metadataFile.path}.'); _logger.printTrace('No .metadata file found at ${file.path}.');
// Create a default empty metadata. // Create a default empty metadata.
return; return;
} }
Object? yamlRoot; Object? yamlRoot;
try { try {
yamlRoot = loadYaml(_metadataFile.readAsStringSync()); yamlRoot = loadYaml(file.readAsStringSync());
} on YamlException { } on YamlException {
// Handled in _validate below. // Handled in _validate below.
} }
if (yamlRoot is! YamlMap) { if (yamlRoot is! YamlMap) {
_logger.printTrace('.metadata file at ${_metadataFile.path} was empty or malformed.'); _logger.printTrace('.metadata file at ${file.path} was empty or malformed.');
return; return;
} }
if (_validateMetadataMap(yamlRoot, <String, Type>{'version': YamlMap}, _logger)) { if (_validateMetadataMap(yamlRoot, <String, Type>{'version': YamlMap}, _logger)) {
...@@ -109,9 +108,9 @@ class FlutterProjectMetadata { ...@@ -109,9 +108,9 @@ class FlutterProjectMetadata {
} }
} }
/// Creates a MigrateConfig by explicitly providing all values. /// Creates a FlutterProjectMetadata by explicitly providing all values.
FlutterProjectMetadata.explicit({ FlutterProjectMetadata.explicit({
required File file, required this.file,
required String? versionRevision, required String? versionRevision,
required String? versionChannel, required String? versionChannel,
required FlutterProjectType? projectType, required FlutterProjectType? projectType,
...@@ -120,8 +119,7 @@ class FlutterProjectMetadata { ...@@ -120,8 +119,7 @@ class FlutterProjectMetadata {
}) : _logger = logger, }) : _logger = logger,
_versionChannel = versionChannel, _versionChannel = versionChannel,
_versionRevision = versionRevision, _versionRevision = versionRevision,
_projectType = projectType, _projectType = projectType;
_metadataFile = file;
/// The name of the config file. /// The name of the config file.
static const String kFileName = '.metadata'; static const String kFileName = '.metadata';
...@@ -140,17 +138,27 @@ class FlutterProjectMetadata { ...@@ -140,17 +138,27 @@ class FlutterProjectMetadata {
final Logger _logger; final Logger _logger;
final File _metadataFile; final File file;
/// Writes the .migrate_config file in the provided project directory's platform subdirectory. /// Writes the .migrate_config file in the provided project directory's platform subdirectory.
/// ///
/// We write the file manually instead of with a template because this /// We write the file manually instead of with a template because this
/// needs to be able to write the .migrate_config file into legacy apps. /// needs to be able to write the .migrate_config file into legacy apps.
void writeFile({File? outputFile}) { void writeFile({File? outputFile}) {
outputFile = outputFile ?? _metadataFile; outputFile = outputFile ?? file;
if (outputFile == null) {
// In-memory FlutterProjectMetadata instances requires an output file to
// be passed or specified in the constructor.
throw const FileSystemException('No outputFile specified to write .metadata to. Initialize with a file or provide one when writing.');
}
outputFile outputFile
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync(''' ..writeAsStringSync(toString(), flush: true);
}
@override
String toString() {
return '''
# This file tracks properties of this Flutter project. # This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc. # Used by Flutter tool to assess capabilities and perform upgrades etc.
# #
...@@ -161,13 +169,12 @@ version: ...@@ -161,13 +169,12 @@ version:
channel: $_versionChannel channel: $_versionChannel
project_type: ${flutterProjectTypeToString(projectType)} project_type: ${flutterProjectTypeToString(projectType)}
${migrateConfig.getOutputFileString()}''', ${migrateConfig.getOutputFileString()}''';
flush: true);
} }
void populate({ void populate({
List<SupportedPlatform>? platforms, List<SupportedPlatform>? platforms,
Directory? projectDirectory, required Directory projectDirectory,
String? currentRevision, String? currentRevision,
String? createRevision, String? createRevision,
bool create = true, bool create = true,
...@@ -205,11 +212,11 @@ ${migrateConfig.getOutputFileString()}''', ...@@ -205,11 +212,11 @@ ${migrateConfig.getOutputFileString()}''',
class MigrateConfig { class MigrateConfig {
MigrateConfig({ MigrateConfig({
Map<SupportedPlatform, MigratePlatformConfig>? platformConfigs, Map<SupportedPlatform, MigratePlatformConfig>? platformConfigs,
this.unmanagedFiles = _kDefaultUnmanagedFiles this.unmanagedFiles = kDefaultUnmanagedFiles
}) : platformConfigs = platformConfigs ?? <SupportedPlatform, MigratePlatformConfig>{}; }) : platformConfigs = platformConfigs ?? <SupportedPlatform, MigratePlatformConfig>{};
/// A mapping of the files that are unmanaged by defult for each platform. /// A mapping of the files that are unmanaged by defult for each platform.
static const List<String> _kDefaultUnmanagedFiles = <String>[ static const List<String> kDefaultUnmanagedFiles = <String>[
'lib/main.dart', 'lib/main.dart',
'ios/Runner.xcodeproj/project.pbxproj', 'ios/Runner.xcodeproj/project.pbxproj',
]; ];
...@@ -222,20 +229,20 @@ class MigrateConfig { ...@@ -222,20 +229,20 @@ class MigrateConfig {
/// These files are typically user-owned files that should not be changed. /// These files are typically user-owned files that should not be changed.
List<String> unmanagedFiles; List<String> unmanagedFiles;
bool get isEmpty => platformConfigs.isEmpty && (unmanagedFiles.isEmpty || unmanagedFiles == _kDefaultUnmanagedFiles); bool get isEmpty => platformConfigs.isEmpty && (unmanagedFiles.isEmpty || unmanagedFiles == kDefaultUnmanagedFiles);
/// Parses the project for all supported platforms and populates the [MigrateConfig] /// Parses the project for all supported platforms and populates the [MigrateConfig]
/// to reflect the project. /// to reflect the project.
void populate({ void populate({
List<SupportedPlatform>? platforms, List<SupportedPlatform>? platforms,
Directory? projectDirectory, required Directory projectDirectory,
String? currentRevision, String? currentRevision,
String? createRevision, String? createRevision,
bool create = true, bool create = true,
bool update = true, bool update = true,
required Logger logger, required Logger logger,
}) { }) {
final FlutterProject flutterProject = projectDirectory == null ? FlutterProject.current() : FlutterProject.fromDirectory(projectDirectory); final FlutterProject flutterProject = FlutterProject.fromDirectory(projectDirectory);
platforms ??= flutterProject.getSupportedPlatforms(includeRoot: true); platforms ??= flutterProject.getSupportedPlatforms(includeRoot: true);
for (final SupportedPlatform platform in platforms) { for (final SupportedPlatform platform in platforms) {
...@@ -245,7 +252,7 @@ class MigrateConfig { ...@@ -245,7 +252,7 @@ class MigrateConfig {
} }
} else { } else {
if (create) { if (create) {
platformConfigs[platform] = MigratePlatformConfig(createRevision: createRevision, baseRevision: currentRevision); platformConfigs[platform] = MigratePlatformConfig(platform: platform, createRevision: createRevision, baseRevision: currentRevision);
} }
} }
} }
...@@ -290,10 +297,11 @@ migration: ...@@ -290,10 +297,11 @@ migration:
'create_revision': String, 'create_revision': String,
'base_revision': String, 'base_revision': String,
}, logger)) { }, logger)) {
final SupportedPlatform platformString = SupportedPlatform.values.firstWhere( final SupportedPlatform platformValue = SupportedPlatform.values.firstWhere(
(SupportedPlatform val) => val.toString() == 'SupportedPlatform.${platformYamlMap['platform'] as String}' (SupportedPlatform val) => val.toString() == 'SupportedPlatform.${platformYamlMap['platform'] as String}'
); );
platformConfigs[platformString] = MigratePlatformConfig( platformConfigs[platformValue] = MigratePlatformConfig(
platform: platformValue,
createRevision: platformYamlMap['create_revision'] as String?, createRevision: platformYamlMap['create_revision'] as String?,
baseRevision: platformYamlMap['base_revision'] as String?, baseRevision: platformYamlMap['base_revision'] as String?,
); );
...@@ -315,7 +323,14 @@ migration: ...@@ -315,7 +323,14 @@ migration:
/// Holds the revisions for a single platform for use by the flutter migrate command. /// Holds the revisions for a single platform for use by the flutter migrate command.
class MigratePlatformConfig { class MigratePlatformConfig {
MigratePlatformConfig({this.createRevision, this.baseRevision}); MigratePlatformConfig({
required this.platform,
this.createRevision,
this.baseRevision
});
/// The platform this config describes.
SupportedPlatform platform;
/// The Flutter SDK revision this platform was created by. /// The Flutter SDK revision this platform was created by.
/// ///
...@@ -326,4 +341,10 @@ class MigratePlatformConfig { ...@@ -326,4 +341,10 @@ class MigratePlatformConfig {
/// ///
/// Null if the project was never migrated or the revision is unknown. /// Null if the project was never migrated or the revision is unknown.
String? baseRevision; String? baseRevision;
bool equals(MigratePlatformConfig other) {
return platform == other.platform &&
createRevision == other.createRevision &&
baseRevision == other.baseRevision;
}
} }
...@@ -105,10 +105,10 @@ project_type: app ...@@ -105,10 +105,10 @@ project_type: app
const String testBaseRevision = 'testanas9anlnq9ba7bjhavan3kma'; const String testBaseRevision = 'testanas9anlnq9ba7bjhavan3kma';
MigrateConfig config = MigrateConfig( MigrateConfig config = MigrateConfig(
platformConfigs: <SupportedPlatform, MigratePlatformConfig>{ platformConfigs: <SupportedPlatform, MigratePlatformConfig>{
SupportedPlatform.android: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), SupportedPlatform.android: MigratePlatformConfig(platform: SupportedPlatform.android, createRevision: testCreateRevision, baseRevision: testBaseRevision),
SupportedPlatform.ios: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), SupportedPlatform.ios: MigratePlatformConfig(platform: SupportedPlatform.ios, createRevision: testCreateRevision, baseRevision: testBaseRevision),
SupportedPlatform.root: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), SupportedPlatform.root: MigratePlatformConfig(platform: SupportedPlatform.root, createRevision: testCreateRevision, baseRevision: testBaseRevision),
SupportedPlatform.windows: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), SupportedPlatform.windows: MigratePlatformConfig(platform: SupportedPlatform.windows, createRevision: testCreateRevision, baseRevision: testBaseRevision),
}, },
unmanagedFiles: <String>[ unmanagedFiles: <String>[
'lib/main.dart', 'lib/main.dart',
...@@ -224,4 +224,15 @@ migration: ...@@ -224,4 +224,15 @@ migration:
- 'ios/Runner.xcodeproj/project.pbxproj' - 'ios/Runner.xcodeproj/project.pbxproj'
''')); '''));
}); });
testUsingContext('equality compares platform', () async {
const String testCreateRevision = 'testmc9skl32nlnf23lnakcs9njr3';
const String testBaseRevision = 'testanas9anlnq9ba7bjhavan3kma';
final MigratePlatformConfig configAndroid = MigratePlatformConfig(platform: SupportedPlatform.android, createRevision: testCreateRevision, baseRevision: testBaseRevision);
final MigratePlatformConfig configIos = MigratePlatformConfig(platform: SupportedPlatform.ios, createRevision: testCreateRevision, baseRevision: testBaseRevision);
expect(configAndroid.equals(configIos), false);
expect(configAndroid.equals(configAndroid), true);
expect(configIos.equals(configIos), true);
});
} }
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