Skip to content

Commit

Permalink
Merge pull request #18 from lowlighter/feat-progress-and-native-zip
Browse files Browse the repository at this point in the history
feat: improve install progress and native unzip
  • Loading branch information
lino-levan authored Oct 9, 2023
2 parents 3a1ec6a + d686808 commit 3c672be
Show file tree
Hide file tree
Showing 5 changed files with 233 additions and 28 deletions.
1 change: 1 addition & 0 deletions deno.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// The task to automatically generate `./src/celestial.ts`
"bind": "deno run -A ./bindings/_tools/generate/mod.ts && deno fmt",
"test": "deno test -A --trace-ops",
"bench": "deno bench -A",
"www": "cd docs && pyro dev"
},
"compilerOptions": {
Expand Down
73 changes: 71 additions & 2 deletions deno.lock

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

130 changes: 104 additions & 26 deletions src/cache.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { ensureDirSync } from "https://deno.land/[email protected]/fs/ensure_dir.ts";
import { resolve } from "https://deno.land/[email protected]/path/mod.ts";
import { ensureDir } from "https://deno.land/[email protected]/fs/ensure_dir.ts";
import { dirname } from "https://deno.land/[email protected]/path/dirname.ts";
import { join } from "https://deno.land/[email protected]/path/join.ts";
import { ZipReader } from "https://deno.land/x/[email protected]/index.js";
import ProgressBar from "https://deno.land/x/[email protected]/mod.ts";
import { exists } from "https://deno.land/[email protected]/fs/exists.ts";

export const SUPPORTED_VERSIONS = {
chrome: "118.0.5943.0",
Expand Down Expand Up @@ -41,28 +47,73 @@ function getCache(): Record<string, string> {
}
}

/**
* Clean cache
*/
export async function cleanCache() {
try {
if (await exists(BASE_PATH)) {
await Deno.remove(BASE_PATH, { recursive: true });
}
} catch (error) {
console.warn(`Failed to clean cache: ${error}`);
}
}

async function isQuietInstall() {
// Hide-progress in CI environment
const ci = await Deno.permissions.query({
name: "env",
variable: "CI",
});
if ((ci.state === "granted") && (`${Deno.env.get("CI") ?? ""}`.length)) {
return true;
}
// Hide-progress if asked by user
const quiet = await Deno.permissions.query({
name: "env",
variable: "ASTRAL_QUIET_INSTALL",
});
if (quiet.state === "granted") {
const value = `${Deno.env.get("ASTRAL_QUIET_INSTALL") ?? ""}`;
return value.length ||
!/^(0|[Nn]o?|NO|[Oo]ff|OFF|[Ff]alse|FALSE)$/.test(value);
}
}

async function decompressArchive(source: string, destination: string) {
const unzipCommand = new Deno.Command(
Deno.build.os === "windows" ? "PowerShell" : "unzip",
{
args: Deno.build.os === "windows"
? [
"Expand-Archive",
"-Path",
`"${source}"`,
"-DestinationPath",
`"${destination}"`,
"-Force",
]
: [
"-o",
source,
"-d",
destination,
],
},
);
await unzipCommand.output();
const quiet = await isQuietInstall();
const archive = await Deno.open(source);
const zip = new ZipReader(archive);
const entries = await zip.getEntries();
const bar = !quiet
? new ProgressBar({
title: `Inflating ${destination}`,
total: entries.length,
clear: true,
display: ":title :bar :percent",
})
: null;
let progress = 0;
for (const entry of entries) {
if ((!entry.directory) && (entry.getData)) {
const path = join(destination, entry.filename);
await ensureDir(dirname(path));
const file = await Deno.open(path, {
create: true,
truncate: true,
write: true,
mode: 0o755,
});
await entry.getData(file, { checkSignature: true, useWebWorkers: false });
}
progress++;
bar?.render(progress);
}
await zip.close();
if (!quiet) {
console.log(`Browser saved to ${destination}`);
}
}

/**
Expand All @@ -75,6 +126,7 @@ export async function getBinary(
const VERSION = SUPPORTED_VERSIONS[browser];

const config = getCache();
const quiet = await isQuietInstall();

// If the config doesn't have the revision, download it and return that
if (!config[VERSION]) {
Expand All @@ -98,17 +150,43 @@ export async function getBinary(
);
})[0];

console.log(
"Downloading browser... (this may take a while depending on your internet connection)",
);
const req = await fetch(download.url);
if (!req.body) {
throw new Error(
"Download failed, please check your internet connection and try again",
);
}
await Deno.writeFile(resolve(BASE_PATH, `raw_${VERSION}.zip`), req.body);
console.log(`Download complete (${browser} version ${VERSION})`);
if (quiet) {
await Deno.writeFile(resolve(BASE_PATH, `raw_${VERSION}.zip`), req.body);
} else {
const reader = req.body.getReader();
const archive = await Deno.open(
resolve(BASE_PATH, `raw_${VERSION}.zip`),
{
write: true,
truncate: true,
create: true,
},
);
const bar = new ProgressBar({
title: `Downloading ${browser} ${VERSION}`,
total: Number(req.headers.get("Content-Length") ?? 0),
clear: true,
display: ":title :bar :percent",
});
let downloaded = 0;
do {
const { done, value } = await reader.read();
if (done) {
break;
}
await Deno.write(archive.rid, value);
downloaded += value.length;
bar.render(downloaded);
} while (true);
Deno.close(archive.rid);
console.log(`Download complete (${browser} version ${VERSION})`);
}
await decompressArchive(
resolve(BASE_PATH, `raw_${VERSION}.zip`),
resolve(BASE_PATH, VERSION),
Expand Down
30 changes: 30 additions & 0 deletions tests/_get_binary_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { assertMatch } from "https://deno.land/[email protected]/assert/assert_match.ts";
import { cleanCache, getBinary, launch } from "../mod.ts";
import { assert } from "https://deno.land/[email protected]/assert/assert.ts";

Deno.test("Test download", async () => {
// Download browser
await cleanCache();
const path = await getBinary("chrome");

// Ensure browser is executable
// Note: it seems that on Windows the --version flag does not exists and spawn a
// browser instance instead. The next test ensure that everything is working
// properly anyways
if (Deno.build.os !== "windows") {
const command = new Deno.Command(path, {
args: [
"--version",
],
});
const { success, stdout } = await command.output();
assert(success);
assertMatch(new TextDecoder().decode(stdout), /Google Chrome/i);
}

// Ensure browser is capable of loading pages
const browser = await launch();
const page = await browser.newPage("http://example.com");
await page.waitForSelector("h1");
await browser.close();
});
27 changes: 27 additions & 0 deletions tests/benchs/_get_binary_bench.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { cleanCache, getBinary } from "../../mod.ts";
import { assert } from "https://deno.land/[email protected]/assert/assert.ts";

Deno.bench({
name: "Download progress",
group: "Download browser",
async fn(t) {
// Download browser
await cleanCache();
t.start();
assert(await getBinary("chrome"));
t.end();
},
});

Deno.bench({
name: "Download quiet",
group: "Download browser",
async fn(t) {
// Download browser
await cleanCache();
t.start();
Deno.env.set("ASTRAL_QUIET_INSTALL", "true");
assert(await getBinary("chrome"));
t.end();
},
});

0 comments on commit 3c672be

Please sign in to comment.