mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-12 22:09: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 {
|
||||
createTaskArgs,
|
||||
detectProvider,
|
||||
ensureDir,
|
||||
getConfiguredMaxWorkers,
|
||||
getConfiguredProviderRateLimits,
|
||||
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 () => {
|
||||
const root = await makeTempDir("baoyu-image-gen-extend-");
|
||||
const cwd = path.join(root, "project");
|
||||
|
||||
@@ -2,7 +2,7 @@ import path from "node:path";
|
||||
import process from "node:process";
|
||||
import { homedir } from "node:os";
|
||||
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 {
|
||||
BatchFile,
|
||||
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> {
|
||||
for (const { current, legacy } of getExtendConfigPathPairs(cwd, home)) {
|
||||
const [hasCurrent, hasLegacy] = await Promise.all([exists(current), exists(legacy)]);
|
||||
if (hasCurrent || !hasLegacy) continue;
|
||||
await mkdir(path.dirname(current), { recursive: true });
|
||||
await ensureDir(path.dirname(current));
|
||||
await rename(legacy, current);
|
||||
}
|
||||
}
|
||||
@@ -1049,7 +1063,7 @@ async function prepareBatchTasks(
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user