Skip to content

Commit

Permalink
fix: createWriteStream failing to create new files in directories (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dy-dx authored Mar 15, 2024
1 parent 4b61fa8 commit cc52c7f
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 2 deletions.
28 changes: 28 additions & 0 deletions src/__tests__/union.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,34 @@ describe('union', () => {

ufs.unlinkSync(realFile);
});

describe('createWriteStream', () => {
it('creates a new file when only parent directory exists', async () => {
const vol = Volume.fromJSON({ '/foo': null });
const vol2 = Volume.fromJSON({ '/bar': null });
const ufs = new Union();
ufs.use(vol as any).use(vol2 as any);

const stream = ufs.createWriteStream('/bar/file');
stream.end('content');
await new Promise(resolve => stream.once('close', resolve));

expect(vol2.readFileSync('/bar/file', 'utf8')).toBe('content');
});

it('writes to an existing file even if parent dir exists on an earlier fss', async () => {
const vol = Volume.fromJSON({ '/bar': null });
const vol2 = Volume.fromJSON({ '/bar/file': '' });
const ufs = new Union();
ufs.use(vol as any).use(vol2 as any);

const stream = ufs.createWriteStream('/bar/file');
stream.end('content');
await new Promise(resolve => stream.once('close', resolve));

expect(vol2.readFileSync('/bar/file', 'utf8')).toBe('content');
});
});
});
});
});
24 changes: 22 additions & 2 deletions src/union.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FSWatcher, Dirent } from 'fs';
import { IFS } from './fs';
import { dirname } from 'path';
import { Readable, Writable } from 'stream';
const { fsAsyncMethods, fsSyncMethods } = require('fs-monkey/lib/util/lists');

Expand Down Expand Up @@ -314,12 +315,31 @@ export class Union {

public createWriteStream = (path: string) => {
let lastError = null;
const fssWithFilePath: IFS[] = [];
const fssWithParentDir: IFS[] = [];

for (const fs of this.fss) {
try {
if (!fs.createWriteStream) throw Error(`Method not supported: "createWriteStream"`);

fs.statSync(path); //we simply stat first to exit early for mocked fs'es
//TODO which filesystem to write to?
//we simply stat first to exit early for mocked fs'es
if (!fs.statSync(dirname(path)).isDirectory()) {
throw new Error(`path "${dirname(path)}" is not a directory`);
}
if (fs.existsSync(path)) {
fssWithFilePath.push(fs);
} else {
fssWithParentDir.push(fs);
}
} catch (err) {
lastError = err;
}
}

// First try writing to filesystems where the file path exists.
// Then try writing to filesystems where the parent directory exists.
for (const fs of [...fssWithFilePath, ...fssWithParentDir]) {
try {
const stream = fs.createWriteStream(path);
if (!stream) {
throw new Error('no valid stream');
Expand Down

0 comments on commit cc52c7f

Please sign in to comment.