mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-13 22:29:48 +08:00
Merge pull request #179 from sandypoli-boop/fix/windows-bun-mkdir-eexist
fix(baoyu-image-gen): tolerate Bun-on-Windows EEXIST from mkdir(recursive)
This commit is contained in:
@@ -8,6 +8,7 @@ import type { CliArgs, ExtendConfig } from "./types.ts";
|
|||||||
import {
|
import {
|
||||||
createTaskArgs,
|
createTaskArgs,
|
||||||
detectProvider,
|
detectProvider,
|
||||||
|
ensureDir,
|
||||||
getConfiguredMaxWorkers,
|
getConfiguredMaxWorkers,
|
||||||
getConfiguredProviderRateLimits,
|
getConfiguredProviderRateLimits,
|
||||||
getWorkerCount,
|
getWorkerCount,
|
||||||
@@ -201,6 +202,26 @@ batch:
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("ensureDir creates nested dirs, is idempotent on an existing dir, and rethrows for a non-directory", async (t: TestContext) => {
|
||||||
|
const root = await makeTempDir("ensure-dir-");
|
||||||
|
t.after(() => fs.rm(root, { recursive: true, force: true }));
|
||||||
|
|
||||||
|
const nested = path.join(root, "a", "b", "c");
|
||||||
|
await ensureDir(nested);
|
||||||
|
assert.equal((await fs.stat(nested)).isDirectory(), true);
|
||||||
|
|
||||||
|
// Idempotent: a second call on an existing directory must not throw. This is the
|
||||||
|
// Bun-on-Windows regression the helper guards against (Bun wrongly throws EEXIST
|
||||||
|
// for mkdir(existingDir, { recursive: true })).
|
||||||
|
await ensureDir(nested);
|
||||||
|
|
||||||
|
// Rethrows when the path exists but is a file rather than a directory, so a real
|
||||||
|
// EEXIST against a non-directory is not silently swallowed.
|
||||||
|
const filePath = path.join(root, "not-a-dir");
|
||||||
|
await fs.writeFile(filePath, "x");
|
||||||
|
await assert.rejects(() => ensureDir(filePath));
|
||||||
|
});
|
||||||
|
|
||||||
test("loadExtendConfig renames legacy EXTEND.md when the new path is missing", async () => {
|
test("loadExtendConfig renames legacy EXTEND.md when the new path is missing", async () => {
|
||||||
const root = await makeTempDir("baoyu-image-gen-extend-");
|
const root = await makeTempDir("baoyu-image-gen-extend-");
|
||||||
const cwd = path.join(root, "project");
|
const cwd = path.join(root, "project");
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import path from "node:path";
|
|||||||
import process from "node:process";
|
import process from "node:process";
|
||||||
import { homedir } from "node:os";
|
import { homedir } from "node:os";
|
||||||
import { fileURLToPath } from "node:url";
|
import { fileURLToPath } from "node:url";
|
||||||
import { access, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
import { access, mkdir, readFile, rename, stat, writeFile } from "node:fs/promises";
|
||||||
import type {
|
import type {
|
||||||
BatchFile,
|
BatchFile,
|
||||||
BatchTaskInput,
|
BatchTaskInput,
|
||||||
@@ -563,11 +563,25 @@ async function exists(filePath: string): Promise<boolean> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function ensureDir(dir: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
await mkdir(dir, { recursive: true });
|
||||||
|
} catch (err) {
|
||||||
|
// Bun on Windows incorrectly throws EEXIST for mkdir(dir, { recursive: true })
|
||||||
|
// when the directory already exists, contradicting Node's documented contract
|
||||||
|
// (mkdir with recursive: true resolves silently for an existing directory).
|
||||||
|
// Tolerate EEXIST only when the path really is a directory; rethrow otherwise
|
||||||
|
// (e.g. EEXIST raised because the path points at an existing file).
|
||||||
|
if ((err as { code?: string }).code !== "EEXIST") throw err;
|
||||||
|
if (!(await stat(dir)).isDirectory()) throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function migrateLegacyExtendConfig(cwd: string, home: string): Promise<void> {
|
async function migrateLegacyExtendConfig(cwd: string, home: string): Promise<void> {
|
||||||
for (const { current, legacy } of getExtendConfigPathPairs(cwd, home)) {
|
for (const { current, legacy } of getExtendConfigPathPairs(cwd, home)) {
|
||||||
const [hasCurrent, hasLegacy] = await Promise.all([exists(current), exists(legacy)]);
|
const [hasCurrent, hasLegacy] = await Promise.all([exists(current), exists(legacy)]);
|
||||||
if (hasCurrent || !hasLegacy) continue;
|
if (hasCurrent || !hasLegacy) continue;
|
||||||
await mkdir(path.dirname(current), { recursive: true });
|
await ensureDir(path.dirname(current));
|
||||||
await rename(legacy, current);
|
await rename(legacy, current);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1049,7 +1063,7 @@ async function prepareBatchTasks(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function writeImage(outputPath: string, imageData: Uint8Array): Promise<void> {
|
async function writeImage(outputPath: string, imageData: Uint8Array): Promise<void> {
|
||||||
await mkdir(path.dirname(outputPath), { recursive: true });
|
await ensureDir(path.dirname(outputPath));
|
||||||
await writeFile(outputPath, imageData);
|
await writeFile(outputPath, imageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user