deno.land / x / zipjs@v2.7.43 / cli-deno / mc-zip.js
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185#!/usr/bin/env -S deno run --allow-write --allow-read --allow-net
/* global Deno, URL, TextEncoderStream */
import { parse as parseArgs } from "https://deno.land/std@0.147.0/flags/mod.ts";import { normalize as normalizePath, resolve as resolvePath, extname } from "https://deno.land/std@0.147.0/path/mod.ts";import { configure, ZipWriter, terminateWorkers, HttpReader } from "../index.js";
const args = parseArgs(Deno.args);const stdout = getTextWriter(Deno.stdout);main();
async function main() { const zipfile = args._.shift(); const list = Array.from(args._); if (!zipfile || !list.length) { await displayUsage(); } else { await runCommand(zipfile, list, getOptions()); }}
async function displayUsage() { await stdout.write("Copyright (c) 2022 Gildas Lormeau. All rights reserved.\n"); await stdout.write("mc-zip 1.0. Usage:\n"); await stdout.write("mc-zip [options] zipfile list\n"); await stdout.write(" The default action is to create or overwrite zipfile entries from list of file names and URLs. Options:\n"); await stdout.write(" --include-directories include directories in the zip file (default: true)\n"); await stdout.write(" --include-sub-directories include sub-directories in the zip file (default: true)\n"); await stdout.write(" --max-workers number of workers (default: number of logical cores)\n"); await stdout.write(" --buffered-write compress entries in parallel with workers (default: true)\n"); await stdout.write(" --password password (default: empty string)\n"); await stdout.write(" --encryption-strength encryption strength when using AES between 1 and 3 (default: 3)\n"); await stdout.write(" --zip-crypto use ZipCrypto instead of AES (default: false)\n"); await stdout.write(" --data-descriptor add data descriptors (default: true)\n"); await stdout.write(" --data-descriptor-signature add data descriptor signatures (default: false)\n"); await stdout.write(" --keep-order keep entries order (default: true)\n"); await stdout.write(" --zip64 use Zip64 format (default: false)\n"); await stdout.write(" --prevent-parent-directories remove occurences of \"../\" in filenames (default: true)\n"); await stdout.write("\n"); Deno.exit(-1);}
function getOptions() { const options = { bufferedWrite: true, encryptionStrength: 3, dataDescriptor: true, keepOrder: true, includeDirectories: true, includeSubDirectories: true, preventParentDirectories: true }; for (const option of Object.getOwnPropertyNames(args)) { if (option != "_") { options[toCamelCase(option)] = args[option]; } } return options;}
async function runCommand(zipfile, list, options) { list = await Promise.all(list.map(file => getFileInfo(file, options))); if (options.includeDirectories) { list = await Promise.all(list.map(file => addDirectories(file, options))); } list = list.flat(); zipfile = await Deno.open(zipfile, { create: true, write: true }); configure(options); const zipWriter = new ZipWriter(zipfile, options); try { await Promise.all(list.map(file => addFile(zipWriter, file))); await zipWriter.close(); } finally { await terminateWorkers(); }}
async function addFile(zipWriter, file) { const options = { onstart: () => stdout.write(" adding: " + file.name + "\n") }; try { const reader = await getReader(file); if (reader) { await zipWriter.add(file.name, reader, options); } } catch (error) { await stdout.write(" error: " + error.message + ", file: " + file.url + "\n"); }}
async function getFileInfo(file, options) { let name, isFile, isDirectory, resolvedName, size; const remote = isRemote(file); if (remote) { const url = new URL(file, import.meta.url); name = url.hostname + (url.pathname == "/" ? "/index.html" : url.pathname); if (!extname(name)) { name += ".html"; } } else { name = file; resolvedName = resolvePath(name); } name = normalizePath(replaceSlashes(name)); if (resolvedName) { if (options.preventParentDirectories) { name = cleanFilename(name); } const stat = await Deno.stat(resolvedName); isFile = stat.isFile; isDirectory = stat.isDirectory; size = stat.size; } return { url: file, name, remote, isFile, size, isDirectory, resolvedName };}
async function addDirectories(file, options) { if (file.isDirectory) { const result = []; for await (const entry of Deno.readDir(resolvePath(file.url))) { const fileInfo = await getFileInfo(file.url + "/" + entry.name, options); if (entry.isFile) { result.push(fileInfo); } else if (entry.isDirectory && options.includeSubDirectories) { result.push(await addDirectories(fileInfo, options)); } } return result.flat(); } else { return file; }}
async function getReader(file) { if (file.remote) { return new HttpReader(file.url); } else if (file.isFile) { const { size } = file; const { readable } = await Deno.open(resolvePath(file.url), { read: true }); return { readable, size }; }}
function isRemote(path) { return path.startsWith("http:") || path.startsWith("https:");}
function getTextWriter(stdout) { const textEncoderStream = new TextEncoderStream(); textEncoderStream.readable.pipeTo(stdout.writable); return textEncoderStream.writable.getWriter();}
function replaceSlashes(url) { url = url.replace(/\\/g, "/"); const match = url.match(/^(?:\/)?(.*?)(?:\/)?$/); if (match) { return match[1]; } else { return url; }}
function cleanFilename(name) { const result = replaceSlashes(("/" + name + "/").replace(/(\/|\\)+(\.+)(\/|\\)+/g, "/")); if (result == name) { return result; } else { return cleanFilename(result); }}
function toCamelCase(kebabCase) { return kebabCase .split("-") .map((word, indexWord) => indexWord ? word.charAt(0).toUpperCase() + word.substring(1) : word) .join("");}
Version Info