diff --git a/src/file-viewer/rsync.ts b/src/file-viewer/rsync.ts index 1d9d61077ff7ce14e1734fa426f620368d4c08bd..9f759a031ba4bef1ffbf6f3c24c23e5370282224 100644 --- a/src/file-viewer/rsync.ts +++ b/src/file-viewer/rsync.ts @@ -1,4 +1,4 @@ -// Utilities for spawning rsync and consuming its output as a `Progress` +// Utilities for spawning rsync and consuming its output as a `progress.Node` // A headless parser is available with `Parse` export type Line = @@ -37,6 +37,8 @@ export async function spawn(options: SpawnOptions) { }); const parser = new Parse(); let running = true; + let fileNode: progress.Node | null = null; + let fileNodeTransferNumber = 0; const stdoutSplitter = readline.createInterface({ input: proc.stdout }); const stderrSplitter = readline.createInterface({ input: proc.stderr }); @@ -51,7 +53,7 @@ export async function spawn(options: SpawnOptions) { node.log[result.level](result.message); } else if (result.kind === "count") { if (!running) return; - node.text = `${title} (${result.files} files...)`; + node.total = result.files; } else if (result.kind === "progress") { if (!running) return; const { @@ -64,17 +66,23 @@ export async function spawn(options: SpawnOptions) { } = result; node.value = transferNumber; node.total = totalFiles; - const extras = [ - string.formatByteSize(bytesTransferred), - (totalFiles > filesToCheck) - ? `${totalFiles - filesToCheck} unchecked` - : null, - speed, - ].filter(Boolean).join(", "); + node.text = filesToCheck > 0 + ? `${title} (${filesToCheck} left)` + : title; const fileName = currentFile.length > 20 ? `${currentFile.slice(0, 3)}..${currentFile.slice(-15)}` : currentFile; - node.text = `${title} - ${fileName}${extras.length > 0 ? ` (${extras})` : ""}`; + if (!fileNode || fileNodeTransferNumber !== transferNumber) { + fileNode?.end(); + fileNode = node.start(fileName, { units: "bytes" }); + fileNodeTransferNumber = transferNumber; + } + const estimatedTotal = result.percentage > 0 + ? Math.ceil(bytesTransferred / (result.percentage / 100)) + : 0; + fileNode.text = speed ? `${fileName} (${speed})` : fileName; + fileNode.value = bytesTransferred; + fileNode.total = estimatedTotal; } else result satisfies never; }; @@ -83,6 +91,7 @@ export async function spawn(options: SpawnOptions) { const [code, signal] = await events.once(proc, "close"); running = false; + fileNode?.end(); if (code !== 0) { const fmt = code ? `code ${code}` : `signal ${signal}`; const e: any = new Error(`rsync failed with ${fmt}`); @@ -119,7 +128,7 @@ export class Parse { totalStr, ] = progressMatch; - this.currentTransfer = Number(transferStr); + if (transferStr) this.currentTransfer = Number(transferStr); return { kind: "progress", @@ -181,7 +190,6 @@ export class Parse { import { Path } from "#sitegen/path"; import { UNWRAP } from "@clo/lib/assert"; import * as progress from "@clo/lib/progress"; -import * as string from "@clo/lib/string"; import * as child_process from "node:child_process"; import events from "node:events"; import * as readline from "node:readline";