@@ -79,6 +79,7 @@ void main(List<String> args) async {
79
79
contentsGolden: options.outputContentsGolden,
80
80
ndkStack: options.ndkStack,
81
81
forceSurfaceProducerSurfaceTexture: options.forceSurfaceProducerSurfaceTexture,
82
+ prefixLogsPerRun: options.prefixLogsPerRun,
82
83
);
83
84
onSigint.cancel ();
84
85
exit (0 );
@@ -122,15 +123,22 @@ Future<void> _run({
122
123
required String ? contentsGolden,
123
124
required String ndkStack,
124
125
required bool forceSurfaceProducerSurfaceTexture,
126
+ required bool prefixLogsPerRun,
125
127
}) async {
126
128
const ProcessManager pm = LocalProcessManager ();
127
129
final String scenarioAppPath = join (outDir.path, 'scenario_app' );
130
+
131
+ // Due to the CI environment, the logs directory persists between runs and
132
+ // even different builds. Because we're checking the output directory after
133
+ // each run, we need a clean logs directory to avoid false positives.
134
+ //
135
+ // Only after the runner is done, we can move the logs to the final location.
136
+ //
137
+ // See [_copyFiles] below and https://github.com/flutter/flutter/issues/144402.
138
+ final Directory finalLogsDir = logsDir..createSync (recursive: true );
139
+ logsDir = Directory .systemTemp.createTempSync ('scenario_app_test_logs.' );
128
140
final String logcatPath = join (logsDir.path, 'logcat.txt' );
129
141
130
- // TODO(matanlurey): Use screenshots/ sub-directory (https://github.com/flutter/flutter/issues/143604).
131
- if (! logsDir.existsSync ()) {
132
- logsDir.createSync (recursive: true );
133
- }
134
142
final String screenshotPath = logsDir.path;
135
143
final String apkOutPath = join (scenarioAppPath, 'app' , 'outputs' , 'apk' );
136
144
final File testApk = File (join (apkOutPath, 'androidTest' , 'debug' , 'app-debug-androidTest.apk' ));
@@ -388,6 +396,32 @@ Future<void> _run({
388
396
await logcat.flush ();
389
397
await logcat.close ();
390
398
log ('wrote logcat to $logcatPath ' );
399
+
400
+ // Copy the logs to the final location.
401
+ // Optionally prefix the logs with a run number and backend name.
402
+ // See https://github.com/flutter/flutter/issues/144402.
403
+ final StringBuffer prefix = StringBuffer ();
404
+ if (prefixLogsPerRun) {
405
+ final int rerunNumber = _getAndIncrementRerunNumber (finalLogsDir.path);
406
+ prefix.write ('run_$rerunNumber .' );
407
+ if (enableImpeller) {
408
+ prefix.write ('impeller' );
409
+ } else {
410
+ prefix.write ('skia' );
411
+ }
412
+ if (enableImpeller) {
413
+ prefix.write ('_${impellerBackend !.name }' );
414
+ }
415
+ if (forceSurfaceProducerSurfaceTexture) {
416
+ prefix.write ('_force-st' );
417
+ }
418
+ prefix.write ('.' );
419
+ }
420
+ _copyFiles (
421
+ source: logsDir,
422
+ destination: finalLogsDir,
423
+ prefix: prefix.toString (),
424
+ );
391
425
});
392
426
393
427
if (enableImpeller) {
@@ -448,7 +482,9 @@ Future<void> _run({
448
482
await Future .wait (pendingComparisons);
449
483
});
450
484
451
- if (contentsGolden != null ) {
485
+ final bool allTestsRun = smokeTestFullPath == null ;
486
+ final bool checkGoldens = contentsGolden != null ;
487
+ if (allTestsRun && checkGoldens) {
452
488
// Check the output here.
453
489
await step ('Check output files...' , () async {
454
490
// TODO(matanlurey): Resolve this in a better way. On CI this file always exists.
@@ -476,3 +512,32 @@ void _withTemporaryCwd(String path, void Function() callback) {
476
512
Directory .current = originalCwd;
477
513
}
478
514
}
515
+
516
+ /// Reads the file named `reruns.txt` in the logs directory and returns the number of reruns.
517
+ ///
518
+ /// If the file does not exist, it is created with the number 1 and that number is returned.
519
+ int _getAndIncrementRerunNumber (String logsDir) {
520
+ final File rerunFile = File (join (logsDir, 'reruns.txt' ));
521
+ if (! rerunFile.existsSync ()) {
522
+ rerunFile.writeAsStringSync ('1' );
523
+ return 1 ;
524
+ }
525
+ final int rerunNumber = int .parse (rerunFile.readAsStringSync ()) + 1 ;
526
+ rerunFile.writeAsStringSync (rerunNumber.toString ());
527
+ return rerunNumber;
528
+ }
529
+
530
+ /// Copies the contents of [source] to [destination] , optionally adding a [prefix] to the destination path.
531
+ ///
532
+ /// This function is used to copy the screenshots from the device to the logs directory.
533
+ void _copyFiles ({
534
+ required Directory source,
535
+ required Directory destination,
536
+ String prefix = '' ,
537
+ }) {
538
+ for (final FileSystemEntity entity in source.listSync ()) {
539
+ if (entity is File ) {
540
+ entity.copySync (join (destination.path, prefix + basename (entity.path)));
541
+ }
542
+ }
543
+ }
0 commit comments