Open History to see the last commit
1import type { PinnedRuntimeProgress } from "../cloud/pinnedRuntime.ts";
2
3export function createUpdateProgress(
4 output: Pick<NodeJS.WriteStream, "write" | "isTTY" | "columns"> = process.stderr,
5) {
6 const interactive = output.isTTY && process.env.TERM !== "dumb";
7 const color = interactive && !process.env.NO_COLOR;
8 const style = (code: number, text: string) => (color ? `\x1b[${code}m${text}\x1b[0m` : text);
9 let stage: PinnedRuntimeProgress["stage"] | undefined;
10 let lastDraw = -Infinity;
11 let lineOpen = false;
12 let downloadLine = false;
13 const finish = () => {
14 if (lineOpen) output.write(downloadLine ? "\n" : "\r\x1b[2K");
15 lineOpen = false;
16 };
17 const status = (message: string) => {
18 finish();
19 let line = ` ${message}`;
20 if (interactive) line = line.slice(0, Math.max(0, (output.columns || 80) - 1));
21 output.write(interactive ? `\r\x1b[2K${style(2, line)}` : `${line}\n`);
22 lineOpen = Boolean(interactive);
23 downloadLine = false;
24 };
25 return {
26 finish,
27 status,
28 heading(message: string, detail = "") {
29 finish();
30 output.write(` ${style(2, message)}${detail ? ` ${style(1, detail)}` : ""}\n\n`);
31 },
32 success(message: string) {
33 finish();
34 output.write(` ${style(32, message)}\n\n`);
35 },
36 report(progress: PinnedRuntimeProgress) {
37 if (progress.stage !== stage) {
38 stage = progress.stage;
39 const labels = {
40 download: "Downloading...",
41 verify: "Verifying the download...",
42 extract: "Extracting T3 Code...",
43 validate: "Checking the new executable...",
44 cached: "Using the downloaded release...",
45 };
46 status(labels[stage]);
47 }
48 if (progress.stage !== "download" || !interactive) return;
49 const now = performance.now();
50 if (now - lastDraw < 100 && progress.received !== progress.total) return;
51 lastDraw = now;
52 const mb = (bytes: number) => (bytes / 1024 / 1024).toFixed(1);
53 const { received, total } = progress;
54 const columns = output.columns || 80;
55 let line =
56 columns >= 32
57 ? ` ${style(2, "Downloading")} ${mb(received)} MB`
58 : ` ${mb(received)} MB`.slice(0, Math.max(0, columns - 1));
59 if (total !== undefined && total > 0 && columns >= 9) {
60 const percent = Math.min(100, Math.floor((received / total) * 100));
61 const width = Math.max(1, Math.min(32, columns - 10));
62 const filled = Math.floor((percent * width) / 100);
63 line = ` ${style(94, "■".repeat(filled))}${style(2, "·".repeat(width - filled))} ${String(percent).padStart(3)}%`;
64 if (columns >= 68) line += ` ${style(2, `${mb(received)} / ${mb(total)} MB`)}`;
65 }
66 output.write(`\r\x1b[2K${line}`);
67 lineOpen = true;
68 downloadLine = true;
69 },
70 };
71}