Skip to content

Commit fc46ccf

Browse files
committed
fix(clownfish): address review for ghcrawl-156809-autonomous-smoke (1)
1 parent ec43f65 commit fc46ccf

2 files changed

Lines changed: 132 additions & 6 deletions

File tree

scripts/format-docs.mjs

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { buildCmdExeCommandLine } from "./windows-cmd-helpers.mjs";
1010

1111
const ROOT = path.resolve(import.meta.dirname, "..");
1212
const OXFMT_CONFIG = path.join(ROOT, ".oxfmtrc.jsonc");
13+
const WINDOWS_CMD_EXE_MAX_COMMAND_LINE_LENGTH = 8191;
14+
const WINDOWS_CMD_EXE_COMMAND_LINE_BUDGET = 7600;
1315

1416
function childFailureMessage(commandName, result) {
1517
if (result.error) {
@@ -63,13 +65,65 @@ export function createOxfmtSpawnSpec(args, params = {}) {
6365
};
6466
}
6567

66-
export function runOxfmt(files, params = {}) {
68+
function oxfmtArgs(files, params = {}) {
69+
return ["--write", "--threads=1", "--config", params.config ?? OXFMT_CONFIG, ...files];
70+
}
71+
72+
function commandLineLength(spec) {
73+
return [spec.command, ...spec.args].join(" ").length;
74+
}
75+
76+
export function oxfmtFileBatches(files, params = {}) {
77+
const platform = params.platform ?? process.platform;
78+
if (platform !== "win32") {
79+
return [files];
80+
}
81+
82+
const maxLength = params.maxWindowsCommandLineLength ?? WINDOWS_CMD_EXE_COMMAND_LINE_BUDGET;
83+
if (maxLength > WINDOWS_CMD_EXE_MAX_COMMAND_LINE_LENGTH) {
84+
throw new Error(
85+
`Windows oxfmt command line budget ${maxLength} exceeds cmd.exe limit ${WINDOWS_CMD_EXE_MAX_COMMAND_LINE_LENGTH}`,
86+
);
87+
}
88+
89+
const batches = [];
90+
let batch = [];
91+
for (const file of files) {
92+
const candidate = [...batch, file];
93+
const candidateLength = commandLineLength(
94+
createOxfmtSpawnSpec(oxfmtArgs(candidate, params), params),
95+
);
96+
if (candidateLength <= maxLength) {
97+
batch = candidate;
98+
continue;
99+
}
100+
101+
if (batch.length === 0) {
102+
throw new Error(
103+
`Windows oxfmt command line is too long for one docs file: ${file} (${candidateLength} characters)`,
104+
);
105+
}
106+
107+
batches.push(batch);
108+
const singleLength = commandLineLength(createOxfmtSpawnSpec(oxfmtArgs([file], params), params));
109+
if (singleLength > maxLength) {
110+
throw new Error(
111+
`Windows oxfmt command line is too long for one docs file: ${file} (${singleLength} characters)`,
112+
);
113+
}
114+
batch = [file];
115+
}
116+
117+
if (batch.length > 0) {
118+
batches.push(batch);
119+
}
120+
return batches;
121+
}
122+
123+
function runOxfmtBatch(files, params = {}) {
67124
const root = params.root ?? ROOT;
68125
const spawnSyncImpl = params.spawnSync ?? spawnSync;
69-
const spec = createOxfmtSpawnSpec(
70-
["--write", "--threads=1", "--config", params.config ?? OXFMT_CONFIG, ...files],
71-
params,
72-
);
126+
const spec = createOxfmtSpawnSpec(oxfmtArgs(files, params), params);
73127
const result = spawnSyncImpl(spec.command, spec.args, {
74128
cwd: root,
75129
encoding: "utf8",
@@ -82,6 +136,12 @@ export function runOxfmt(files, params = {}) {
82136
}
83137
}
84138

139+
export function runOxfmt(files, params = {}) {
140+
for (const batch of oxfmtFileBatches(files, params)) {
141+
runOxfmtBatch(batch, params);
142+
}
143+
}
144+
85145
function repairFiles(root, files) {
86146
const changed = [];
87147
for (const relativePath of files) {

test/scripts/format-docs.test.ts

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import path from "node:path";
22
import { describe, expect, it } from "vitest";
3-
import { createOxfmtSpawnSpec, docsFiles, runOxfmt } from "../../scripts/format-docs.mjs";
3+
import {
4+
createOxfmtSpawnSpec,
5+
docsFiles,
6+
oxfmtFileBatches,
7+
runOxfmt,
8+
} from "../../scripts/format-docs.mjs";
49

510
describe("format-docs", () => {
611
it("wraps the local oxfmt.cmd shim through cmd.exe on Windows", () => {
@@ -34,6 +39,67 @@ describe("format-docs", () => {
3439
});
3540
});
3641

42+
it("batches Windows docs files under the cmd.exe command line limit", () => {
43+
const files = Array.from(
44+
{ length: 24 },
45+
(_, index) =>
46+
`C:\\Users\\contributor\\AppData\\Local\\Temp\\openclaw-docs-format-test\\docs\\section-${index}\\long-file-name-${index}.mdx`,
47+
);
48+
const params = {
49+
comSpec: "C:\\Windows\\System32\\cmd.exe",
50+
config: "C:\\repo\\.oxfmtrc.jsonc",
51+
maxWindowsCommandLineLength: 1000,
52+
platform: "win32",
53+
root: "C:\\repo",
54+
};
55+
56+
const batches = oxfmtFileBatches(files, params);
57+
58+
expect(batches.length).toBeGreaterThan(1);
59+
expect(batches.flat()).toEqual(files);
60+
for (const batch of batches) {
61+
const spec = createOxfmtSpawnSpec(
62+
["--write", "--threads=1", "--config", params.config, ...batch],
63+
params,
64+
);
65+
expect([spec.command, ...spec.args].join(" ").length).toBeLessThanOrEqual(
66+
params.maxWindowsCommandLineLength,
67+
);
68+
}
69+
});
70+
71+
it("runs one oxfmt process per Windows batch", () => {
72+
const commands: string[] = [];
73+
74+
runOxfmt(
75+
Array.from(
76+
{ length: 10 },
77+
(_, index) =>
78+
`C:\\Users\\contributor\\AppData\\Local\\Temp\\openclaw-docs-format-test\\docs\\guide-${index}.mdx`,
79+
),
80+
{
81+
comSpec: "C:\\Windows\\System32\\cmd.exe",
82+
config: "C:\\repo\\.oxfmtrc.jsonc",
83+
maxWindowsCommandLineLength: 800,
84+
platform: "win32",
85+
root: "C:\\repo",
86+
spawnSync: (command: string, args: string[]) => {
87+
commands.push([command, ...args].join(" "));
88+
return {
89+
error: undefined,
90+
status: 0,
91+
signal: null,
92+
stderr: "",
93+
stdout: "",
94+
};
95+
},
96+
},
97+
);
98+
99+
expect(commands.length).toBeGreaterThan(1);
100+
expect(commands.every((command) => command.length <= 800)).toBe(true);
101+
});
102+
37103
it("reports oxfmt launch failures", () => {
38104
expect(() =>
39105
runOxfmt(["README.md"], {

0 commit comments

Comments
 (0)