Create abstraction layer for dart:io's Process commands (#7100)
With this change, they're run via instance methods on an object
obtained through the context. This will allow us to substitute
that object in tests with replay/record versions to allow us to
mock out the os-layer in tests.
diff --git a/packages/flutter_tools/lib/src/base/os.dart b/packages/flutter_tools/lib/src/base/os.dart
index f709d4d..01c46d3 100644
--- a/packages/flutter_tools/lib/src/base/os.dart
+++ b/packages/flutter_tools/lib/src/base/os.dart
@@ -10,6 +10,7 @@
import 'context.dart';
import 'process.dart';
+import 'process_manager.dart';
/// Returns [OperatingSystemUtils] active in the current app context (i.e. zone).
OperatingSystemUtils get os => context[OperatingSystemUtils];
@@ -49,14 +50,14 @@
@override
ProcessResult makeExecutable(File file) {
- return Process.runSync('chmod', <String>['a+x', file.path]);
+ return processManager.runSync('chmod', <String>['a+x', file.path]);
}
/// Return the path to the given executable, or `null` if `which` was not able
/// to locate the binary.
@override
File which(String execName) {
- ProcessResult result = Process.runSync('which', <String>[execName]);
+ ProcessResult result = processManager.runSync('which', <String>[execName]);
if (result.exitCode != 0)
return null;
String path = result.stdout.trim().split('\n').first.trim();
@@ -87,7 +88,7 @@
@override
File which(String execName) {
- ProcessResult result = Process.runSync('where', <String>[execName]);
+ ProcessResult result = processManager.runSync('where', <String>[execName]);
if (result.exitCode != 0)
return null;
return new File(result.stdout.trim().split('\n').first.trim());
diff --git a/packages/flutter_tools/lib/src/base/process.dart b/packages/flutter_tools/lib/src/base/process.dart
index 104db6c..8b20f90 100644
--- a/packages/flutter_tools/lib/src/base/process.dart
+++ b/packages/flutter_tools/lib/src/base/process.dart
@@ -6,6 +6,7 @@
import 'dart:convert';
import 'dart:io';
+import 'process_manager.dart';
import '../globals.dart';
typedef String StringConverter(String string);
@@ -44,7 +45,7 @@
_traceCommand(cmd, workingDirectory: workingDirectory);
String executable = cmd[0];
List<String> arguments = cmd.length > 1 ? cmd.sublist(1) : <String>[];
- Process process = await Process.start(
+ Process process = await processManager.start(
executable,
arguments,
workingDirectory: workingDirectory,
@@ -108,13 +109,13 @@
Future<Process> proc = runDetached(cmd);
return new Future<Null>.delayed(timeout, () async {
printTrace('Intentionally killing ${cmd[0]}');
- Process.killPid((await proc).pid);
+ processManager.killPid((await proc).pid);
});
}
Future<Process> runDetached(List<String> cmd) {
_traceCommand(cmd);
- Future<Process> proc = Process.start(
+ Future<Process> proc = processManager.start(
cmd[0], cmd.getRange(1, cmd.length).toList(),
mode: ProcessStartMode.DETACHED
);
@@ -126,7 +127,7 @@
bool allowReentrantFlutter: false
}) async {
_traceCommand(cmd, workingDirectory: workingDirectory);
- ProcessResult results = await Process.run(
+ ProcessResult results = await processManager.run(
cmd[0],
cmd.getRange(1, cmd.length).toList(),
workingDirectory: workingDirectory,
@@ -140,7 +141,7 @@
bool exitsHappy(List<String> cli) {
_traceCommand(cli);
try {
- return Process.runSync(cli.first, cli.sublist(1)).exitCode == 0;
+ return processManager.runSync(cli.first, cli.sublist(1)).exitCode == 0;
} catch (error) {
return false;
}
@@ -203,7 +204,7 @@
bool hideStdout: false,
}) {
_traceCommand(cmd, workingDirectory: workingDirectory);
- ProcessResult results = Process.runSync(
+ ProcessResult results = processManager.runSync(
cmd[0],
cmd.getRange(1, cmd.length).toList(),
workingDirectory: workingDirectory,
diff --git a/packages/flutter_tools/lib/src/base/process_manager.dart b/packages/flutter_tools/lib/src/base/process_manager.dart
new file mode 100644
index 0000000..0cfc1f5
--- /dev/null
+++ b/packages/flutter_tools/lib/src/base/process_manager.dart
@@ -0,0 +1,66 @@
+// Copyright 2016 The Chromium Authors. 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';
+
+import 'context.dart';
+
+ProcessManager get processManager => context[ProcessManager];
+
+class ProcessManager {
+ Future<Process> start(
+ String executable,
+ List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ ProcessStartMode mode: ProcessStartMode.NORMAL}) {
+ return Process.start(
+ executable,
+ arguments,
+ workingDirectory: workingDirectory,
+ environment: environment,
+ mode: mode,
+ );
+ }
+
+ Future<ProcessResult> run(
+ String executable,
+ List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ Encoding stdoutEncoding: SYSTEM_ENCODING,
+ Encoding stderrEncoding: SYSTEM_ENCODING}) {
+ return Process.run(
+ executable,
+ arguments,
+ workingDirectory: workingDirectory,
+ environment: environment,
+ stdoutEncoding: stdoutEncoding,
+ stderrEncoding: stderrEncoding,
+ );
+ }
+
+ ProcessResult runSync(
+ String executable,
+ List<String> arguments,
+ {String workingDirectory,
+ Map<String, String> environment,
+ Encoding stdoutEncoding: SYSTEM_ENCODING,
+ Encoding stderrEncoding: SYSTEM_ENCODING}) {
+ return Process.runSync(
+ executable,
+ arguments,
+ workingDirectory: workingDirectory,
+ environment: environment,
+ stdoutEncoding: stdoutEncoding,
+ stderrEncoding: stderrEncoding,
+ );
+ }
+
+ bool killPid(int pid, [ProcessSignal signal = ProcessSignal.SIGTERM]) {
+ return Process.killPid(pid, signal);
+ }
+}