@obsidize/tar-browserify
Version:
Browser-based tar utility for packing and unpacking tar files (stream-capable)
113 lines (112 loc) • 4.39 kB
JavaScript
import { Constants } from '../common/constants';
import { TarUtility } from '../common/tar-utility';
import { UstarHeaderLinkIndicatorType } from '../header/ustar/ustar-header-link-indicator-type';
import { ArchiveEntry } from './archive-entry';
/**
* Generic utility for building a tar octet stream by adding JSON-style entries.
* See the `add***()` options in this class definition for details.
*/
export class ArchiveWriter {
constructor(entries = []) {
this.entries = entries;
}
/**
* Combines the given array of entries into a single, complete tarball buffer
*/
static serialize(entries) {
let outputLength = Constants.TERMINAL_PADDING_SIZE;
const outputBuffers = [];
for (const entry of entries) {
const entryBytes = entry.toUint8Array();
outputBuffers.push(entryBytes);
outputLength += entryBytes.byteLength;
}
const output = new Uint8Array(outputLength);
let offset = 0;
for (const entryBuf of outputBuffers) {
output.set(entryBuf, offset);
offset += entryBuf.byteLength;
}
return output;
}
/**
* @returns a complete tar buffer from all the currently set tar entries in this instance.
*/
toUint8Array() {
return ArchiveWriter.serialize(this.entries);
}
/**
* Convenience for appending a new entry to the existing `entries` array
* @returns `this` for operation chaining
*/
addEntry(entry) {
this.entries.push(entry);
return this;
}
/**
* Convenience for appending a new entry to the existing `entries` array.
* @returns `this` for operation chaining
*/
addEntryWith(header, content) {
return this.addEntry(new ArchiveEntry({ headerAttributes: header, content }));
}
/**
* Convenience option for building tarball data
* @param path - the file name, e.g. './relative/path/to/your/file.txt'
* @param content - the content of the file (shocker!)
* @param headerOptions - custom options for this entry
* @returns `this` for operation chaining
*/
addTextFile(path, content, headerOptions) {
return this.addBinaryFile(path, TarUtility.encodeString(content), headerOptions);
}
/**
* Convenience option for building tarball data
* @param path - the file name, e.g. './relative/path/to/your/file.bin'
* @param content - the content of the file (shocker!)
* @param headerOptions - custom options for this entry
* @returns `this` for operation chaining
*/
addBinaryFile(path, content, headerOptions = {}) {
const combinedHeaderOptions = Object.assign({
fileName: path,
fileSize: content.byteLength,
typeFlag: UstarHeaderLinkIndicatorType.NORMAL_FILE,
}, headerOptions);
return this.addEntryWith(combinedHeaderOptions, content);
}
/**
* Convenience option for building tarball data
* @param path - the directory name, e.g. './relative/path/to/your/dir'
* @param headerOptions - custom options for this entry
* @returns `this` for operation chaining
*/
addDirectory(path, headerOptions = {}) {
const combinedHeaderOptions = Object.assign({
fileName: path,
typeFlag: UstarHeaderLinkIndicatorType.DIRECTORY,
}, headerOptions);
return this.addEntryWith(combinedHeaderOptions);
}
/**
* Removes any entries from this writer's cache that meet the given predicate condition.
* @param predicate - delegate that will return true for any entry that should be removed.
* @returns `this` for operation chaining
*/
removeEntriesWhere(predicate) {
this.entries = this.entries.filter((v) => !predicate(v));
return this;
}
/**
* Convenience option for cleaning the header of each listed entry.
* When headers are "cleaned", unknown PAX properties will be removed
* (e.g. unwanted MacOS "quarantine" headers), and USTAR fields
* will be normalized (if necessary).
*/
cleanAllHeaders() {
for (const entry of this.entries) {
entry.header.clean();
}
return this;
}
}