mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-07 05:56:21 -10:00
fix(cli): report byte counts from Apple openrsync (#1232)
macOS ships Apple's openrsync as `/usr/bin/rsync`, and its `--stats` output reads `Total transferred file size: 20 B`. The parser accepted only GNU rsync's `bytes`, so on macOS `bytesTransferred` stayed undefined: `rig file copy --json` printed `null` and the human summary left the count out. The parser now accepts `bytes` or `B` followed by a word boundary. GNU output is unchanged, units it doesn't understand (`KB`, `MB`, `KiB`) stay undefined rather than becoming a wrong number, and the rsync command and its arguments are unchanged. The count is shown only; nothing decides on it. A unit test covers openrsync's form and the unsupported units, and a native test copies a real file with whichever rsync the runner has and checks the byte count.
This commit is contained in:
1 parent
904fa99bc5
commit
6d5f6c54ab
2 files changed
+29
-1
No files matched your search
@@ -309,7 +309,7 @@ const CONNECTION_FAILURE_PATTERNS = [
|
||||
];
|
||||
|
||||
function parseStats(stdout: string): { bytesTransferred?: number; filesTransferred?: number } {
|
||||
const bytes = stdout.match(/Total transferred file size:\s*([\d,.]+)\s*bytes/i);
|
||||
const bytes = stdout.match(/Total transferred file size:\s*([\d,.]+)\s*(?:bytes|B)\b/i);
|
||||
const files = stdout.match(/Number of (?:regular )?files transferred:\s*([\d,.]+)/i);
|
||||
const num = (m: RegExpMatchArray | null) => (m ? Number(m[1]!.replace(/[,.](?=\d{3})/g, "").replace(/,/g, "")) : undefined);
|
||||
return { bytesTransferred: num(bytes), filesTransferred: num(files) };
|
||||
|
||||
@@ -363,6 +363,15 @@ describe("classifyRsyncResult / runFileCopy", () => {
|
||||
expect(res).toMatchObject({ ok: true, failedStep: "none", bytesTransferred: 2048, filesTransferred: 1 });
|
||||
});
|
||||
|
||||
it("parses the byte unit emitted by Apple openrsync", () => {
|
||||
const result = classifyRsyncResult(0, "Number of files transferred: 1\nTotal transferred file size: 21 B\n", "");
|
||||
expect(result).toMatchObject({ ok: true, bytesTransferred: 21, filesTransferred: 1 });
|
||||
});
|
||||
|
||||
it.each(["KB", "MB", "KiB"])("does not interpret the unsupported %s unit as bytes", (unit) => {
|
||||
expect(classifyRsyncResult(0, `Total transferred file size: 21 ${unit}\n`, "").bytesTransferred).toBeUndefined();
|
||||
});
|
||||
|
||||
it.each([
|
||||
"user@host: Permission denied (publickey).",
|
||||
"Could not query Keychain entry",
|
||||
@@ -468,3 +477,22 @@ describe("local directory copy semantics", () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it.skipIf(!rsyncAvailable && process.platform !== "darwin")("native local file copies disclose the transferred byte count", async () => {
|
||||
expect(rsyncAvailable, "macOS native copy proof requires the system rsync").toBe(true);
|
||||
const root = mkdtempSync(path.join(process.cwd(), "openrig-copy-stats-"));
|
||||
try {
|
||||
const src = path.join(root, "source.txt");
|
||||
const dst = path.join(root, "copied.txt");
|
||||
const content = Buffer.from("owned stats fixture\n", "utf8");
|
||||
writeFileSync(src, content);
|
||||
const planned = planFileCopy(src, dst);
|
||||
expect(planned.ok).toBe(true);
|
||||
if (!planned.ok) return;
|
||||
const result = await runFileCopy(planned.plan);
|
||||
expect(result.ok, result.stderr).toBe(true);
|
||||
expect(readFileSync(dst)).toEqual(content);
|
||||
expect(result.bytesTransferred).toBe(content.length);
|
||||
expect(result.filesTransferred).toBe(1);
|
||||
} finally { rmSync(root, { recursive: true, force: true }); }
|
||||
});
|
||||
Reference in new issue
Block a user