From 64606591c6efd64990397cb1a8cc2073046b64c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Iv=C3=A1n=20Ovejero?= Date: Fri, 11 Oct 2024 13:02:45 +0200 Subject: [PATCH] Restore `extractTarball` --- .../import-export/database-import.service.ts | 11 ++---- .../cli/src/filesystem/filesystem.service.ts | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/databases/import-export/database-import.service.ts b/packages/cli/src/databases/import-export/database-import.service.ts index cf60cd6c35..e65366b63f 100644 --- a/packages/cli/src/databases/import-export/database-import.service.ts +++ b/packages/cli/src/databases/import-export/database-import.service.ts @@ -3,9 +3,7 @@ import { ensureError, jsonParse } from 'n8n-workflow'; import fs from 'node:fs'; import path from 'node:path'; import readline from 'node:readline'; -import { pipeline } from 'node:stream/promises'; import { Service } from 'typedi'; -import { Extract } from 'unzip-stream'; import { NotObjectLiteralError } from '@/errors/not-object-literal.error'; import { RowCountMismatchError } from '@/errors/row-count-mismatch.error'; @@ -28,7 +26,7 @@ import { DatabaseSchemaService } from '../database-schema.service'; @Service() export class DatabaseImportService { private config: DatabaseImportConfig = { - importFilePath: '', + importFilePath: '/tmp/backup/n8n-db-export-2024-10-11.tar.gz', extractDirPath: '/tmp/backup', truncateDestination: true, // @TODO: Only for dev, default it to `false` later }; @@ -85,12 +83,7 @@ export class DatabaseImportService { if (dbType !== 'postgresdb') throw new UnsupportedDestinationError(dbType); - // @TODO: Stream instead of extracting to filesystem - - await pipeline( - fs.createReadStream(this.config.importFilePath), - Extract({ path: this.config.extractDirPath }), - ); + await this.fsService.extractTarball(this.config.importFilePath, this.config.extractDirPath); this.manifest = await this.getManifest(); diff --git a/packages/cli/src/filesystem/filesystem.service.ts b/packages/cli/src/filesystem/filesystem.service.ts index 572e34bf49..cde0143aa8 100644 --- a/packages/cli/src/filesystem/filesystem.service.ts +++ b/packages/cli/src/filesystem/filesystem.service.ts @@ -1,10 +1,18 @@ import { FileNotFoundError } from 'n8n-core'; import { ensureError } from 'n8n-workflow'; import fs from 'node:fs'; +import path from 'node:path'; +import { pipeline } from 'node:stream/promises'; +import { createGunzip } from 'node:zlib'; +import tar from 'tar-stream'; import { Service } from 'typedi'; +import { Logger } from '@/logging/logger.service'; + @Service() export class FilesystemService { + constructor(private readonly logger: Logger) {} + /** * Ensure a directory exists by checking or creating it. * @param dirPath Path to the directory to check or create. @@ -46,4 +54,31 @@ export class FilesystemService { } } } + + /** + * Extract a tarball to a given directory. + * @param tarballPath Path to the tarball file to extract. + * @param dstDir Path to the directory to extract the tarball into. + * @returns Paths to the extracted files. + */ + async extractTarball(tarballPath: string, dstDir: string) { + await this.checkAccessible(tarballPath); // @TODO: Clearer error if tarball missing + + const extractedFilePaths: string[] = []; + + const extract = tar.extract(); + + extract.on('entry', async (header, stream, next) => { + const filePath = path.join(dstDir, header.name); + await pipeline(stream, fs.createWriteStream(filePath)); + extractedFilePaths.push(filePath); + next(); + }); + + await pipeline(fs.createReadStream(tarballPath), createGunzip(), extract); + + this.logger.info('[FilesystemService] Extracted tarball', { tarballPath }); + + return extractedFilePaths; + } }