| // Copyright 2013 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 'base/file_system.dart'; |
| import 'base/logger.dart'; |
| import 'flutter_project_metadata.dart'; |
| import 'utils.dart'; |
| |
| /// Handles the custom/manual merging of one file at `localPath`. |
| /// |
| /// The `merge` method should be overridden to implement custom merging. |
| abstract class CustomMerge { |
| CustomMerge({ |
| required this.logger, |
| required this.localPath, |
| }); |
| |
| /// The local path (with the project root as the root directory) of the file to merge. |
| final String localPath; |
| final Logger logger; |
| |
| /// Called to perform a custom three way merge between the current, |
| /// base, and target files. |
| MergeResult merge(File current, File base, File target); |
| } |
| |
| /// Manually merges a flutter .metadata file. |
| /// |
| /// See `FlutterProjectMetadata`. |
| class MetadataCustomMerge extends CustomMerge { |
| MetadataCustomMerge({ |
| required super.logger, |
| }) : super(localPath: '.metadata'); |
| |
| @override |
| MergeResult merge(File current, File base, File target) { |
| final FlutterProjectMetadata result = computeMerge( |
| FlutterProjectMetadata(current, logger), |
| FlutterProjectMetadata(base, logger), |
| FlutterProjectMetadata(target, logger), |
| logger, |
| ); |
| return StringMergeResult.explicit( |
| mergedString: result.toString(), |
| hasConflict: false, |
| exitCode: 0, |
| localPath: localPath, |
| ); |
| } |
| |
| FlutterProjectMetadata computeMerge( |
| FlutterProjectMetadata current, |
| FlutterProjectMetadata base, |
| FlutterProjectMetadata target, |
| Logger logger) { |
| // Prefer to update the version revision and channel to latest version. |
| final String? versionRevision = target.versionRevision ?? |
| current.versionRevision ?? |
| base.versionRevision; |
| final String? versionChannel = |
| target.versionChannel ?? current.versionChannel ?? base.versionChannel; |
| // Prefer to leave the project type untouched as it is non-trivial to change project type. |
| final FlutterProjectType? projectType = |
| current.projectType ?? base.projectType ?? target.projectType; |
| final MigrateConfig migrateConfig = mergeMigrateConfig( |
| current.migrateConfig, |
| target.migrateConfig, |
| ); |
| final FlutterProjectMetadata output = FlutterProjectMetadata.explicit( |
| file: current.file, |
| versionRevision: versionRevision, |
| versionChannel: versionChannel, |
| projectType: projectType, |
| migrateConfig: migrateConfig, |
| logger: logger, |
| ); |
| return output; |
| } |
| |
| MigrateConfig mergeMigrateConfig( |
| MigrateConfig current, MigrateConfig target) { |
| // Create the superset of current and target platforms with baseRevision updated to be that of target. |
| final Map<FlutterProjectComponent, MigratePlatformConfig> |
| projectComponentConfigs = |
| <FlutterProjectComponent, MigratePlatformConfig>{}; |
| for (final MapEntry<FlutterProjectComponent, MigratePlatformConfig> entry |
| in current.platformConfigs.entries) { |
| if (target.platformConfigs.containsKey(entry.key)) { |
| projectComponentConfigs[entry.key] = MigratePlatformConfig( |
| component: entry.value.component, |
| createRevision: entry.value.createRevision, |
| baseRevision: target.platformConfigs[entry.key]?.baseRevision); |
| } else { |
| projectComponentConfigs[entry.key] = entry.value; |
| } |
| } |
| for (final MapEntry<FlutterProjectComponent, MigratePlatformConfig> entry |
| in target.platformConfigs.entries) { |
| if (!projectComponentConfigs.containsKey(entry.key)) { |
| projectComponentConfigs[entry.key] = entry.value; |
| } |
| } |
| |
| // Ignore the base file list. |
| final List<String> unmanagedFiles = |
| List<String>.from(current.unmanagedFiles); |
| for (final String path in target.unmanagedFiles) { |
| if (!unmanagedFiles.contains(path) && |
| !MigrateConfig.kDefaultUnmanagedFiles.contains(path)) { |
| unmanagedFiles.add(path); |
| } |
| } |
| return MigrateConfig( |
| platformConfigs: projectComponentConfigs, |
| unmanagedFiles: unmanagedFiles, |
| ); |
| } |
| } |