project_migrator.dart 2.82 KB
Newer Older
1 2 3 4 5 6
// 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';

7 8
import 'file_system.dart';
import 'logger.dart';
9

10 11
/// 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
12
/// from the original template.
13 14
abstract class ProjectMigrator {
  ProjectMigrator(this.logger);
15 16 17 18 19

  @protected
  final Logger logger;

  /// Returns whether migration was successful or was skipped.
20 21 22
  bool migrate();

  /// Return null if the line should be deleted.
23
  @protected
24
  String? migrateLine(String line) {
25 26
    return line;
  }
27 28

  @protected
29 30 31 32
  String migrateFileContents(String fileContents) {
    return fileContents;
  }

33 34 35 36
  @protected
  bool get migrationRequired => _migrationRequired;
  bool _migrationRequired = false;

37 38 39
  @protected
  /// Calls [migrateLine] per line, then [migrateFileContents]
  /// including the line migrations.
40
  void processFileLines(File file) {
41 42 43 44 45 46
    final List<String> lines = file.readAsLinesSync();

    final StringBuffer newProjectContents = StringBuffer();
    final String basename = file.basename;

    for (final String line in lines) {
47
      final String? newProjectLine = migrateLine(line);
48 49 50
      if (newProjectLine == null) {
        logger.printTrace('Migrating $basename, removing:');
        logger.printTrace('    $line');
51
        _migrationRequired = true;
52 53 54 55 56 57 58
        continue;
      }
      if (newProjectLine != line) {
        logger.printTrace('Migrating $basename, replacing:');
        logger.printTrace('    $line');
        logger.printTrace('with:');
        logger.printTrace('    $newProjectLine');
59
        _migrationRequired = true;
60 61 62 63
      }
      newProjectContents.writeln(newProjectLine);
    }

64 65 66 67
    final String projectContentsWithMigratedLines = newProjectContents.toString();
    final String projectContentsWithMigratedContents = migrateFileContents(projectContentsWithMigratedLines);
    if (projectContentsWithMigratedLines != projectContentsWithMigratedContents) {
      logger.printTrace('Migrating $basename contents');
68
      _migrationRequired = true;
69 70
    }

71 72
    if (migrationRequired) {
      logger.printStatus('Upgrading $basename');
73
      file.writeAsStringSync(projectContentsWithMigratedContents);
74 75 76
    }
  }
}
77

78 79
class ProjectMigration {
  ProjectMigration(this.migrators);
80

81
  final List<ProjectMigrator> migrators;
82 83

  bool run() {
84
    for (final ProjectMigrator migrator in migrators) {
85 86 87 88 89 90 91 92 93 94
      if (!migrator.migrate()) {
        // Migration failures should be more robust, with transactions and fallbacks.
        // See https://github.com/flutter/flutter/issues/12573 and
        // https://github.com/flutter/flutter/issues/40460
        return false;
      }
    }
    return true;
  }
}