run method

  1. @override
void run()
override

Runs this command.

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

Implementation

@override
void run() async {
  final root = findNitroProjectRoot();
  if (root == null) {
    stderr.writeln(red('No pubspec.yaml found containing a Nitrogen dependency.'));
    exit(1);
  }

  // Attempt to parse project info for name

  stdout.writeln(cyan('\n⚡ Starting Nitrogen Watch Mode (build_runner watch)...'));
  stdout.writeln(dim('Project: ${root.path}\n'));

  // 1. Kill any existing build_runner before starting a new one.
  //    build_runner uses a lock file — a second invocation hangs waiting
  //    for the lock. Stopping the old instance (and clearing the lock)
  //    lets the new watch process start immediately without hanging.
  stdout.writeln(gray('  › Stopping any existing build_runner instance...'));
  final killed = await killBuildRunner(workingDirectory: root.path);
  if (killed > 0) {
    stdout.writeln(gray('  ✔ Stopped previous build_runner.'));
  } else {
    stdout.writeln(gray('  ✔ No existing build_runner found.'));
  }
  stdout.writeln('');

  // Always clear the build cache so watch starts fresh — same as generate.
  // Without this a stale lock from a previously crashed process blocks startup.
  final buildCache = Directory(p.join(root.path, '.dart_tool', 'build'));
  if (buildCache.existsSync()) {
    try { buildCache.deleteSync(recursive: true); } catch (_) {}
  }

  // 2. Initial bridge sync to make sure everything is wired
  stdout.writeln(gray('  - Performing initial bridge sync...'));
  syncBridgeFiles(root.path);

  // 3. Start the watcher for .native.dart file additions/removals
  // (This acts as a backup, but build_runner handles the generation itself)
  final specWatcher = DirectoryWatcher(root.path);
  specWatcher.events.listen((event) {
    // Just logging or reacting to file-system level changes
  });

  // 4. Run build_runner watch and pipe output
  final stream = streamProcess('flutter', [
    'pub',
    'run',
    'build_runner',
    'watch',
    '--delete-conflicting-outputs',
  ], workingDirectory: root.path);

  await for (final line in stream) {
    stdout.writeln(line);

    // When build_runner says it finished a build, sync the bridge files to iOS
    if (line.contains('Succeeded after')) {
      stdout.writeln(green('  ✨ Generation complete. Syncing bridge files to iOS...'));
      try {
        syncBridgeFiles(root.path);
        stdout.writeln(dim('  ✔ Sync successful.\n'));
      } catch (e) {
        stdout.writeln(red('  ✘ Sync failed: $e'));
      }
    }

    if (line.contains('Failed after')) {
      stdout.writeln(red('  ✘ Generation failed. Fix the errors to continue syncing.'));
    }
  }
}