execute method

Future<int> execute()

Executes the generation logic and returns the exit code. Does NOT call exit().

Implementation

Future<int> execute() async {
  final failOnWarn = argResults!['fail-on-warn'] as bool;
  final dryRun = argResults!['dry-run'] as bool;
  final check = argResults!['check'] as bool;
  final targets = _parseTargets(argResults!['targets'] as String?);
  if (targets == null) return 1;

  final startDir = argResults!['directory'] as String?;
  final projectDir = findNitroProjectRoot(startDir: startDir);
  if (projectDir == null) {
    _logError('No Nitro project found in . or its subdirectories (must have nitro dependency in pubspec.yaml).');
    return 1;
  }

  _printGenerateHeader(projectDir);

  if (dryRun) {
    _printDryRunPlan(projectDir.path, targets);
    return 0;
  }

  if (check) {
    return _checkGeneratedFiles(projectDir.path, targets);
  }

  final totalStart = DateTime.now();
  final specFiles = _discoverNativeSpecFiles(projectDir.path);
  final incrementalCache = IncrementalGenerationCache(projectDir.path);
  final incrementalPlan = incrementalCache.plan(
    specs: specFiles,
    outputPathsForSpec: (spec) => _generatedOutputsForSpec(projectDir.path, spec, targets),
  );

  if (!incrementalPlan.hasChanges) {
    _printNoChanges();
    _logTiming('total', DateTime.now().difference(totalStart));
    return 0;
  }

  // ── pub get ─────────────────────────────────────────────────────────────
  final pubGetExit = await _runPubGet(projectDir.path);
  if (pubGetExit != null) return pubGetExit;

  // ── build_runner ─────────────────────────────────────────────────────────
  await _prepareBuildRunner(projectDir.path);
  final buildExit = await _runBuildRunner(projectDir.path, targets, incrementalPlan, failOnWarn);
  if (buildExit != null) return buildExit;

  incrementalCache.write(
    specs: specFiles,
    outputPathsForSpec: (spec) => _generatedOutputsForSpec(projectDir.path, spec, targets),
  );

  // ── Post-generation bridge cleanup ───────────────────────────────────────
  // Generated Swift bridges live in lib/src/generated/swift/ and are compiled
  // via the podspec source_files pattern. Remove any stale copies from Classes/
  // to prevent "Invalid redeclaration" Swift compiler errors.
  if (targets.isDartOnly) {
    _logTiming('total', DateTime.now().difference(totalStart));
    _printGenerationComplete();
    return 0;
  }

  _runLinkPhase(projectDir.path);

  // ── pod install ──────────────────────────────────────────────────────────
  await _runPodInstall(projectDir.path);

  // Detect whether any spec uses NativeImpl.cpp to tailor the next-steps hint
  final libDir = Directory(p.join(projectDir.path, 'lib'));
  final hasCppModules = libDir.existsSync() && libDir.listSync(recursive: true).whereType<File>().where((f) => f.path.endsWith('.native.dart')).any(isCppModule);

  _logTiming('total', DateTime.now().difference(totalStart));
  _reportSuccess(projectDir.path, hasCppModules);
  return 0;
}