@@ -170,7 +170,7 @@ abstract class PackageLoopingCommand extends PluginCommand {
170
170
/// messages. DO NOT RELY on someone noticing a warning; instead, use it for
171
171
/// things that might be useful to someone debugging an unexpected result.
172
172
void logWarning (String warningMessage) {
173
- print ( Colorize ( warningMessage).. yellow () );
173
+ _printColorized ( warningMessage, Styles . YELLOW );
174
174
if (_currentPackageEntry != null ) {
175
175
_packagesWithWarnings.add (_currentPackageEntry! );
176
176
} else {
@@ -219,6 +219,8 @@ abstract class PackageLoopingCommand extends PluginCommand {
219
219
_otherWarningCount = 0 ;
220
220
_currentPackageEntry = null ;
221
221
222
+ final DateTime runStart = DateTime .now ();
223
+
222
224
await initializeRun ();
223
225
224
226
final List <PackageEnumerationEntry > targetPackages =
@@ -227,8 +229,9 @@ abstract class PackageLoopingCommand extends PluginCommand {
227
229
final Map <PackageEnumerationEntry , PackageResult > results =
228
230
< PackageEnumerationEntry , PackageResult > {};
229
231
for (final PackageEnumerationEntry entry in targetPackages) {
232
+ final DateTime packageStart = DateTime .now ();
230
233
_currentPackageEntry = entry;
231
- _printPackageHeading (entry);
234
+ _printPackageHeading (entry, startTime : runStart );
232
235
233
236
// Command implementations should never see excluded packages; they are
234
237
// included at this level only for logging.
@@ -246,11 +249,20 @@ abstract class PackageLoopingCommand extends PluginCommand {
246
249
result = PackageResult .fail (< String > ['Unhandled exception' ]);
247
250
}
248
251
if (result.state == RunState .skipped) {
249
- final String message =
250
- '${indentation }SKIPPING: ${result .details .first }' ;
251
- captureOutput ? print (message) : print (Colorize (message)..darkGray ());
252
+ _printColorized ('${indentation }SKIPPING: ${result .details .first }' ,
253
+ Styles .DARK_GRAY );
252
254
}
253
255
results[entry] = result;
256
+
257
+ // Only log an elapsed time for long output; for short output, comparing
258
+ // the relative timestamps of successive entries should be trivial.
259
+ if (shouldLogTiming && hasLongOutput) {
260
+ final Duration elapsedTime = DateTime .now ().difference (packageStart);
261
+ _printColorized (
262
+ '\n [${entry .package .displayName } completed in '
263
+ '${elapsedTime .inMinutes }m ${elapsedTime .inSeconds % 60 }s]' ,
264
+ Styles .DARK_GRAY );
265
+ }
254
266
}
255
267
_currentPackageEntry = null ;
256
268
@@ -287,11 +299,20 @@ abstract class PackageLoopingCommand extends PluginCommand {
287
299
/// Something is always printed to make it easier to distinguish between
288
300
/// a command running for a package and producing no output, and a command
289
301
/// not having been run for a package.
290
- void _printPackageHeading (PackageEnumerationEntry entry) {
302
+ void _printPackageHeading (PackageEnumerationEntry entry,
303
+ {required DateTime startTime}) {
291
304
final String packageDisplayName = entry.package.displayName;
292
305
String heading = entry.excluded
293
306
? 'Not running for $packageDisplayName ; excluded'
294
307
: 'Running for $packageDisplayName ' ;
308
+
309
+ if (shouldLogTiming) {
310
+ final Duration relativeTime = DateTime .now ().difference (startTime);
311
+ final String timeString = _formatDurationAsRelativeTime (relativeTime);
312
+ heading =
313
+ hasLongOutput ? '$heading [@$timeString ]' : '[$timeString ] $heading ' ;
314
+ }
315
+
295
316
if (hasLongOutput) {
296
317
heading = '''
297
318
@@ -302,13 +323,7 @@ abstract class PackageLoopingCommand extends PluginCommand {
302
323
} else if (! entry.excluded) {
303
324
heading = '$heading ...' ;
304
325
}
305
- if (captureOutput) {
306
- print (heading);
307
- } else {
308
- final Colorize colorizeHeading = Colorize (heading);
309
- print (
310
- entry.excluded ? colorizeHeading.darkGray () : colorizeHeading.cyan ());
311
- }
326
+ _printColorized (heading, entry.excluded ? Styles .DARK_GRAY : Styles .CYAN );
312
327
}
313
328
314
329
/// Prints a summary of packges run, packages skipped, and warnings.
@@ -401,4 +416,21 @@ abstract class PackageLoopingCommand extends PluginCommand {
401
416
}
402
417
_printError (failureListFooter);
403
418
}
419
+
420
+ /// Prints [message] in [color] unless [captureOutput] is set, in which case
421
+ /// it is printed without color.
422
+ void _printColorized (String message, Styles color) {
423
+ if (captureOutput) {
424
+ print (message);
425
+ } else {
426
+ print (Colorize (message)..apply (color));
427
+ }
428
+ }
429
+
430
+ /// Returns a duration [d] formatted as minutes:seconds. Does not use hours,
431
+ /// since time logging is primarily intended for CI, where durations should
432
+ /// always be less than an hour.
433
+ String _formatDurationAsRelativeTime (Duration d) {
434
+ return '${d .inMinutes }:${(d .inSeconds % 60 ).toString ().padLeft (2 , '0' )}' ;
435
+ }
404
436
}
0 commit comments