UNPKG

@shopify/cli-kit

Version:

A set of utilities, interfaces, and models that are common across all the platform features

96 lines 3.67 kB
import { relativePath, joinPath } from './path.js'; import { glob, removeFile } from './fs.js'; import { outputDebug, outputContent, outputToken } from '../../public/node/output.js'; import archiver from 'archiver'; import { createWriteStream, readFileSync, writeFileSync } from 'fs'; import { tmpdir } from 'os'; import { randomUUID } from 'crypto'; /** * It zips a directory and by default normalizes the paths to be forward-slash. * Even with forward-slash paths, zip files should still be able to be opened on * Windows. * * @param options - ZipOptions. */ export async function zip(options) { const { inputDirectory, outputZipPath, matchFilePattern = '**/*' } = options; outputDebug(outputContent `Zipping ${outputToken.path(inputDirectory)} into ${outputToken.path(outputZipPath)}`); const pathsToZip = await glob(matchFilePattern, { cwd: inputDirectory, absolute: true, dot: true, followSymbolicLinks: false, }); return new Promise((resolve, reject) => { const archive = archiver('zip'); const output = createWriteStream(outputZipPath); output.on('close', () => { resolve(); }); archive.on('error', (error) => { reject(error); }); archive.pipe(output); for (const filePath of pathsToZip) { const fileRelativePath = relativePath(inputDirectory, filePath); archive.file(filePath, { name: fileRelativePath }); } // eslint-disable-next-line @typescript-eslint/no-floating-promises archive.finalize(); }); } /** * It compresses a directory with Brotli. * First creates a tar archive to preserve directory structure, * then compresses it with Brotli. * * @param options - BrotliOptions. */ export async function brotliCompress(options) { const tempTarPath = joinPath(tmpdir(), `${randomUUID()}.tar`); try { // Create tar archive using archiver await new Promise((resolve, reject) => { const archive = archiver('tar'); const output = createWriteStream(tempTarPath); output.on('close', () => resolve()); archive.on('error', (error) => reject(error)); archive.pipe(output); glob(options.matchFilePattern ?? '**/*', { cwd: options.inputDirectory, absolute: true, dot: true, followSymbolicLinks: false, }) .then((pathsToZip) => { for (const filePath of pathsToZip) { const fileRelativePath = relativePath(options.inputDirectory, filePath); archive.file(filePath, { name: fileRelativePath }); } // eslint-disable-next-line @typescript-eslint/no-floating-promises archive.finalize(); }) .catch((error) => reject(error)); }); const tarContent = readFileSync(tempTarPath); const brotli = await import('brotli'); const compressed = brotli.default.compress(tarContent, { quality: 7, mode: 0, }); if (!compressed) { throw new Error('Brotli compression failed'); } writeFileSync(options.outputPath, compressed); } finally { try { await removeFile(tempTarPath); // eslint-disable-next-line no-catch-all/no-catch-all } catch (error) { outputDebug(outputContent `Failed to clean up temporary file: ${outputToken.path(tempTarPath)}`); } } } //# sourceMappingURL=archiver.js.map