@@ -302,7 +302,7 @@ class DownloadTask {
302302 // Uses official magerun2 table groups: https://github.com/netz98/n98-magerun2
303303 const customStripParts : string [ ] = [ ] ;
304304 const keepOptions = config . settings . stripOptions || [ ] ;
305-
305+
306306 // Always strip these for development (safe to remove)
307307 customStripParts . push (
308308 '@log' , // Log tables
@@ -312,41 +312,41 @@ class DownloadTask {
312312 '@replica' , // Replica tables
313313 '@newrelic_reporting' // New Relic tables
314314 ) ;
315-
315+
316316 // Strip based on what user wants to KEEP (unchecked = strip)
317317 if ( ! keepOptions . includes ( 'customers' ) ) {
318318 customStripParts . push ( '@customers' ) ;
319319 }
320-
320+
321321 if ( ! keepOptions . includes ( 'admin' ) ) {
322322 customStripParts . push ( '@admin' , '@oauth' , '@2fa' ) ;
323323 }
324-
324+
325325 if ( ! keepOptions . includes ( 'sales' ) ) {
326326 customStripParts . push ( '@sales' ) ;
327327 }
328-
328+
329329 if ( ! keepOptions . includes ( 'quotes' ) ) {
330330 customStripParts . push ( '@quotes' ) ;
331331 }
332-
332+
333333 if ( ! keepOptions . includes ( 'search' ) ) {
334334 customStripParts . push ( '@search' , '@idx' ) ;
335335 }
336-
336+
337337 if ( ! keepOptions . includes ( 'dotmailer' ) ) {
338338 customStripParts . push ( '@dotmailer' , '@mailchimp' ) ;
339339 }
340-
340+
341341 // Note: We don't strip config even if unchecked, as it would break the database
342342 // Configuration data (core_config_data) is not in any strip group - it's always kept
343343 if ( ! keepOptions . includes ( 'config' ) ) {
344344 logger . warn ( 'Configuration settings are always kept as they are required for Magento to function' ) ;
345345 }
346-
346+
347347 const customStripString = customStripParts . join ( ' ' ) ;
348348 stripOptions = customStripString ? `--strip="${ customStripString } "` : '' ;
349-
349+
350350 logger . info ( 'Using custom strip configuration' , {
351351 keepOptions,
352352 stripGroups : customStripParts ,
@@ -357,26 +357,30 @@ class DownloadTask {
357357 const keepCustomerOptions = staticSettings . settings ?. databaseStripKeepCustomerData || '' ;
358358 stripOptions = keepCustomerOptions ? `--strip="${ keepCustomerOptions } "` : '' ;
359359 } else if ( config . settings . strip === 'full and human readable' ) {
360- const staticSettings = this . services . getConfig ( ) . getStaticSettings ( ) ;
361- const fullStripOptions = staticSettings . settings ?. databaseStripDevelopment || '' ;
362- stripOptions = fullStripOptions ? `--strip="${ fullStripOptions } "` : '' ;
360+ // FULL dump with human-readable format - NO stripping
361+ stripOptions = '' ;
363362 humanReadable = '--human-readable' ;
363+ logger . info ( 'Using full database dump with human-readable format (no stripping)' ) ;
364364 } else if ( config . settings . strip === 'full' ) {
365- const staticSettings = this . services . getConfig ( ) . getStaticSettings ( ) ;
366- const fullStripOptions = staticSettings . settings ?. databaseStripDevelopment || '' ;
367- stripOptions = fullStripOptions ? `--strip=" ${ fullStripOptions } "` : '' ;
365+ // FULL dump - NO stripping
366+ stripOptions = '' ;
367+ logger . info ( 'Using full database dump (no stripping)' ) ;
368368 } else {
369+ // Default: apply development strip options
369370 const staticSettings = this . services . getConfig ( ) . getStaticSettings ( ) ;
370371 const developmentStripOptions = staticSettings . settings ?. databaseStripDevelopment || '' ;
371372 stripOptions = developmentStripOptions ? `--strip="${ developmentStripOptions } "` : '' ;
372373 }
373374
375+ // Escape filename for shell usage
376+ const escapedFileName = shellEscape ( databaseFileName ) ;
377+
374378 // Build compression command based on what's available
375379 if ( compression . type === 'gzip' ) {
376- dumpCommand = `db:dump --stdout -n --no-tablespaces ${ humanReadable } ${ stripOptions } | gzip ${ compression . level } > ${ databaseFileName } ` ;
380+ dumpCommand = `db:dump --stdout -n --no-tablespaces ${ humanReadable } ${ stripOptions } | gzip ${ compression . level } > ${ escapedFileName } ` ;
377381 } else {
378382 // No compression - just dump to file
379- dumpCommand = `db:dump --stdout -n --no-tablespaces ${ humanReadable } ${ stripOptions } > ${ databaseFileName } ` ;
383+ dumpCommand = `db:dump --stdout -n --no-tablespaces ${ humanReadable } ${ stripOptions } > ${ escapedFileName } ` ;
380384 }
381385
382386 logger . info ( 'Using compression for database dump' , {
@@ -387,27 +391,80 @@ class DownloadTask {
387391 } ) ;
388392
389393 const fullCommand = sshMagentoRootFolderMagerunCommand (
390- `${ dumpCommand } ; mv ${ databaseFileName } ~` ,
394+ `${ dumpCommand } ; mv ${ escapedFileName } ~` ,
391395 config
392396 ) ;
393397
394- task . output = 'Dumping database (this may take a minute) ...' ;
398+ task . output = 'Starting database dump ...' ;
395399 logger . info ( 'Starting database dump' , {
396400 database : config . serverVariables . databaseName ,
397401 stripType
398402 } ) ;
399403
400- await ssh . execCommand ( fullCommand ) . then ( function ( result : any ) {
404+ // Start the dump command (non-blocking)
405+ const dumpPromise = ssh . execCommand ( fullCommand ) ;
406+
407+ // Monitor file size in real-time
408+ const startTime = Date . now ( ) ;
409+ let lastSize = 0 ;
410+ let lastSizeTime = Date . now ( ) ;
411+
412+ const sizeCheckInterval = setInterval ( async ( ) => {
413+ try {
414+ // Check file size on server (in Magento root first, then home)
415+ const sizeCommand = sshMagentoRootFolderMagerunCommand (
416+ `stat -f%z ${ escapedFileName } 2>/dev/null || stat -c%s ${ escapedFileName } 2>/dev/null || echo "0"` ,
417+ config
418+ ) ;
419+
420+ const sizeResult = await ssh . execCommand ( sizeCommand ) ;
421+ const currentSize = parseInt ( sizeResult . stdout . trim ( ) || '0' ) ;
422+
423+ if ( currentSize > 0 ) {
424+ const elapsed = Math . floor ( ( Date . now ( ) - startTime ) / 1000 ) ;
425+ const elapsedMinutes = Math . floor ( elapsed / 60 ) ;
426+ const elapsedSeconds = elapsed % 60 ;
427+ const timeStr = elapsedMinutes > 0
428+ ? `${ elapsedMinutes } m ${ elapsedSeconds } s`
429+ : `${ elapsedSeconds } s` ;
430+
431+ // Calculate speed since last check
432+ const timeDiff = ( Date . now ( ) - lastSizeTime ) / 1000 ;
433+ const sizeDiff = currentSize - lastSize ;
434+ const speed = timeDiff > 0 ? sizeDiff / timeDiff : 0 ;
435+
436+ lastSize = currentSize ;
437+ lastSizeTime = Date . now ( ) ;
438+
439+ const sizeStr = ProgressDisplay . formatBytes ( currentSize ) ;
440+ const speedStr = speed > 0 ? ` ${ chalk . cyan ( '~' + ProgressDisplay . formatSpeed ( speed ) ) } ` : '' ;
441+
442+ task . output = `Dumping database... ${ chalk . bold . cyan ( sizeStr ) } ${ speedStr } ${ chalk . gray ( `(${ timeStr } elapsed)` ) } ` ;
443+ }
444+ } catch ( err ) {
445+ // Ignore errors during size check (file might not exist yet)
446+ }
447+ } , 2000 ) ; // Check every 2 seconds
448+
449+ await dumpPromise . then ( function ( result : any ) {
450+ clearInterval ( sizeCheckInterval ) ;
451+
401452 if ( result . code && result . code !== 0 ) {
402453 throw new Error (
403454 `Database dump failed\n[TIP] Check database permissions and disk space\nError: ${ result . stderr } `
404455 ) ;
405456 }
406- task . output = '✓ Database dump completed' ;
457+
458+ const elapsed = Math . floor ( ( Date . now ( ) - startTime ) / 1000 ) ;
459+ const finalSizeStr = lastSize > 0 ? ` (${ ProgressDisplay . formatBytes ( lastSize ) } )` : '' ;
460+ task . output = `✓ Database dump completed${ finalSizeStr } in ${ elapsed } s` ;
461+ } ) . catch ( ( err : Error ) => {
462+ clearInterval ( sizeCheckInterval ) ;
463+ throw err ;
407464 } ) ;
408465
409466 const duration = PerformanceMonitor . end ( 'database-dump' ) ;
410- logger . info ( 'Database dump complete' , { duration } ) ;
467+ logger . info ( 'Database dump complete' , { duration, finalSize : lastSize } ) ;
411468 task . title = `Dumped database` ;
412469 }
413470 } ) ;
0 commit comments