@ayonli/jsext
Version:
A JavaScript extension package for building strong and modern applications.
197 lines (192 loc) • 7.96 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var bytes = require('../bytes.js');
var env = require('../env.js');
var event = require('../event.js');
var fs = require('../fs.js');
var fs_util = require('../fs/util.js');
var path = require('../path.js');
var runtime = require('../runtime.js');
var archive_Tarball = require('./Tarball.js');
async function untar(src, dest = {}, options = {}) {
var _a;
let _dest = undefined;
if (typeof dest === "string") {
_dest = options.root ? dest : path.resolve(dest);
}
else if (typeof dest === "object") {
if (typeof FileSystemDirectoryHandle === "function" &&
dest instanceof FileSystemDirectoryHandle) {
_dest = dest;
}
else {
options = dest;
}
}
src = typeof src === "string" && options.root ? path.resolve(src) : src;
let input = src instanceof ReadableStream ? src : fs.createReadableStream(src, options);
if (options.gzip) {
const gzip = new DecompressionStream("gzip");
input = input.pipeThrough(gzip);
}
const { signal } = options;
signal === null || signal === void 0 ? void 0 : signal.addEventListener("abort", () => {
input.cancel(signal.reason);
});
if (!_dest) {
return await archive_Tarball.default.load(input);
}
else if (typeof _dest === "string") {
await fs.ensureDir(_dest, options);
}
let totalWrittenBytes = 0;
let totalBytes = (_a = options.size) !== null && _a !== void 0 ? _a : 0;
if (!totalBytes && options.onProgress) {
if (typeof src === "string") {
const info = await fs.stat(src, options);
totalBytes = info.size;
}
else if (typeof FileSystemFileHandle === "function"
&& src instanceof FileSystemFileHandle) {
const info = await src.getFile();
totalBytes = info.size;
}
}
const entries = [];
const reader = input.getReader();
let lastChunk = new Uint8Array(0);
let entry = null;
let writer = null;
let writtenBytes = 0;
let paddingSize = 0;
try {
outer: while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
lastChunk = lastChunk.byteLength ? bytes.concat(lastChunk, value) : value;
while (true) {
if (paddingSize > 0 && lastChunk.byteLength >= paddingSize) {
lastChunk = lastChunk.subarray(paddingSize);
paddingSize = 0;
}
if (!entry) {
if (lastChunk.byteLength >= archive_Tarball.HEADER_LENGTH) {
const _header = archive_Tarball.parseHeader(lastChunk);
if (_header) {
lastChunk = _header[2];
entry = archive_Tarball.createEntry(_header[0]);
entries.push(entry);
}
else {
lastChunk = new Uint8Array(0);
break outer;
}
}
else {
break;
}
}
const fileSize = entry.size;
let filename = undefined;
if (writer) {
const chunk = lastChunk.subarray(0, fileSize - writtenBytes);
await writer.write(chunk);
lastChunk = lastChunk.subarray(fileSize - writtenBytes);
writtenBytes += chunk.byteLength;
if (chunk.byteLength) {
totalWrittenBytes += chunk.byteLength;
if (options.onProgress) {
options.onProgress(event.createProgressEvent("progress", {
lengthComputable: !!totalBytes,
loaded: totalWrittenBytes,
total: totalBytes
}));
}
}
}
else if (entry.kind === "directory") {
if (typeof FileSystemDirectoryHandle === "function" &&
_dest instanceof FileSystemDirectoryHandle) {
await fs.ensureDir(entry.relativePath, { ...options, root: _dest });
}
else {
filename = path.join(_dest, entry.relativePath);
await fs.ensureDir(filename, options);
}
}
else {
let _options = options;
if (typeof FileSystemDirectoryHandle === "function" &&
_dest instanceof FileSystemDirectoryHandle) {
_options = { ...options, root: _dest };
filename = entry.relativePath;
}
else {
filename = path.join(_dest, entry.relativePath);
}
const dir = path.dirname(filename);
if (dir && dir !== "." && dir !== "/") {
await fs.ensureDir(dir, _options);
}
const output = fs.createWritableStream(filename, _options);
writer = output.getWriter();
continue;
}
if (writtenBytes === fileSize) {
paddingSize = archive_Tarball.HEADER_LENGTH - (fileSize % archive_Tarball.HEADER_LENGTH || archive_Tarball.HEADER_LENGTH);
writtenBytes = 0;
writer === null || writer === void 0 ? void 0 : writer.close();
writer = null;
entry = null;
}
else {
break;
}
}
}
if (lastChunk.byteLength) {
throw new Error("The archive is corrupted");
}
else if (totalBytes && totalWrittenBytes < totalBytes && options.onProgress) {
totalWrittenBytes = totalBytes;
options.onProgress(event.createProgressEvent("progress", {
lengthComputable: true,
loaded: totalWrittenBytes,
total: totalBytes,
}));
}
}
finally {
reader.releaseLock();
}
if ((env.isDeno || env.isNodeLike) && typeof _dest === "string") {
const isWindows = runtime.platform() === "windows";
const tree = fs_util.makeTree(path.basename(_dest), entries);
await (async function restoreStats(nodes) {
var _a;
for (const entry of nodes) {
const filename = path.join(_dest, entry.relativePath);
if (entry.kind === "directory" && ((_a = entry.children) === null || _a === void 0 ? void 0 : _a.length)) {
// must restore contents' stats before the directory itself
await restoreStats(entry.children);
}
// Only restore the permission mode and the last modified time,
// don't restore the owner and group, because they may not exist
// and may cause an error.
//
// This behavior is consistent with `tar -xf archive.tar` in
// Unix-like systems.
if (entry.mode && !isWindows) {
await fs.chmod(filename, entry.mode);
}
if (entry.mtime) {
await fs.utimes(filename, new Date(), entry.mtime);
}
}
})(tree.children);
}
}
exports.default = untar;
//# sourceMappingURL=untar.js.map