From 43ab7ab811284f066df1924b86f82f3518b6445f Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Wed, 14 Mar 2018 09:16:37 -0700 Subject: [PATCH] metro-memory-fs: clean up createWriteStream() Reviewed By: rafeca Differential Revision: D7257022 fbshipit-source-id: 30598f2dd24a66bf07d75133ca10fb6b9082010a --- .../src/__tests__/index-test.js | 22 ++++++- packages/metro-memory-fs/src/index.js | 61 +++++++++++++------ 2 files changed, 63 insertions(+), 20 deletions(-) diff --git a/packages/metro-memory-fs/src/__tests__/index-test.js b/packages/metro-memory-fs/src/__tests__/index-test.js index be0a038b..cebaad22 100644 --- a/packages/metro-memory-fs/src/__tests__/index-test.js +++ b/packages/metro-memory-fs/src/__tests__/index-test.js @@ -60,7 +60,7 @@ it('can write then read a file as buffer', () => { }); describe('createWriteStream', () => { - it('can write a file', done => { + it('writes a file', done => { const st = fs.createWriteStream('/foo.txt'); let opened = false; let closed = false; @@ -76,7 +76,7 @@ describe('createWriteStream', () => { }); }); - it('can write a file, as buffer', done => { + it('writes a file, as buffer', done => { const st = fs.createWriteStream('/foo.txt'); let opened = false; let closed = false; @@ -92,7 +92,7 @@ describe('createWriteStream', () => { }); }); - it('can write a file, with a starting position', done => { + it('writes a file, with a starting position', done => { fs.writeFileSync('/foo.txt', 'test bar'); const st = fs.createWriteStream('/foo.txt', {start: 5, flags: 'r+'}); let opened = false; @@ -107,6 +107,22 @@ describe('createWriteStream', () => { done(); }); }); + + it('writes a file with a custom fd', done => { + const fd = fs.openSync('/bar.txt', 'w'); + const st = fs.createWriteStream('/foo.txt', {fd}); + let opened = false; + let closed = false; + st.on('open', () => (opened = true)); + st.on('close', () => (closed = true)); + st.write('beep boop'); + st.end(() => { + expect(opened).toBe(false); + expect(closed).toBe(true); + expect(fs.readFileSync('/bar.txt', 'utf8')).toEqual('beep boop'); + done(); + }); + }); }); describe('createReadStream', () => { diff --git a/packages/metro-memory-fs/src/index.js b/packages/metro-memory-fs/src/index.js index 939d890d..d78dad71 100644 --- a/packages/metro-memory-fs/src/index.js +++ b/packages/metro-memory-fs/src/index.js @@ -482,22 +482,9 @@ class MemoryFs { fd = this._open(pathStr(filePath), flags || 'w', mode); process.nextTick(() => (st: any).emit('open', fd)); } - if (start != null) { - this._write(fd, new Buffer(0), 0, 0, start); - } const ffd = fd; - const rst = new stream.Writable({ - write: (buffer, encoding, callback) => { - try { - this._write(ffd, buffer, 0, buffer.length); - (st: any).bytesWritten += buffer.length; - } catch (error) { - callback(error); - return; - } - callback(); - }, - }); + const ropt = {fd, writeSync: this._write.bind(this), filePath, start}; + const rst = new WriteFileStream(ropt); st = rst; if (autoClose !== false) { const doClose = () => { @@ -507,8 +494,6 @@ class MemoryFs { rst.on('finish', doClose); rst.on('error', doClose); } - (st: any).path = filePath; - (st: any).bytesWritten = 0; return st; }; @@ -811,6 +796,48 @@ class ReadFileSteam extends stream.Readable { } } +type WriteSync = ( + fd: number, + buffer: Buffer, + offset: number, + length: number, + position?: number, +) => number; + +class WriteFileStream extends stream.Writable { + bytesWritten: number; + path: string | Buffer; + _fd: number; + _writeSync: WriteSync; + + constructor(opts: { + fd: number, + filePath: string | Buffer, + writeSync: WriteSync, + start: ?number, + }) { + super(); + this.path = opts.filePath; + this.bytesWritten = 0; + this._fd = opts.fd; + this._writeSync = opts.writeSync; + if (opts.start != null) { + this._writeSync(opts.fd, new Buffer(0), 0, 0, opts.start); + } + } + + _write(buffer, encoding, callback) { + try { + const bytesWritten = this._writeSync(this._fd, buffer, 0, buffer.length); + this.bytesWritten += bytesWritten; + } catch (error) { + callback(error); + return; + } + callback(); + } +} + function checkPathLength(entNames, filePath) { if (entNames.length > 32) { throw makeError(