Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/src/exceptions/stacked_process_failed_exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
class StackedProcessFailedException implements Exception {
final dynamic msg;
StackedProcessFailedException(this.msg);

@override
toString() => msg.toString();
}
50 changes: 46 additions & 4 deletions lib/src/services/process_service.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:async/async.dart';
import 'package:stacked_cli/src/constants/command_constants.dart';
import 'package:stacked_cli/src/exceptions/stacked_process_failed_exception.dart';
import 'package:stacked_cli/src/locator.dart';
import 'package:stacked_cli/src/services/colorized_log_service.dart';
import 'package:stacked_cli/src/services/config_service.dart';
Expand Down Expand Up @@ -135,6 +138,7 @@ class ProcessService {
}

/// It runs a process and logs the output to the console when [verbose] is true.
/// Will throw if the process errors out and won't run any subsequent processes.
///
/// Args:
/// programName (String): The name of the program to run.
Expand Down Expand Up @@ -166,17 +170,43 @@ class ProcessService {

final lines = <String>[];
final lineSplitter = LineSplitter();
await process.stdout.transform(utf8.decoder).forEach((output) {
if (verbose) _cLog.flutterOutput(message: output);

final Stream<_IdStreamResponse<String>> infoStream =
process.stdout.transform(utf8.decoder).transform(
StreamTransformer.fromHandlers(
handleData: (data, sink) => sink.add(
_IdStreamResponse('info', data),
),
),
);

final Stream<_IdStreamResponse<String>> errorStream =
process.stderr.transform(utf8.decoder).transform(
StreamTransformer.fromHandlers(
handleData: (data, sink) => sink.add(
_IdStreamResponse('error', data),
),
),
);

final Stream<_IdStreamResponse<String>> groupedStream =
StreamGroup.merge([infoStream, errorStream]);

await for (final value in groupedStream) {
if (value.id == 'error') {
throw StackedProcessFailedException(value.value);
} else if (value.id == 'info' && verbose) {
_cLog.flutterOutput(message: value.value);
}

if (handleOutput != null) {
lines.addAll(lineSplitter
.convert(output)
.convert(value.value)
.map((l) => l.trim())
.where((l) => l.isNotEmpty)
.toList());
}
});
}

await handleOutput?.call(lines);

Expand All @@ -192,6 +222,8 @@ class ProcessService {
message: message,
stackTrace: s.toString(),
);
} on StackedProcessFailedException catch (e, _) {
rethrow;
} catch (e, s) {
final message =
'Command failed. Command executed: $programName ${arguments.join(' ')}\nException: ${e.toString()}';
Expand Down Expand Up @@ -221,3 +253,13 @@ class ProcessService {
);
}
}

/// A simple wrapper class for values emitted by stderr- and stdout streams
/// to differentiate between them when merged.
/// [id] should be either 'error' or 'info'.
class _IdStreamResponse<T> {
final String id;
final T value;

_IdStreamResponse(this.id, this.value);
}
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies:
pub_updater: ^0.4.0
http: ^1.1.2
hive: ^2.2.3
async: ^2.13.0

dev_dependencies:
lints: ^3.0.0
Expand Down