import type { SmartArchive } from './classes.smartarchive.js'; import * as plugins from './plugins.js'; export class TarTools { // INSTANCE smartArchiveRef: SmartArchive; constructor(smartArchiveRefArg: SmartArchive) { this.smartArchiveRef = smartArchiveRefArg; } // packing public async addFileToPack( pack: plugins.tarStream.Pack, optionsArg: { fileName?: string; content?: | string | Buffer | plugins.smartstream.stream.Readable | plugins.smartfile.SmartFile | plugins.smartfile.StreamFile; byteLength?: number; filePath?: string; } ): Promise { return new Promise(async (resolve, reject) => { let fileName = optionsArg.fileName || optionsArg.content instanceof plugins.smartfile.SmartFile ? (optionsArg.content as plugins.smartfile.SmartFile).relative : null || optionsArg.content instanceof plugins.smartfile.StreamFile ? (optionsArg.content as plugins.smartfile.StreamFile).relativeFilePath : null || optionsArg.filePath; /** * contentByteLength is used to set the size of the entry in the tar file */ let contentByteLength: number; if (optionsArg.byteLength) { contentByteLength = optionsArg.byteLength; } else if (typeof optionsArg.content === 'string') { contentByteLength = Buffer.byteLength(optionsArg.content, 'utf8'); } else if (Buffer.isBuffer(optionsArg.content)) { contentByteLength = optionsArg.content.length; } else if (optionsArg.content instanceof plugins.smartfile.SmartFile) { contentByteLength = await optionsArg.content.getSize(); // assuming SmartFile has getSize method } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) { contentByteLength = await optionsArg.content.getSize(); // assuming StreamFile has getSize method } else if (optionsArg.content instanceof plugins.smartstream.stream.Readable) { console.warn( '@push.rocks/smartarchive: When streaming, it is recommended to provide byteLength, if known.' ); } else if (optionsArg.filePath) { const fileStat = await plugins.smartfile.fs.stat(optionsArg.filePath); contentByteLength = fileStat.size; } /** * here we try to harmonize all kind of entries towards a readable stream */ let content: plugins.smartstream.stream.Readable; if (Buffer.isBuffer(optionsArg.content)) { content = plugins.smartstream.stream.Readable.from(optionsArg.content); } else if (typeof optionsArg.content === 'string') { content = plugins.smartstream.stream.Readable.from(Buffer.from(optionsArg.content)); } else if (optionsArg.content instanceof plugins.smartfile.SmartFile) { content = plugins.smartstream.stream.Readable.from(optionsArg.content.contents); } else if (optionsArg.content instanceof plugins.smartfile.StreamFile) { content = await optionsArg.content.createReadStream(); } else if (optionsArg.content instanceof plugins.smartstream.stream.Readable) { content = optionsArg.content; } const entry = pack.entry( { name: fileName, ...(contentByteLength ? { size: contentByteLength, } : null), }, (err: Error) => { if (err) { reject(err); } else { resolve(); } } ); content.pipe(entry); entry.on('end', () => { resolve(); }); }); } /** * packs a directory from disk into a tar stream * @param directoryPath */ public async packDirectory(directoryPath: string) { const fileTree = await plugins.smartfile.fs.listFileTree(directoryPath, '**/*'); const pack = await this.getPackStream(); for (const filePath of fileTree) { const absolutePath = plugins.path.join(directoryPath, filePath); const fileStat = await plugins.smartfile.fs.stat(absolutePath); await this.addFileToPack(pack, { byteLength: fileStat.size, filePath: filePath, fileName: filePath, content: plugins.smartfile.fsStream.createReadStream(absolutePath), }); } } public async getPackStream() { const pack = plugins.tarStream.pack(); return pack; } // extracting getDecompressionStream() { return plugins.tarStream.extract(); } }