mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 14:06:50 +01:00
E4: generators tolerate Bun's spurious EEXIST on Windows (#2329)
Bun on Windows throws EEXIST from a recursive mkdir of an existing directory, so gen:skill-docs and the llms.txt writer crashed once a second file landed in a directory. Both now use lib/fs-utils' mkdirpSync (ported from PR #2329 onto the existing helper instead of a new scripts/fs-utils.ts). Co-authored-by: Vaughan <vaughan@cairnsitguy.com.au>
This commit is contained in:
1 parent
9eda423a85
commit
a1969d9287
3 files changed
+42
-2
No files matched your search
@@ -19,6 +19,7 @@
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { mkdirpSync } from '../lib/fs-utils';
|
||||
import { discoverTemplates } from './discover-skills';
|
||||
import { COMMAND_DESCRIPTIONS as BROWSE_COMMANDS } from '../browse/src/commands';
|
||||
|
||||
@@ -224,7 +225,7 @@ export async function generateLlmsTxt(opts: GenerateOptions = {}): Promise<Gener
|
||||
export async function writeLlmsTxt(opts: GenerateOptions & { outputPath?: string } = {}): Promise<GenerateResult> {
|
||||
const result = await generateLlmsTxt(opts);
|
||||
const outputPath = opts.outputPath ?? OUTPUT;
|
||||
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
||||
mkdirpSync(path.dirname(outputPath));
|
||||
fs.writeFileSync(outputPath, result.content, { encoding: 'utf-8' });
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import type { HostConfig } from './host-config';
|
||||
const ROOT = path.resolve(import.meta.dir, '..');
|
||||
import { ALL_MODEL_NAMES, resolveModel, type Model } from './models';
|
||||
import { resolveStateRoot } from '../lib/state-root';
|
||||
import { mkdirpSync } from '../lib/fs-utils';
|
||||
|
||||
type HostArg = Host | 'all';
|
||||
|
||||
@@ -967,7 +968,7 @@ export async function runGeneration(settings: GenerationOptions = {}): Promise<G
|
||||
log(`FRESH: ${relativePath}`);
|
||||
}
|
||||
} else {
|
||||
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
|
||||
mkdirpSync(path.dirname(outputPath));
|
||||
fs.writeFileSync(outputPath, content);
|
||||
log(`GENERATED: ${relativePath}`);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* #2329: Bun on Windows throws EEXIST from mkdirSync(dir, { recursive: true })
|
||||
* when dir already exists, so a second `gen:skill-docs` (or llms.txt write)
|
||||
* crashed. Both generators now use lib/fs-utils' mkdirpSync. Emulated on every
|
||||
* platform with the same --preload fixture as test/fs-utils.test.ts (#2635).
|
||||
*/
|
||||
import { afterAll, describe, expect, test } from 'bun:test';
|
||||
import { spawnSync } from 'child_process';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
|
||||
const ROOT = path.resolve(import.meta.dir, '..');
|
||||
const PRELOAD = path.join(import.meta.dir, 'helpers', 'emulate-bun-windows-eexist.ts');
|
||||
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-gen-eexist-'));
|
||||
afterAll(() => fs.rmSync(tmp, { recursive: true, force: true }));
|
||||
|
||||
const bun = (...args: string[]) => spawnSync(process.execPath, ['--preload', PRELOAD, ...args], { cwd: ROOT, encoding: 'utf8', timeout: 120_000 });
|
||||
|
||||
describe('#2329: generators tolerate existing output directories under Windows EEXIST semantics', () => {
|
||||
test('gen-skill-docs renders twice into the same out-dir', () => {
|
||||
const out = path.join(tmp, 'render');
|
||||
for (let run = 1; run <= 2; run++) {
|
||||
const r = bun('scripts/gen-skill-docs.ts', '--host', 'codex', '--out-dir', out);
|
||||
expect(`run ${run}: exit ${r.status}`, r.stderr).toBe(`run ${run}: exit 0`);
|
||||
expect(r.stderr).not.toContain('EEXIST');
|
||||
}
|
||||
expect(fs.existsSync(path.join(out, '.agents', 'skills', 'gstack-review', 'SKILL.md'))).toBe(true);
|
||||
});
|
||||
|
||||
test('writeLlmsTxt writes into an existing directory', () => {
|
||||
const target = path.join(tmp, 'llms', 'llms.txt');
|
||||
fs.mkdirSync(path.dirname(target), { recursive: true });
|
||||
const r = bun('-e', `const { writeLlmsTxt } = await import(${JSON.stringify(path.join(ROOT, 'scripts/gen-llms-txt.ts'))}); await writeLlmsTxt({ outputPath: ${JSON.stringify(target)} });`);
|
||||
expect(r.status, r.stderr).toBe(0);
|
||||
expect(fs.readFileSync(target, 'utf8')).toContain('gstack');
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user