run method

  1. @override
Future<int> run()
override

Runs this command.

The return value is wrapped in a Future if necessary and returned by CommandRunner.runCommand.

Implementation

@override
Future<int> run() async {
  final results = argResults!;
  final prefix = results['prefix'] as String;
  final dryRun = results['dry-run'] as bool;
  final inPlace = results['in-place'] as bool;
  final force = results['force'] as bool;
  // Verbose flag isn't on `migrate`'s parser; use a non-verbose
  // logger purely to access the stderr-routing `error()` helper.
  final logger = FLILogger(false);

  // Reject stray positional args before doing anything else.
  final rejectCode = rejectUnknownArgs(results, logger);
  if (rejectCode != null) {
    return rejectCode;
  }

  // 1. Discover legacy files.
  final legacy = _discoverLegacyFiles(prefix);
  if (legacy.isEmpty) {
    stdout.writeln(
      'ℹ No legacy flutter_launcher_icons-<flavor>.yaml files found in '
      '$prefix. Nothing to migrate.',
    );
    return 0;
  }

  // 2. Target existence check (skipped on --dry-run because we're not
  //    writing anything).
  final targetPath = p.join(prefix, constants.consolidatedFlavorsFileName);
  if (!dryRun && File(targetPath).existsSync() && !force) {
    logger.error(
      '$targetPath already exists. Re-run with --force to overwrite, '
      'or move/delete the file first.',
    );
    return 64;
  }

  // 3. Parse each legacy file.
  final flavorBlocks = <String, Map<String, dynamic>>{};
  for (final entry in legacy) {
    try {
      final block = _parseLegacyFile(entry.path);
      flavorBlocks[entry.flavor] = block;
    } on _MigrateParseException catch (e) {
      logger.error('Failed to parse ${entry.path}: ${e.message}');
      return 64;
    } on Exception catch (e) {
      logger.error('Failed to read ${entry.path}: $e');
      return 1;
    }
  }

  // 4. Build the output document.
  final doc = <String, dynamic>{
    'version': 1,
    'defaults': <String, dynamic>{},
    'flavors': flavorBlocks,
  };
  final yamlOut = emitYaml(doc);

  // 5. Compute promotion candidates (keys with identical values across
  //    every flavor block).
  final candidates = _computePromotionCandidates(flavorBlocks);

  // 6. Output / write.
  if (dryRun) {
    stdout.write(yamlOut);
    _printCandidatesReport(candidates);
    return 0;
  }

  // Backup originals before any destructive step.
  for (final entry in legacy) {
    try {
      File(entry.path).copySync('${entry.path}.bak');
    } on Exception catch (e) {
      logger.error('Failed to back up ${entry.path}: $e');
      return 1;
    }
  }

  try {
    File(targetPath).writeAsStringSync(yamlOut);
  } on Exception catch (e) {
    logger.error('Failed to write $targetPath: $e');
    return 1;
  }

  if (inPlace) {
    for (final entry in legacy) {
      try {
        File(entry.path).deleteSync();
      } on Exception catch (e) {
        logger.warn('Could not delete ${entry.path}: $e');
      }
    }
  }

  stdout.writeln('✓ Wrote $targetPath (${flavorBlocks.length} flavors)');
  _printCandidatesReport(candidates);
  return 0;
}