90 lines
2.7 KiB
TypeScript
90 lines
2.7 KiB
TypeScript
|
|
import * as plugins from './plugins.js';
|
||
|
|
import type { IArchiveEntry, ITarEntry, TCompressionLevel } from './interfaces.js';
|
||
|
|
import { GzipTools } from './classes.gziptools.js';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* TAR archive creation and extraction utilities using modern-tar (browser-compatible)
|
||
|
|
*/
|
||
|
|
export class TarTools {
|
||
|
|
/**
|
||
|
|
* Pack files into a TAR buffer
|
||
|
|
*/
|
||
|
|
public async packFiles(files: IArchiveEntry[]): Promise<Uint8Array> {
|
||
|
|
const entries: ITarEntry[] = [];
|
||
|
|
|
||
|
|
for (const file of files) {
|
||
|
|
let data: Uint8Array;
|
||
|
|
|
||
|
|
if (typeof file.content === 'string') {
|
||
|
|
data = new TextEncoder().encode(file.content);
|
||
|
|
} else if (file.content instanceof Uint8Array) {
|
||
|
|
data = file.content;
|
||
|
|
} else if (file.content instanceof plugins.smartfile.SmartFile) {
|
||
|
|
data = new Uint8Array(file.content.contents);
|
||
|
|
} else if (file.content instanceof plugins.smartfile.StreamFile) {
|
||
|
|
const buffer = await file.content.getContentAsBuffer();
|
||
|
|
data = new Uint8Array(buffer);
|
||
|
|
} else {
|
||
|
|
throw new Error('Unsupported content type for TAR entry');
|
||
|
|
}
|
||
|
|
|
||
|
|
entries.push({
|
||
|
|
header: {
|
||
|
|
name: file.archivePath,
|
||
|
|
size: data.length,
|
||
|
|
type: 'file',
|
||
|
|
mode: file.mode,
|
||
|
|
mtime: file.mtime,
|
||
|
|
},
|
||
|
|
body: data,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
return plugins.modernTar.packTar(entries);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Extract a TAR buffer to an array of entries
|
||
|
|
*/
|
||
|
|
public async extractTar(data: Uint8Array): Promise<Array<{ path: string; content: Uint8Array; isDirectory: boolean }>> {
|
||
|
|
const entries = await plugins.modernTar.unpackTar(data);
|
||
|
|
const result: Array<{ path: string; content: Uint8Array; isDirectory: boolean }> = [];
|
||
|
|
|
||
|
|
for (const entry of entries) {
|
||
|
|
const isDirectory = entry.header.type === 'directory' || entry.header.name.endsWith('/');
|
||
|
|
|
||
|
|
// modern-tar uses 'data' property, not 'body'
|
||
|
|
const content = entry.data ?? new Uint8Array(0);
|
||
|
|
|
||
|
|
result.push({
|
||
|
|
path: entry.header.name,
|
||
|
|
content,
|
||
|
|
isDirectory,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Pack files into a TAR.GZ buffer
|
||
|
|
*/
|
||
|
|
public async packFilesToTarGz(
|
||
|
|
files: IArchiveEntry[],
|
||
|
|
compressionLevel?: TCompressionLevel
|
||
|
|
): Promise<Uint8Array> {
|
||
|
|
const tarBuffer = await this.packFiles(files);
|
||
|
|
const gzipTools = new GzipTools();
|
||
|
|
return gzipTools.compress(tarBuffer, compressionLevel);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Extract a TAR.GZ buffer to an array of entries
|
||
|
|
*/
|
||
|
|
public async extractTarGz(data: Uint8Array): Promise<Array<{ path: string; content: Uint8Array; isDirectory: boolean }>> {
|
||
|
|
const gzipTools = new GzipTools();
|
||
|
|
const tarBuffer = await gzipTools.decompress(data);
|
||
|
|
return this.extractTar(tarBuffer);
|
||
|
|
}
|
||
|
|
}
|