From ddfcda73cd7effbf9f23dae08e9eca22d634776d Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Wed, 31 Aug 2022 12:04:22 -0700 Subject: [PATCH] Track platform in MigratePlaformConfig and enforce metadata file being provided (#110540) --- .../lib/src/flutter_project_metadata.dart | 71 ++++++++++++------- .../migrate_config_test.dart | 19 +++-- 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/packages/flutter_tools/lib/src/flutter_project_metadata.dart b/packages/flutter_tools/lib/src/flutter_project_metadata.dart index 4e0fa787e2..2f3fbe3b60 100644 --- a/packages/flutter_tools/lib/src/flutter_project_metadata.dart +++ b/packages/flutter_tools/lib/src/flutter_project_metadata.dart @@ -72,22 +72,21 @@ FlutterProjectType? stringToProjectType(String value) { /// A wrapper around the `.metadata` file. class FlutterProjectMetadata { /// Creates a MigrateConfig by parsing an existing .migrate_config yaml file. - FlutterProjectMetadata(File file, Logger logger) : _metadataFile = file, - _logger = logger, + FlutterProjectMetadata(this.file, Logger logger) : _logger = logger, migrateConfig = MigrateConfig() { - if (!_metadataFile.existsSync()) { - _logger.printTrace('No .metadata file found at ${_metadataFile.path}.'); + if (!file.existsSync()) { + _logger.printTrace('No .metadata file found at ${file.path}.'); // Create a default empty metadata. return; } Object? yamlRoot; try { - yamlRoot = loadYaml(_metadataFile.readAsStringSync()); + yamlRoot = loadYaml(file.readAsStringSync()); } on YamlException { // Handled in _validate below. } 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; } if (_validateMetadataMap(yamlRoot, {'version': YamlMap}, _logger)) { @@ -109,9 +108,9 @@ class FlutterProjectMetadata { } } - /// Creates a MigrateConfig by explicitly providing all values. + /// Creates a FlutterProjectMetadata by explicitly providing all values. FlutterProjectMetadata.explicit({ - required File file, + required this.file, required String? versionRevision, required String? versionChannel, required FlutterProjectType? projectType, @@ -120,8 +119,7 @@ class FlutterProjectMetadata { }) : _logger = logger, _versionChannel = versionChannel, _versionRevision = versionRevision, - _projectType = projectType, - _metadataFile = file; + _projectType = projectType; /// The name of the config file. static const String kFileName = '.metadata'; @@ -140,17 +138,27 @@ class FlutterProjectMetadata { final Logger _logger; - final File _metadataFile; + final File file; /// 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 /// needs to be able to write the .migrate_config file into legacy apps. 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 ..createSync(recursive: true) - ..writeAsStringSync(''' + ..writeAsStringSync(toString(), flush: true); + } + + @override + String toString() { + return ''' # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # @@ -161,13 +169,12 @@ version: channel: $_versionChannel project_type: ${flutterProjectTypeToString(projectType)} -${migrateConfig.getOutputFileString()}''', - flush: true); +${migrateConfig.getOutputFileString()}'''; } void populate({ List? platforms, - Directory? projectDirectory, + required Directory projectDirectory, String? currentRevision, String? createRevision, bool create = true, @@ -205,11 +212,11 @@ ${migrateConfig.getOutputFileString()}''', class MigrateConfig { MigrateConfig({ Map? platformConfigs, - this.unmanagedFiles = _kDefaultUnmanagedFiles + this.unmanagedFiles = kDefaultUnmanagedFiles }) : platformConfigs = platformConfigs ?? {}; /// A mapping of the files that are unmanaged by defult for each platform. - static const List _kDefaultUnmanagedFiles = [ + static const List kDefaultUnmanagedFiles = [ 'lib/main.dart', 'ios/Runner.xcodeproj/project.pbxproj', ]; @@ -222,20 +229,20 @@ class MigrateConfig { /// These files are typically user-owned files that should not be changed. List 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] /// to reflect the project. void populate({ List? platforms, - Directory? projectDirectory, + required Directory projectDirectory, String? currentRevision, String? createRevision, bool create = true, bool update = true, required Logger logger, }) { - final FlutterProject flutterProject = projectDirectory == null ? FlutterProject.current() : FlutterProject.fromDirectory(projectDirectory); + final FlutterProject flutterProject = FlutterProject.fromDirectory(projectDirectory); platforms ??= flutterProject.getSupportedPlatforms(includeRoot: true); for (final SupportedPlatform platform in platforms) { @@ -245,7 +252,7 @@ class MigrateConfig { } } else { if (create) { - platformConfigs[platform] = MigratePlatformConfig(createRevision: createRevision, baseRevision: currentRevision); + platformConfigs[platform] = MigratePlatformConfig(platform: platform, createRevision: createRevision, baseRevision: currentRevision); } } } @@ -290,10 +297,11 @@ migration: 'create_revision': String, 'base_revision': String, }, logger)) { - final SupportedPlatform platformString = SupportedPlatform.values.firstWhere( + final SupportedPlatform platformValue = SupportedPlatform.values.firstWhere( (SupportedPlatform val) => val.toString() == 'SupportedPlatform.${platformYamlMap['platform'] as String}' ); - platformConfigs[platformString] = MigratePlatformConfig( + platformConfigs[platformValue] = MigratePlatformConfig( + platform: platformValue, createRevision: platformYamlMap['create_revision'] as String?, baseRevision: platformYamlMap['base_revision'] as String?, ); @@ -315,7 +323,14 @@ migration: /// Holds the revisions for a single platform for use by the flutter migrate command. 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. /// @@ -326,4 +341,10 @@ class MigratePlatformConfig { /// /// Null if the project was never migrated or the revision is unknown. String? baseRevision; + + bool equals(MigratePlatformConfig other) { + return platform == other.platform && + createRevision == other.createRevision && + baseRevision == other.baseRevision; + } } diff --git a/packages/flutter_tools/test/integration.shard/migrate_config_test.dart b/packages/flutter_tools/test/integration.shard/migrate_config_test.dart index 0792d30e2c..8d5a9f7418 100644 --- a/packages/flutter_tools/test/integration.shard/migrate_config_test.dart +++ b/packages/flutter_tools/test/integration.shard/migrate_config_test.dart @@ -105,10 +105,10 @@ project_type: app const String testBaseRevision = 'testanas9anlnq9ba7bjhavan3kma'; MigrateConfig config = MigrateConfig( platformConfigs: { - SupportedPlatform.android: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), - SupportedPlatform.ios: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), - SupportedPlatform.root: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), - SupportedPlatform.windows: MigratePlatformConfig(createRevision: testCreateRevision, baseRevision: testBaseRevision), + SupportedPlatform.android: MigratePlatformConfig(platform: SupportedPlatform.android, createRevision: testCreateRevision, baseRevision: testBaseRevision), + SupportedPlatform.ios: MigratePlatformConfig(platform: SupportedPlatform.ios, createRevision: testCreateRevision, baseRevision: testBaseRevision), + SupportedPlatform.root: MigratePlatformConfig(platform: SupportedPlatform.root, createRevision: testCreateRevision, baseRevision: testBaseRevision), + SupportedPlatform.windows: MigratePlatformConfig(platform: SupportedPlatform.windows, createRevision: testCreateRevision, baseRevision: testBaseRevision), }, unmanagedFiles: [ 'lib/main.dart', @@ -224,4 +224,15 @@ migration: - '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); + }); }