Skip to content

Commit

Permalink
fix: better unarchive
Browse files Browse the repository at this point in the history
  • Loading branch information
Yohe-Am committed Nov 30, 2023
1 parent f21dafb commit 0b0fb49
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 35 deletions.
11 changes: 11 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion deps/plug.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
//! This contains dependencies used by plugins

export * from "./common.ts";
export * as compress from "https://deno.land/x/[email protected]/mod.ts";
export * as zipjs from "https://deno.land/x/[email protected]/index.js";
export * as compress from "https://deno.land/x/[email protected]/mod.ts";
export { Foras } from "https://deno.land/x/[email protected]/src/deno/mod.ts";
export * as std_tar from "https://deno.land/[email protected]/archive/tar.ts";
export * as std_streams from "https://deno.land/[email protected]/streams/mod.ts";
export * as std_io from "https://deno.land/[email protected]/io/mod.ts";
135 changes: 101 additions & 34 deletions plug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,13 @@ import {
} from "./core/mod.ts";
import {
compress,
Foras,
log,
std_fs,
std_io,
std_path,
std_streams,
std_tar,
std_url,
zipjs,
} from "./deps/plug.ts";
Expand Down Expand Up @@ -176,47 +180,110 @@ export async function unarchive(
case ".gz":
case ".tar.gz":
case ".tgz":
await compress.tgz.uncompress(path, dest, {
debug: true,
});
await untgz(path, dest);
break;
case ".tar":
await compress.tar.uncompress(path, dest, {
debug: true,
});
await untar(path, dest);
break;
case ".zip": {
const zipFile = await Deno.open(path, { read: true });
const zipReader = new zipjs.ZipReader(zipFile.readable);
try {
await Promise.allSettled(
(await zipReader.getEntries()).map(async (entry) => {
if (entry.directory) {
await std_fs.ensureDir(std_path.resolve(dest, entry.filename));
return;
}
const filePath = std_path.resolve(dest, entry.filename);
await std_fs.ensureDir(std_path.dirname(filePath));
const file = await Deno.open(filePath, {
create: true,
truncate: true,
write: true,
mode: entry.externalFileAttribute >> 16,
});
if (!entry.getData) throw Error("impossible");
await entry.getData(file.writable);
}),
);
} catch (err) {
throw err;
} finally {
zipReader.close();
}
case ".zip":
await unzip(path, dest);
break;
}
default:
throw Error("unsupported archive extension: ${ext}");
}
}

export async function untgz(
path: string,
dest = "./",
) {
// FIXME: replace Foras with zip.js from below if possible
// this unzips the whole thing into memory first
// but I was not able to figure out the
await Foras.initBundledOnce();
const tgzFile = await Deno.open(path, { read: true });
const gzDec = new Foras.GzDecoder();
await std_streams.copy(tgzFile, {
write(buf) {
const mem = new Foras.Memory(buf);
gzDec.write(mem);
mem.freeNextTick();
return Promise.resolve(buf.length);
},
});
const buf = gzDec.finish().copyAndDispose();
await untarReader(new std_io.Buffer(buf), dest);
}
export async function untar(
path: string,
dest = "./",
) {
const tarFile = await Deno.open(path, {
read: true,
});

try {
await untarReader(tarFile, dest);
} catch (err) {
throw err;
} finally {
tarFile.close();
}
}

/// This does not close the reader
export async function untarReader(
reader: Deno.Reader,
dest = "./",
) {
for await (const entry of new std_tar.Untar(reader)) {
const filePath = std_path.resolve(dest, entry.fileName);
if (entry.type === "directory") {
await std_fs.ensureDir(filePath);
return;
}
await std_fs.ensureDir(std_path.dirname(filePath));
const file = await Deno.open(filePath, {
create: true,
truncate: true,
write: true,
mode: entry.fileMode,
});
await std_streams.copy(entry, file);
file.close();
}
}

export async function unzip(
path: string,
dest = "./",
) {
const zipFile = await Deno.open(path, { read: true });
const zipReader = new zipjs.ZipReader(zipFile.readable);
try {
await Promise.allSettled(
(await zipReader.getEntries()).map(async (entry) => {
const filePath = std_path.resolve(dest, entry.filename);
if (entry.directory) {
await std_fs.ensureDir(filePath);
return;
}
await std_fs.ensureDir(std_path.dirname(filePath));
const file = await Deno.open(filePath, {
create: true,
truncate: true,
write: true,
mode: entry.externalFileAttribute >> 16,
});
if (!entry.getData) throw Error("impossible");
await entry.getData(file.writable);
}),
);
} catch (err) {
throw err;
} finally {
zipReader.close();
}
}

export const removeFile = Deno.remove;

0 comments on commit 0b0fb49

Please sign in to comment.