diff --git a/app/Support/DatabaseImport/DatabaseImportCommandBuilder.php b/app/Support/DatabaseImport/DatabaseImportCommandBuilder.php index 2b75c8b78a..7dcbb7e216 100644 --- a/app/Support/DatabaseImport/DatabaseImportCommandBuilder.php +++ b/app/Support/DatabaseImport/DatabaseImportCommandBuilder.php @@ -17,10 +17,10 @@ class DatabaseImportCommandBuilder : 'pg_restore --exit-on-error'.($replaceExisting ? ' --clean --if-exists' : '').' -U $POSTGRES_USER -d ${POSTGRES_DB:-${POSTGRES_USER:-postgres}} '.$path, 'mysql' => $dumpAll ? $this->mysqlDumpAll('mysql', 'MYSQL', $path) - : 'mysql -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE < '.$path, + : '(gunzip -cf '.$path.' 2>/dev/null || cat '.$path.') | mysql -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE', 'mariadb' => $dumpAll ? $this->mysqlDumpAll('mariadb', 'MARIADB', $path) - : 'mariadb -u $MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE < '.$path, + : '(gunzip -cf '.$path.' 2>/dev/null || cat '.$path.') | mariadb -u $MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE', 'mongodb' => 'mongorestore --authenticationDatabase=admin --username $MONGO_INITDB_ROOT_USERNAME --password $MONGO_INITDB_ROOT_PASSWORD --uri mongodb://localhost:27017 --gzip --archive='.$path, default => throw new InvalidArgumentException('Database import is not supported for this database type.'), }; diff --git a/tests/Unit/DatabaseImport/DatabaseImportCommandBuilderTest.php b/tests/Unit/DatabaseImport/DatabaseImportCommandBuilderTest.php index e5cd4abcc4..77d882895b 100644 --- a/tests/Unit/DatabaseImport/DatabaseImportCommandBuilderTest.php +++ b/tests/Unit/DatabaseImport/DatabaseImportCommandBuilderTest.php @@ -36,6 +36,21 @@ test('builds database-specific restore commands', function (string $class, ?stri 'service mongo' => [ServiceDatabase::class, 'mongodb', 'mongorestore'], ]); +test('decompresses gzip backups for single-database mysql and mariadb restores', function (string $class, ?string $type, string $client) { + $builder = new DatabaseImportCommandBuilder; + + $command = $builder->buildRestoreCommand(importResource($class, $type), '/tmp/restore file.sql.gz', false); + + expect($command)->toBe( + "(gunzip -cf '/tmp/restore file.sql.gz' 2>/dev/null || cat '/tmp/restore file.sql.gz') | {$client}" + ); +})->with([ + 'mysql' => [StandaloneMysql::class, null, 'mysql -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE'], + 'mariadb' => [StandaloneMariadb::class, null, 'mariadb -u $MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE'], + 'service mysql' => [ServiceDatabase::class, 'mysql', 'mysql -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE'], + 'service mariadb' => [ServiceDatabase::class, 'mariadb', 'mariadb -u $MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE'], +]); + test('builds dump-all commands and postgres safety scan', function () { $builder = new DatabaseImportCommandBuilder; $postgres = importResource(StandalonePostgresql::class); diff --git a/tests/Unit/Livewire/Database/S3RestoreTest.php b/tests/Unit/Livewire/Database/S3RestoreTest.php index e961f1317c..a0acf229d8 100644 --- a/tests/Unit/Livewire/Database/S3RestoreTest.php +++ b/tests/Unit/Livewire/Database/S3RestoreTest.php @@ -132,23 +132,23 @@ test('dump-all PostgreSQL restore selects the client for the dump format', funct test('buildRestoreCommand handles MySQL without dumpAll', function () { $component = importFormWithResource('App\Models\StandaloneMysql'); $component->dumpAll = false; - $component->mysqlRestoreCommand = 'mysql -u $MYSQL_USER -p$MYSQL_PASSWORD $MYSQL_DATABASE'; $result = $component->buildRestoreCommand('/tmp/test.dump'); expect($result)->toContain('mysql -u $MYSQL_USER'); - expect($result)->toContain("< '/tmp/test.dump'"); + expect($result)->toContain("(gunzip -cf '/tmp/test.dump' 2>/dev/null || cat '/tmp/test.dump') | mysql"); + expect($result)->not->toContain("< '/tmp/test.dump'"); }); test('buildRestoreCommand handles MariaDB without dumpAll', function () { $component = importFormWithResource('App\Models\StandaloneMariadb'); $component->dumpAll = false; - $component->mariadbRestoreCommand = 'mariadb -u $MARIADB_USER -p$MARIADB_PASSWORD $MARIADB_DATABASE'; $result = $component->buildRestoreCommand('/tmp/test.dump'); expect($result)->toContain('mariadb -u $MARIADB_USER'); - expect($result)->toContain("< '/tmp/test.dump'"); + expect($result)->toContain("(gunzip -cf '/tmp/test.dump' 2>/dev/null || cat '/tmp/test.dump') | mariadb"); + expect($result)->not->toContain("< '/tmp/test.dump'"); }); test('buildRestoreCommand always appends the MongoDB archive path', function (bool $dumpAll) {