-
-
Save guest271314/8256d618b4a94ccc368c1a61e65e4cfa to your computer and use it in GitHub Desktop.
Basic unzip implementation based on zip.js and Deno (Fetch and unzip Chrome-For-Testing Canary Channel)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Fetch and unzip Chrome-For-Testing Canary Channel | |
// deno run -A unzip.js | |
/* eslint-disable no-console */ | |
/* global Deno, Intl */ | |
"use strict"; | |
// import { parse } from "https://deno.land/std/flags/mod.ts"; | |
import { exists } from "https://deno.land/std/fs/mod.ts"; | |
import { basename, dirname } from "https://deno.land/std/path/mod.ts"; | |
import { | |
ERR_HTTP_RANGE, | |
HttpReader, | |
terminateWorkers, | |
Uint8ArrayReader, | |
Uint8ArrayWriter, | |
ZipReader, | |
} from "https://raw.githubusercontent.com/gildas-lormeau/zip.js/master/index.js"; | |
const executables = new Set([ | |
"chrome", | |
"chrome-wrapper", | |
"chrome_crashpad_handler", | |
"chrome_sandbox", | |
"libEGL.so", | |
"libGLESv2.so", | |
"libvk_swiftshader.so", | |
"libvulkan.so.1", | |
"nacl_helper", | |
"nacl_helper_bootstrap", | |
"nacl_irt_x86_64.nexe", | |
"xdg-mime", | |
"xdg-settings", | |
]); | |
const json = await (await fetch( | |
"https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json", | |
)).json(); | |
const { | |
url, | |
} = json.channels.Canary.downloads.chrome.find(({ | |
platform, | |
}) => platform === "linux64"); | |
console.log(`Fetch ${url}`); | |
const response = await fetch(url); | |
const length = response.headers.get("content-length"); | |
const ab = new ArrayBuffer(length); | |
const uint8 = new Uint8Array(ab); | |
const encoder = new TextEncoder(); | |
let offset = 0; | |
async function log(bytes) { | |
// https://medium.com/deno-the-complete-reference/deno-nuggets-overwrite-a-console-log-line-2513e52e264b | |
await Deno.stdout.write( | |
encoder.encode(`${bytes} of ${length} bytes written.\r`), | |
); | |
} | |
// Just so we see what's going on | |
await response.body.pipeTo( | |
new WritableStream({ | |
start() { | |
console.log("Start reading stream."); | |
}, | |
async write(value) { | |
uint8.set(value, offset); | |
await log(offset += value.length); | |
}, | |
close() { | |
console.log("\nDone reading stream."); | |
}, | |
}), | |
); | |
// const ab = await response.arrayBuffer(); | |
// console.log(ab.byteLength); | |
await Deno.writeFile("chrome-linux64.zip", uint8); | |
unzip({ _: ["chrome-linux64.zip"] }).catch((error) => | |
console.error(error.toString()) | |
); | |
async function unzip(args) { | |
if (args.l) { | |
await listEntries(args.l || args._[0]); | |
} else { | |
const archive = args._.shift(); | |
if (archive) { | |
await unzipEntries(archive, args._); | |
await Deno.remove("chrome-linux64.zip"); | |
} | |
} | |
} | |
async function unzipEntries(archive, filenames) { | |
const zipReader = new ZipReader(await getReader(archive)); | |
const entries = await zipReader.getEntries(); | |
let selectedEntries; | |
if (filenames.length) { | |
selectedEntries = entries.filter((entry) => | |
filenames.includes(entry.filename) | |
); | |
} else { | |
selectedEntries = entries; | |
} | |
await Promise.all(selectedEntries.map(async (entry) => { | |
const entryDirectory = dirname(entry.filename); | |
if (!await exists(entryDirectory)) { | |
await Deno.mkdir(entryDirectory, { recursive: true }); | |
} | |
if (!entry.directory) { | |
await Deno.writeFile( | |
entry.filename, | |
await entry.getData(new Uint8ArrayWriter()), | |
); | |
} | |
})); | |
await terminateWorkers(); | |
for (const file of executables) { | |
await Deno.chmod(`chrome-linux64/${file}`, 0o764); | |
} | |
} | |
async function listEntries(archive) { | |
const zipReader = new ZipReader(await getReader(archive)); | |
const entries = await zipReader.getEntries(); | |
let totalSize = 0; | |
console.log("Archive: ", archive); | |
let maxNameLength = 0; | |
const formattedData = entries.map((entry) => { | |
const length = formatLength(entry.uncompressedSize); | |
const splitDate = entry.lastModDate.toISOString().split("T"); | |
const date = splitDate[0].padStart(11); | |
const time = splitDate[1].match(/([^:]+:[^:]+):/)[1].padEnd(7); | |
const name = entry.filename; | |
totalSize += entry.uncompressedSize; | |
maxNameLength = Math.max(maxNameLength, length.length); | |
return { length, date, time, name }; | |
}); | |
console.log( | |
"Length".padStart(maxNameLength - 1, " "), | |
" Date Time Name", | |
); | |
const lengthSeparator = "-".padStart(maxNameLength, "-"); | |
console.log(lengthSeparator, " ---------- ----- ----"); | |
formattedData.forEach(({ length, date, time, name }) => | |
console.log(length.padStart(maxNameLength), date, time, name) | |
); | |
console.log(lengthSeparator, " ----"); | |
console.log(formatLength(totalSize)); | |
} | |
function formatLength(length) { | |
return new Intl.NumberFormat().format(length); | |
} | |
async function getReader(archive) { | |
if (/^https?:/.test(archive)) { | |
try { | |
return new HttpReader(archive, { | |
useRangeHeader: true, | |
forceRangeRequests: true, | |
}); | |
} catch (error) { | |
if (error.message == ERR_HTTP_RANGE) { | |
try { | |
return new HttpReader(archive, { useRangeHeader: true }); | |
} catch (error) { | |
if (error.message == ERR_HTTP_RANGE) { | |
return new HttpReader(archive); | |
} else { | |
throw error; | |
} | |
} | |
} else { | |
throw error; | |
} | |
} | |
} else { | |
if (!basename(archive).includes(".")) { | |
archive += ".zip"; | |
} | |
return new Uint8ArrayReader(await Deno.readFile(archive)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment