Skip to content

Commit

Permalink
feat: start to log pub get output if it runs for more than 10s (#286)
Browse files Browse the repository at this point in the history
  • Loading branch information
blaugold authored Apr 28, 2022
1 parent f48e8f1 commit fca44a4
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
20 changes: 14 additions & 6 deletions packages/melos/lib/src/commands/bootstrap.dart
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,21 @@ mixin _BootstrapMixin on _CleanMixin {
process.stdin.writeln(r'exit $?');
}

const logTimeout = Duration(seconds: 10);
final packagePrefix = '[${AnsiStyles.blue.bold(package.name)}]: ';
void Function(String) logLineTo(void Function(String)? log) =>
(line) => log?.call('$packagePrefix$line');

// We always fully consume stdout and stderr. This is required to prevent
// leaking resources and to ensure that the process exits. We
// need stdout and stderr in case of an error. Otherwise, we don't care
// about the output, don't wait for it to finish and don't handle errors.
// We just make sure the output streams are drained.
final stdout = utf8.decodeStream(process.stdout);
final stderr = utf8.decodeStream(process.stderr);
// leaking resources and to ensure that the process exits.
final stdout = process.stdout.toStringAndLogAfterTimeout(
timeout: logTimeout,
log: logLineTo(logger?.stdout),
);
final stderr = process.stderr.toStringAndLogAfterTimeout(
timeout: logTimeout,
log: logLineTo(logger?.stderr),
);

final exitCode = await process.exitCode;

Expand Down
26 changes: 26 additions & 0 deletions packages/melos/lib/src/common/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -497,3 +497,29 @@ extension StreamUtils<T> on Stream<T> {
}
}
}

extension Utf8StreamUtils on Stream<List<int>> {
/// Fully consumes this stream and returns the decoded string, while also
/// starting to call [log] after [timeout] has elapsed for the previously
/// decoded lines and all subsequent lines.
Future<String> toStringAndLogAfterTimeout({
required Duration timeout,
required void Function(String) log,
}) async {
final bufferedLines = <String>[];
final stopwatch = Stopwatch()..start();
return transform(utf8.decoder).transform(const LineSplitter()).map((line) {
if (stopwatch.elapsed >= timeout) {
if (bufferedLines.isNotEmpty) {
bufferedLines.forEach(log);
bufferedLines.clear();
}
log(line);
} else {
bufferedLines.add(line);
}

return line;
}).join('\n');
}
}

0 comments on commit fca44a4

Please sign in to comment.