blob: 72e513a6a2512aafbd90a8d8e4f10d0e15db4019 [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:convert';
import 'dart:io'
show
Process,
ProcessResult,
ProcessSignal,
ProcessStartMode,
ProcessException,
systemEncoding;
import 'package:process/process.dart';
import 'common.dart';
import 'exceptions.dart';
import 'process_manager.dart';
/// Local implementation of the `ProcessManager` interface.
///
/// This implementation delegates directly to the corresponding static methods
/// in `dart:io`.
///
/// All methods that take a `command` will run `toString()` on the command
/// elements to derive the executable and arguments that should be passed to
/// the underlying `dart:io` methods. Thus, the degenerate case of
/// `List<String>` will trivially work as expected.
class LocalProcessManager implements ProcessManager {
/// Creates a new `LocalProcessManager`.
const LocalProcessManager();
@override
Future<Process> start(
List<Object> command, {
String? workingDirectory,
Map<String, String>? environment,
bool includeParentEnvironment = true,
bool runInShell = false,
ProcessStartMode mode = ProcessStartMode.normal,
}) {
try {
return Process.start(
sanitizeExecutablePath(_getExecutable(
command,
workingDirectory,
runInShell,
)),
_getArguments(command),
workingDirectory: workingDirectory,
environment: environment,
includeParentEnvironment: includeParentEnvironment,
runInShell: runInShell,
mode: mode,
);
} on ProcessException catch (exception) {
throw ProcessPackageException.fromProcessException(exception,
workingDirectory: workingDirectory);
}
}
@override
Future<ProcessResult> run(
List<Object> command, {
String? workingDirectory,
Map<String, String>? environment,
bool includeParentEnvironment = true,
bool runInShell = false,
Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding,
}) {
try {
return Process.run(
sanitizeExecutablePath(_getExecutable(
command,
workingDirectory,
runInShell,
)),
_getArguments(command),
workingDirectory: workingDirectory,
environment: environment,
includeParentEnvironment: includeParentEnvironment,
runInShell: runInShell,
stdoutEncoding: stdoutEncoding,
stderrEncoding: stderrEncoding,
);
} on ProcessException catch (exception) {
throw ProcessPackageException.fromProcessException(exception,
workingDirectory: workingDirectory);
}
}
@override
ProcessResult runSync(
List<Object> command, {
String? workingDirectory,
Map<String, String>? environment,
bool includeParentEnvironment = true,
bool runInShell = false,
Encoding stdoutEncoding = systemEncoding,
Encoding stderrEncoding = systemEncoding,
}) {
try {
return Process.runSync(
sanitizeExecutablePath(_getExecutable(
command,
workingDirectory,
runInShell,
)),
_getArguments(command),
workingDirectory: workingDirectory,
environment: environment,
includeParentEnvironment: includeParentEnvironment,
runInShell: runInShell,
stdoutEncoding: stdoutEncoding,
stderrEncoding: stderrEncoding,
);
} on ProcessException catch (exception) {
throw ProcessPackageException.fromProcessException(exception,
workingDirectory: workingDirectory);
}
}
@override
bool canRun(covariant String executable, {String? workingDirectory}) =>
getExecutablePath(executable, workingDirectory, throwOnFailure: false) !=
null;
@override
bool killPid(int pid, [ProcessSignal signal = ProcessSignal.sigterm]) {
return Process.killPid(pid, signal);
}
}
String _getExecutable(
List<dynamic> command, String? workingDirectory, bool runInShell) {
String commandName = command.first.toString();
if (runInShell) {
return commandName;
}
return getExecutablePath(
commandName,
workingDirectory,
throwOnFailure: true,
)!;
}
List<String> _getArguments(List<Object> command) =>
// Adding a specific type to map in order to workaround dart issue
// https://github.com/dart-lang/sdk/issues/32414
command
.skip(1)
.map<String>((dynamic element) => element.toString())
.toList();