@@ -41,6 +41,7 @@ class QubitFlatfileImport
4141 public $ limitToId = 0 ; // id of repository or TLD to limit our update matching under
4242 public $ status = []; // place to store data related to overall import
4343 public $ rowStatusVars = []; // place to store data related to current row
44+ public $ progressLineActive = false ; // track if a progress line is currently shown on STDERR
4445
4546 public $ columnNames = []; // column names from first row of imported CSV
4647 public $ ignoreColumns = []; // columns in CSV to ignore
@@ -281,6 +282,14 @@ public function logError($message, $includeCurrentRowNumber = true)
281282 {
282283 $ message = ($ includeCurrentRowNumber ) ? sprintf ("Row %d: %s \n" , $ this ->getStatus ('rows ' ) + 1 , $ message ) : $ message ;
283284
285+ // If a carriage-return progress line is active on STDERR, break it so
286+ // subsequent STDOUT messages start on a new line.
287+ if ($ this ->displayProgress && $ this ->progressLineActive ) {
288+ fwrite (STDERR , "\n" );
289+ fflush (STDERR );
290+ $ this ->progressLineActive = false ;
291+ }
292+
284293 if ($ this ->errorLog ) {
285294 file_put_contents ($ this ->errorLog , $ message , FILE_APPEND );
286295 }
@@ -413,7 +422,7 @@ public function csv($fh, $skipRows = 0)
413422 ++$ this ->status ['rows ' ];
414423
415424 if ($ this ->displayProgress ) {
416- echo $ this ->renderProgressDescription ();
425+ $ this ->renderProgressDescription ();
417426 }
418427 } else {
419428 ++$ this ->status ['rows ' ];
@@ -424,6 +433,26 @@ public function csv($fh, $skipRows = 0)
424433 $ this ->stopTimer ();
425434 }
426435
436+ // If a carriage-return progress line is active on STDERR, break it before summaries
437+ if ($ this ->displayProgress && $ this ->progressLineActive ) {
438+ fwrite (STDERR , "\n" );
439+ fflush (STDERR );
440+ $ this ->progressLineActive = false ;
441+ }
442+
443+ // Final summary to STDOUT for logs
444+ $ rowsProcessed = $ this ->getStatus ('rows ' ) - $ this ->getStatus ('skippedRows ' );
445+ $ totalDuration = $ this ->getTimeElapsed ();
446+ // Ensure total duration is never zero (avoid div by zero in rate calc below)
447+ $ finalRate = $ rowsProcessed / max ($ totalDuration , 1e-9 );
448+ $ msg = sprintf (
449+ "Processed %d rows total in %.2fs (%.1f/s) \n" ,
450+ $ rowsProcessed ,
451+ $ totalDuration ,
452+ $ finalRate
453+ );
454+ echo $ this ->logError ($ msg , false );
455+
427456 if ($ this ->status ['duplicates ' ]) {
428457 $ msg = sprintf ('Duplicates found: %d ' , $ this ->status ['duplicates ' ]);
429458 echo $ this ->logError ($ msg , false );
@@ -547,30 +576,31 @@ public function isUpdating()
547576 */
548577 public function renderProgressDescription ()
549578 {
550- $ output = '. ' ;
579+ // Periodic single-line summaries to STDERR.
580+ static $ startTime = null ;
581+ static $ lastLogTime = null ;
582+ static $ processedCount = 0 ;
551583
552- // return empty string if no intermittant progress display
553- if (
554- !isset ($ this ->rowsUntilProgressDisplay )
555- || !$ this ->rowsUntilProgressDisplay
556- ) {
557- return $ output ;
584+ if (null === $ startTime ) {
585+ $ startTime = microtime (true );
586+ $ lastLogTime = $ startTime ;
558587 }
559- // row count isn't incremented until after this is displayed, so add one to reflect reality
560- $ rowsProcessed = $ this ->getStatus ('rows ' ) - $ this ->getStatus ('skippedRows ' );
561- $ memoryUsageMB = round (memory_get_usage () / (1024 * 1024 ), 2 );
562588
563- // if this show should be displayed, display it
564- if (!($ rowsProcessed % $ this ->rowsUntilProgressDisplay )) {
565- $ elapsed = $ this ->getTimeElapsed ();
566- $ elapsedMinutes = round ($ elapsed / 60 , 2 );
567- $ averageTime = round ($ elapsed / $ rowsProcessed , 2 );
589+ ++$ processedCount ;
568590
569- $ output .= "\n" .$ rowsProcessed .' rows processed in ' .$ elapsedMinutes
570- .' minutes ( ' .$ averageTime .' second/row average, ' .$ memoryUsageMB ." MB used). \n" ;
591+ $ now = microtime (true );
592+ if ($ now - $ lastLogTime >= 5 ) {
593+ // Ensure elapsed is never zero (avoid div by zero in rate calc below)
594+ $ elapsed = max ($ now - $ startTime , 1e-9 );
595+ $ rate = $ processedCount / $ elapsed ;
596+ $ memoryUsageMB = round (memory_get_usage () / (1024 * 1024 ), 2 );
597+ fwrite (STDERR , sprintf ("\rProcessed %d rows (%.1f/s, %.2f MB) " , $ processedCount , $ rate , $ memoryUsageMB ));
598+ fflush (STDERR );
599+ $ lastLogTime = $ now ;
600+ $ this ->progressLineActive = true ;
571601 }
572602
573- return $ output ;
603+ return '' ;
574604 }
575605
576606 /*
@@ -1498,7 +1528,8 @@ protected function startTimer()
14981528 */
14991529 protected function stopTimer ()
15001530 {
1501- $ this ->timer ->stop ();
1531+ // Record elapsed time into the timer's total so elapsed() reports correctly.
1532+ $ this ->timer ->add (false );
15021533 }
15031534
15041535 /**
0 commit comments