blob: d2dfe8db7459cee2fe1aa046095cb295d81b9e1f [file] [log] [blame]
// Copyright 2014 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 'package:meta/meta.dart';
import 'file_system.dart';
import 'logger.dart';
/// Project is generated from a template on Flutter project creation.
/// Sometimes (due to behavior changes in Xcode, Gradle, etc) these files need to be altered
/// from the original template.
abstract class ProjectMigrator {
final Logger logger;
/// Returns whether migration was successful or was skipped.
bool migrate();
/// Return null if the line should be deleted.
String? migrateLine(String line) {
return line;
String migrateFileContents(String fileContents) {
return fileContents;
bool get migrationRequired => _migrationRequired;
bool _migrationRequired = false;
/// Calls [migrateLine] per line, then [migrateFileContents]
/// including the line migrations.
void processFileLines(File file) {
final List<String> lines = file.readAsLinesSync();
final StringBuffer newProjectContents = StringBuffer();
final String basename = file.basename;
for (final String line in lines) {
final String? newProjectLine = migrateLine(line);
if (newProjectLine == null) {
logger.printTrace('Migrating $basename, removing:');
logger.printTrace(' $line');
_migrationRequired = true;
if (newProjectLine != line) {
logger.printTrace('Migrating $basename, replacing:');
logger.printTrace(' $line');
logger.printTrace(' $newProjectLine');
_migrationRequired = true;
final String projectContentsWithMigratedLines = newProjectContents.toString();
final String projectContentsWithMigratedContents = migrateFileContents(projectContentsWithMigratedLines);
if (projectContentsWithMigratedLines != projectContentsWithMigratedContents) {
logger.printTrace('Migrating $basename contents');
_migrationRequired = true;
if (migrationRequired) {
logger.printStatus('Upgrading $basename');
class ProjectMigration {
final List<ProjectMigrator> migrators;
bool run() {
for (final ProjectMigrator migrator in migrators) {
if (!migrator.migrate()) {
// Migration failures should be more robust, with transactions and fallbacks.
// See and
return false;
return true;