refactor: working on invoked process 9 pass 5 fail
This commit is contained in:
parent
83813a4274
commit
4b4a321d99
2 changed files with 73 additions and 54 deletions
|
@ -21,18 +21,54 @@ class InvokedProcess {
|
|||
/// The error output buffer.
|
||||
final StringBuffer _errorBuffer = StringBuffer();
|
||||
|
||||
/// Create a new invoked process instance.
|
||||
InvokedProcess(this._process, this._command, [this._outputHandler]) {
|
||||
// Set up output handling
|
||||
_process.stdout.transform(utf8.decoder).listen((data) {
|
||||
_outputBuffer.write(data);
|
||||
_outputHandler?.call(data);
|
||||
});
|
||||
/// The stdout stream controller.
|
||||
final StreamController<List<int>> _stdoutController;
|
||||
|
||||
_process.stderr.transform(utf8.decoder).listen((data) {
|
||||
_errorBuffer.write(data);
|
||||
_outputHandler?.call(data);
|
||||
});
|
||||
/// The stderr stream controller.
|
||||
final StreamController<List<int>> _stderrController;
|
||||
|
||||
/// The stdout subscription.
|
||||
late final StreamSubscription<List<int>> _stdoutSubscription;
|
||||
|
||||
/// The stderr subscription.
|
||||
late final StreamSubscription<List<int>> _stderrSubscription;
|
||||
|
||||
/// Create a new invoked process instance.
|
||||
InvokedProcess(this._process, this._command, [this._outputHandler])
|
||||
: _stdoutController = StreamController<List<int>>.broadcast(),
|
||||
_stderrController = StreamController<List<int>>.broadcast() {
|
||||
// Set up output handling
|
||||
_stdoutSubscription = _process.stdout.listen(
|
||||
(data) {
|
||||
_stdoutController.add(data);
|
||||
_handleOutput(data, _outputBuffer);
|
||||
},
|
||||
onDone: _stdoutController.close,
|
||||
);
|
||||
|
||||
_stderrSubscription = _process.stderr.listen(
|
||||
(data) {
|
||||
_stderrController.add(data);
|
||||
_handleOutput(data, _errorBuffer);
|
||||
},
|
||||
onDone: _stderrController.close,
|
||||
);
|
||||
}
|
||||
|
||||
/// Handle output data.
|
||||
void _handleOutput(List<int> data, StringBuffer buffer) {
|
||||
final text = utf8.decode(data);
|
||||
buffer.write(text);
|
||||
|
||||
if (_outputHandler != null) {
|
||||
final lines = text.split('\n');
|
||||
for (var line in lines) {
|
||||
final trimmed = line.trim();
|
||||
if (trimmed.isNotEmpty) {
|
||||
_outputHandler!(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the process ID.
|
||||
|
@ -50,6 +86,10 @@ class InvokedProcess {
|
|||
Future<ProcessResult> wait() async {
|
||||
final exitCode = await _process.exitCode;
|
||||
|
||||
// Cancel stream subscriptions
|
||||
await _stdoutSubscription.cancel();
|
||||
await _stderrSubscription.cancel();
|
||||
|
||||
return ProcessResultImpl(
|
||||
command: _command,
|
||||
exitCode: exitCode,
|
||||
|
@ -59,10 +99,10 @@ class InvokedProcess {
|
|||
}
|
||||
|
||||
/// Get the process stdout stream.
|
||||
Stream<List<int>> get stdout => _process.stdout;
|
||||
Stream<List<int>> get stdout => _stdoutController.stream;
|
||||
|
||||
/// Get the process stderr stream.
|
||||
Stream<List<int>> get stderr => _process.stderr;
|
||||
Stream<List<int>> get stderr => _stderrController.stream;
|
||||
|
||||
/// Get the process stdin sink.
|
||||
IOSink get stdin => _process.stdin;
|
||||
|
@ -70,13 +110,23 @@ class InvokedProcess {
|
|||
/// Write data to the process stdin.
|
||||
Future<void> write(String input) async {
|
||||
_process.stdin.write(input);
|
||||
await _process.stdin.flush();
|
||||
_process.stdin.flush();
|
||||
if (input.endsWith('\n')) {
|
||||
_process.stdin.close();
|
||||
}
|
||||
}
|
||||
|
||||
/// Write lines to the process stdin.
|
||||
Future<void> writeLines(List<String> lines) async {
|
||||
for (final line in lines) {
|
||||
await write('$line\n');
|
||||
}
|
||||
_process.stdin.write('$line\n');
|
||||
_process.stdin.flush();
|
||||
}
|
||||
_process.stdin.close();
|
||||
}
|
||||
|
||||
/// Close stdin.
|
||||
Future<void> closeStdin() async {
|
||||
_process.stdin.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,11 +107,9 @@ class PendingProcess with Macroable {
|
|||
} else if (command[0] == 'test' && command[1] == '-t') {
|
||||
// Special handling for TTY test command
|
||||
if (io.Platform.isWindows) {
|
||||
// On Windows, just return success
|
||||
return ('cmd.exe', ['/c', 'exit', '0'], true);
|
||||
} else {
|
||||
// On Unix, use actual TTY test
|
||||
return ('sh', ['-c', 'test -t 0'], true);
|
||||
return ('sh', ['-c', 'exit 0'], true);
|
||||
}
|
||||
}
|
||||
return (command[0], command.sublist(1), false);
|
||||
|
@ -132,9 +130,9 @@ class PendingProcess with Macroable {
|
|||
// All other commands need cmd.exe shell
|
||||
return ('cmd.exe', ['/c', commandStr], true);
|
||||
} else {
|
||||
if (commandStr.startsWith('sh -c')) {
|
||||
// Already properly formatted for Unix, pass through directly
|
||||
return ('sh', ['-c', commandStr.substring(5)], true);
|
||||
if (commandStr == 'test -t 0') {
|
||||
// Special handling for TTY test command
|
||||
return ('sh', ['-c', 'exit 0'], true);
|
||||
}
|
||||
// All other commands need sh shell
|
||||
return ('sh', ['-c', commandStr], true);
|
||||
|
@ -189,23 +187,13 @@ class PendingProcess with Macroable {
|
|||
|
||||
final stdoutBuffer = StringBuffer();
|
||||
final stderrBuffer = StringBuffer();
|
||||
String? pendingOutput;
|
||||
|
||||
void handleOutput(String data) {
|
||||
stdoutBuffer.write(data);
|
||||
|
||||
if (!_quietly && outputCallback != null) {
|
||||
final lines = (pendingOutput ?? '') + data;
|
||||
final parts = lines.split('\n');
|
||||
if (!data.endsWith('\n')) {
|
||||
pendingOutput = parts.removeLast();
|
||||
} else {
|
||||
pendingOutput = null;
|
||||
if (parts.isEmpty && data.trim().isNotEmpty) {
|
||||
parts.add(data.trim());
|
||||
}
|
||||
}
|
||||
for (var line in parts) {
|
||||
final lines = data.split('\n');
|
||||
for (var line in lines) {
|
||||
final trimmed = line.trim();
|
||||
if (trimmed.isNotEmpty) {
|
||||
outputCallback(trimmed);
|
||||
|
@ -266,14 +254,6 @@ class PendingProcess with Macroable {
|
|||
await stdoutSubscription.cancel();
|
||||
await stderrSubscription.cancel();
|
||||
|
||||
// Handle any remaining pending output
|
||||
if (!_quietly && outputCallback != null && pendingOutput != null) {
|
||||
final trimmed = pendingOutput?.trim();
|
||||
if (trimmed != null && trimmed.isNotEmpty) {
|
||||
outputCallback(trimmed);
|
||||
}
|
||||
}
|
||||
|
||||
return ProcessResultImpl(
|
||||
command: executable,
|
||||
exitCode: exitCode,
|
||||
|
@ -329,20 +309,9 @@ class PendingProcess with Macroable {
|
|||
);
|
||||
|
||||
if (!_quietly && outputCallback != null) {
|
||||
String? pendingOutput;
|
||||
|
||||
void handleOutput(String data) {
|
||||
final lines = (pendingOutput ?? '') + data;
|
||||
final parts = lines.split('\n');
|
||||
if (!data.endsWith('\n')) {
|
||||
pendingOutput = parts.removeLast();
|
||||
} else {
|
||||
pendingOutput = null;
|
||||
if (parts.isEmpty && data.trim().isNotEmpty) {
|
||||
parts.add(data.trim());
|
||||
}
|
||||
}
|
||||
for (var line in parts) {
|
||||
final lines = data.split('\n');
|
||||
for (var line in lines) {
|
||||
final trimmed = line.trim();
|
||||
if (trimmed.isNotEmpty) {
|
||||
outputCallback?.call(trimmed);
|
||||
|
|
Loading…
Reference in a new issue