startShellJob method

  1. @override
Future<Result<ShellJob, ExecutionError>> startShellJob(
  1. String command, {
  2. required String id,
  3. required String logPath,
  4. ShellExecOptions? options,
})
override

Starts command detached: stdout/stderr append to logPath and the returned ShellJob keeps running until it exits or is stopped. ShellExecOptions.timeout and ShellExecOptions.cancelToken still apply (both stop the job).

Implementation

@override
Future<Result<ShellJob, ExecutionError>> startShellJob(
  String command, {
  required String id,
  required String logPath,
  ShellExecOptions? options,
}) async {
  final token = options?.cancelToken;
  if (token?.isCancelled ?? false) {
    return const Err(ExecutionError(ExecutionErrorCode.aborted, 'aborted'));
  }
  final started = await _start(command, options);
  if (started.isErr) return Err(started.errorOrNull!);
  final process = started.valueOrNull!;
  // Feed optional stdin data (bash tool `stdin` param), then close the
  // pipe — background jobs are not interactive beyond this.
  if (options?.stdinData != null) {
    try {
      process.stdin.write(options!.stdinData);
      await process.stdin.flush();
    } on Object {
      // Process already gone — the settle path reports the real status.
    }
  }
  unawaited(process.stdin.close());
  final IOSink logSink;
  try {
    logSink = File(logPath).openWrite(mode: FileMode.append);
  } on Object catch (error) {
    process.kill();
    return Err(
      ExecutionError(
        ExecutionErrorCode.spawnError,
        'cannot open job log file $logPath: $error',
        cause: error,
      ),
    );
  }
  return Ok(
    _LocalShellJob(
      id: id,
      command: command,
      logPath: logPath,
      process: process,
      logSink: logSink,
      timeout: options?.timeout,
      token: token,
    ),
  );
}