@shopify/cli-kit
Version:
A set of utilities, interfaces, and models that are common across all the platform features
96 lines • 3.67 kB
JavaScript
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