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 rest = results.rest;
  if (rest.length > 1) {
    stderr.writeln('serve takes at most one positional argument.');
    return 64;
  }
  final root = rest.isEmpty
      ? Directory.current.path
      : p.normalize(p.absolute(rest.first));

  final portRaw = results['port'] as String;
  final port = int.tryParse(portRaw);
  if (port == null || port < 0 || port > 65535) {
    stderr.writeln('--port must be an integer 0–65535, got `$portRaw`.');
    return 64;
  }
  final host = results['host'] as String;

  // Eager-load once just to surface "no project" early — the
  // request middleware re-loads on every call.
  try {
    DialectProject.load(root);
  } on FileSystemException catch (e) {
    stderr.writeln(e.message);
    stderr.writeln(
      'Run `dialect init` first, or pass the project root as an argument.',
    );
    return 66;
  } on FormatException catch (e) {
    stderr.writeln('dialect.yaml or an ARB file is malformed:');
    stderr.writeln('  ${e.message}');
    return 65;
  }

  final HttpServer server;
  try {
    server = await startServer(projectRoot: root, host: host, port: port);
  } on SocketException catch (e) {
    stderr.writeln(
      'Could not bind $host:$port — ${e.osError?.message ?? e.message}.',
    );
    stderr.writeln(
      'Try a different port with `--port`, or stop the process holding it.',
    );
    return 1;
  }

  stdout.writeln('Dialect Review running at http://$host:${server.port}');
  stdout.writeln('Reading from: $root');
  if (!hasEmbeddedDashboard) {
    stdout.writeln('');
    stdout.writeln(
      '  Note: SPA assets are not bundled in this build. The REST API is live,',
    );
    stdout.writeln(
      '  but http://$host:${server.port}/ will show a "not built yet" page.',
    );
    stdout.writeln(
      '  Bake the dashboard in: `dart run tool/build_dashboard.dart`',
    );
  }
  stdout.writeln('');
  stdout.writeln('Press Ctrl-C to stop.');

  // Block until the user kills the process. Tests use `startServer`
  // directly instead of going through `run()`, so they don't need
  // to wait on this.
  final done = Completer<void>();
  final sigint = ProcessSignal.sigint.watch().listen((_) {
    stdout.writeln('\nStopping…');
    done.complete();
  });
  await done.future;
  await sigint.cancel();
  await server.close(force: true);
  return 0;
}