execute method

  1. @override
Future<int> execute(
  1. List<String> arguments
)
override

Executes the command with the provided arguments. Returns an integer exit code (0 for success).

Implementation

@override
Future<int> execute(List<String> arguments) async {
  final ArgResults results;
  try {
    results = _argParser.parse(arguments);
  } on FormatException catch (e) {
    throw ValidationException(
      'Error: ${e.message}\n\nUsage:\n  flutter_setup create [<project_name>] [--template <name>] [--force]',
    );
  }

  final bool forceFlag = results['force'] as bool? ?? false;
  final bool isInteractive = results.rest.isEmpty;
  CreateProjectRequest request;

  if (!isInteractive) {
    // Non-interactive path from CLI flags/arguments
    final projectName = results.rest.first;
    final templateName = results['template'] as String? ?? 'default';
    request = CreateProjectRequest(
      projectName: projectName,
      templateName: templateName,
      force: forceFlag,
    );
  } else {
    // Interactive prompting path when no project name argument is passed
    request = _promptForProjectRequest(force: forceFlag);
  }

  // Common validation and destination checks
  Validators.validateFlutterProjectName(request.projectName);

  String targetPath = workingDirectory != null
      ? p.join(workingDirectory!, request.projectName)
      : request.projectName;
  bool force = request.force;

  while (
      Directory(targetPath).existsSync() || File(targetPath).existsSync()) {
    if (force) {
      // Delete existing directory contents BEFORE running flutter create
      final targetDir = Directory(targetPath);
      if (targetDir.existsSync()) {
        try {
          targetDir.deleteSync(recursive: true);
        } catch (e) {
          throw CliException(
              'Failed to clear target directory "$targetPath": $e');
        }
      } else if (File(targetPath).existsSync()) {
        File(targetPath).deleteSync();
      }
      break;
    }

    if (!isInteractive) {
      throw DestinationConflictException(
        targetPath,
        customMessage:
            'Target directory "$targetPath" already exists. Use --force to overwrite.',
      );
    }

    _output.warning('Directory "$targetPath" already exists.');
    final choice = _prompter.askChoice(
      'Action',
      ['Cancel', 'Overwrite', 'Choose a different name'],
      defaultValue: 'Cancel',
    );

    if (choice == 'Cancel') {
      throw DestinationConflictException(
        targetPath,
        customMessage: 'Project generation cancelled by user.',
      );
    } else if (choice == 'Overwrite') {
      force = true;
    } else {
      // Prompt for a different name and validate
      final newRequest = _promptForProjectRequest(force: force);
      Validators.validateFlutterProjectName(newRequest.projectName);
      request = newRequest;
      targetPath = workingDirectory != null
          ? p.join(workingDirectory!, request.projectName)
          : request.projectName;
    }
  }

  final template = _repository.getTemplate(request.templateName);

  _output.info('Creating Flutter project "${request.projectName}"...');

  final context = GeneratorContext(
    projectName: request.projectName,
    template: template,
    targetDirectory: targetPath,
  );

  final GenerationResult result;
  try {
    result = await _generator.generate(context);
  } on PackageInstallException catch (e) {
    _output.error('Error: Failed to install package "${e.packageName}".');
    _output.error('Reason: ${e.errorDetails}\n');
    if (e.installedBeforeFailure.isNotEmpty) {
      _output.info(
          'Successfully installed before failure: ${e.installedBeforeFailure.join(', ')}');
    }
    return e.exitCode;
  } on CliException catch (e) {
    _output.error('Project generation failed: ${e.message}');
    return e.exitCode;
  } catch (e) {
    _output.error('An unexpected error occurred during generation: $e');
    return 1;
  }

  // Success summary
  _output.success('Flutter project created');
  _output.success('Applied template "${template.name}"');
  _output.success(
    'Generated ${result.renderResult.createdFiles.length} files, ${result.renderResult.createdFolders.length} folders',
  );
  if (result.installResult.installedDependencies.isNotEmpty) {
    _output.success(
      'Installed dependencies (${result.installResult.installedDependencies.length})',
    );
  }
  if (result.installResult.installedDevDependencies.isNotEmpty) {
    _output.success(
      'Installed dev dependencies (${result.installResult.installedDevDependencies.length})',
    );
  }
  _output.success('Dependencies resolved (flutter pub get)');

  if (result.discoveredAssetsCount > 0) {
    _output.success('Assets discovered (${result.discoveredAssetsCount})');
    _output.success('pubspec.yaml updated');
    _output.success(
      'Assets class generated (${result.assetsClassPath ?? "lib/core/constants/assets.dart"})',
    );
  } else {
    _output
        .info('⊘ No assets found in template — skipping asset registration');
  }

  final platformSetupFile = File(p.join(targetPath, 'PLATFORM_SETUP.md'));
  if (platformSetupFile.existsSync()) {
    _output.warning(
      '⚠ Some packages require platform-specific setup — see PLATFORM_SETUP.md before running on a real device',
    );
  }

  _output.info('\nProject ready at ./${request.projectName}');

  return 0;
}