blob: 67fd0794a67a3f044c4dc211b80dc9545cac6f7f [file] [log] [blame]
// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'dart:io'
show
Process,
ProcessResult,
ProcessSignal,
ProcessStartMode,
systemEncoding;
/// Manages the creation of abstract processes.
///
/// Using instances of this class provides level of indirection from the static
/// methods in the [Process] class, which in turn allows the underlying
/// implementation to be mocked out or decorated for testing and debugging
/// purposes.
abstract class ProcessManager {
/// Starts a process by running the specified [command].
///
/// The first element in [command] will be treated as the executable to run,
/// with subsequent elements being passed as arguments to the executable. It
/// is left to implementations to decide what element types they support in
/// the [command] list.
///
/// Returns a `Future<Process>` that completes with a Process instance when
/// the process has been successfully started. That [Process] object can be
/// used to interact with the process. If the process cannot be started, the
/// returned [Future] completes with an exception.
///
/// Use [workingDirectory] to set the working directory for the process. Note
/// that the change of directory occurs before executing the process on some
/// platforms, which may have impact when using relative paths for the
/// executable and the arguments.
///
/// Use [environment] to set the environment variables for the process. If not
/// set, the environment of the parent process is inherited. Currently, only
/// US-ASCII environment variables are supported and errors are likely to occur
/// if an environment variable with code-points outside the US-ASCII range is
/// passed in.
///
/// If [includeParentEnvironment] is `true`, the process's environment will
/// include the parent process's environment, with [environment] taking
/// precedence. Default is `true`.
///
/// If [runInShell] is `true`, the process will be spawned through a system
/// shell. On Linux and OS X, `/bin/sh` is used, while
/// `%WINDIR%\system32\cmd.exe` is used on Windows.
///
/// Users must read all data coming on the `stdout` and `stderr`
/// streams of processes started with [start]. If the user
/// does not read all data on the streams the underlying system
/// resources will not be released since there is still pending data.
///
/// The following code uses `start` to grep for `main` in the
/// file `test.dart` on Linux.
///
/// ProcessManager mgr = new LocalProcessManager();
/// mgr.start('grep', ['-i', 'main', 'test.dart']).then((process) {
/// stdout.addStream(process.stdout);
/// stderr.addStream(process.stderr);
/// });
///
/// If [mode] is [ProcessStartMode.normal] (the default) a child
/// process will be started with `stdin`, `stdout` and `stderr`
/// connected.
///
/// If `mode` is [ProcessStartMode.detached] a detached process will
/// be created. A detached process has no connection to its parent,
/// and can keep running on its own when the parent dies. The only
/// information available from a detached process is its `pid`. There
/// is no connection to its `stdin`, `stdout` or `stderr`, nor will
/// the process' exit code become available when it terminates.
///
/// If `mode` is [ProcessStartMode.detachedWithStdio] a detached
/// process will be created where the `stdin`, `stdout` and `stderr`
/// are connected. The creator can communicate with the child through
/// these. The detached process will keep running even if these
/// communication channels are closed. The process' exit code will
/// not become available when it terminated.
///
/// The default value for `mode` is `ProcessStartMode.NORMAL`.
Future<Process> start(
List<dynamic> command, {
String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
ProcessStartMode mode = ProcessStartMode.normal,
});
/// Starts a process and runs it non-interactively to completion.
///
/// The first element in [command] will be treated as the executable to run,
/// with subsequent elements being passed as arguments to the executable. It
/// is left to implementations to decide what element types they support in
/// the [command] list.
///
/// Use [workingDirectory] to set the working directory for the process. Note
/// that the change of directory occurs before executing the process on some
/// platforms, which may have impact when using relative paths for the
/// executable and the arguments.
///
/// Use [environment] to set the environment variables for the process. If not
/// set the environment of the parent process is inherited. Currently, only
/// US-ASCII environment variables are supported and errors are likely to occur
/// if an environment variable with code-points outside the US-ASCII range is
/// passed in.
///
/// If [includeParentEnvironment] is `true`, the process's environment will
/// include the parent process's environment, with [environment] taking
/// precedence. Default is `true`.
///
/// If [runInShell] is true, the process will be spawned through a system
/// shell. On Linux and OS X, `/bin/sh` is used, while
/// `%WINDIR%\system32\cmd.exe` is used on Windows.
///
/// The encoding used for decoding `stdout` and `stderr` into text is
/// controlled through [stdoutEncoding] and [stderrEncoding]. The
/// default encoding is [systemEncoding]. If `null` is used no
/// decoding will happen and the [ProcessResult] will hold binary
/// data.
///
/// Returns a `Future<ProcessResult>` that completes with the
/// result of running the process, i.e., exit code, standard out and
/// standard in.
///
/// The following code uses `run` to grep for `main` in the
/// file `test.dart` on Linux.
///
/// ProcessManager mgr = new LocalProcessManager();
/// mgr.run('grep', ['-i', 'main', 'test.dart']).then((result) {
/// stdout.write(result.stdout);
/// stderr.write(result.stderr);
/// });
Future<ProcessResult> run(
List<dynamic> command, {
String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding,
});
/// Starts a process and runs it to completion. This is a synchronous
/// call and will block until the child process terminates.
///
/// The arguments are the same as for [run]`.
///
/// Returns a `ProcessResult` with the result of running the process,
/// i.e., exit code, standard out and standard in.
ProcessResult runSync(
List<dynamic> command, {
String workingDirectory,
Map<String, String> environment,
bool includeParentEnvironment = true,
bool runInShell = false,
Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding,
});
/// Returns `true` if the [executable] exists and if it can be executed.
bool canRun(dynamic executable, {String workingDirectory});
/// Kills the process with id [pid].
///
/// Where possible, sends the [signal] to the process with id
/// `pid`. This includes Linux and OS X. The default signal is
/// [ProcessSignal.sigterm] which will normally terminate the
/// process.
///
/// On platforms without signal support, including Windows, the call
/// just terminates the process with id `pid` in a platform specific
/// way, and the `signal` parameter is ignored.
///
/// Returns `true` if the signal is successfully delivered to the
/// process. Otherwise the signal could not be sent, usually meaning
/// that the process is already dead.
bool killPid(int pid, [ProcessSignal signal = ProcessSignal.sigterm]);
}