From cb485f49285f7bcf857d02e343b4823adaa9b350 Mon Sep 17 00:00:00 2001 From: Alexander Vega Date: Sun, 20 Nov 2022 20:06:32 +0000 Subject: [PATCH 1/2] copyFilesSync from one file system to another --- src/__tests__/union.test.ts | 18 ++++++++++++++++++ src/fs.ts | 1 + src/union.ts | 31 +++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/src/__tests__/union.test.ts b/src/__tests__/union.test.ts index dd8efa84..06f3c265 100644 --- a/src/__tests__/union.test.ts +++ b/src/__tests__/union.test.ts @@ -183,6 +183,24 @@ describe('union', () => { expect(() => ufs.readdirSync('/bar')).toThrow(); }); }); + + describe('copyFileSync()', () => { + it('can copy from one filesystem to another', async () => { + const vol1 = Volume.fromJSON({ + '/foo/bar': 'bar', + }); + const vol2 = Volume.fromJSON({ + '/bar/baz': 'baz', + }); + + const ufs = new Union(); + ufs.use(vol1 as any).use(vol2 as any); + + ufs.copyFileSync('/foo/bar', '/bar/barCopy'); + expect(vol2.readFileSync('/bar/barCopy').toString()).toEqual('bar'); + expect(vol1.existsSync('/bar/barCopy')).toBeFalsy(); + }); + }); }); describe('async methods', () => { it('Basic one file system', done => { diff --git a/src/fs.ts b/src/fs.ts index efd71f3f..62e0c390 100644 --- a/src/fs.ts +++ b/src/fs.ts @@ -32,6 +32,7 @@ type FSMethods = | 'readFileSync' | 'writeFileSync' | 'appendFileSync' + | 'copyFileSync' | 'existsSync' | 'accessSync' | 'createReadStream' diff --git a/src/union.ts b/src/union.ts index 94183001..ab730acc 100644 --- a/src/union.ts +++ b/src/union.ts @@ -1,6 +1,8 @@ import { FSWatcher, Dirent } from 'fs'; import { IFS } from './fs'; import { Readable, Writable } from 'stream'; +import { dirname } from 'path'; +import { ENOENT } from 'constants'; const { fsAsyncMethods, fsSyncMethods } = require('fs-monkey/lib/util/lists'); export interface IUnionFsError extends Error { @@ -13,6 +15,7 @@ const SPECIAL_METHODS = new Set([ 'existsSync', 'readdir', 'readdirSync', + 'copyFileSync', 'createReadStream', 'createWriteStream', 'watch', @@ -245,6 +248,34 @@ export class Union { return this.sortedArrayFromReaddirResult(result); }; + public copyFileSync(src: string, dest: string, flags?: number) { + const destDir = dirname(dest); + + // CASE 1: dest is a filename. Don't treat, standard copy (opinionated) + if (destDir.length == 0) { + return this.syncMethod('copyFileSync', [src, dest, flags]); + } + + // CASE 2: src doesn't exist in any fs. + const srcFS = this.fss.find(fs => fs.existsSync(src)); + if (!srcFS) { + const error = new Error(`no such source file: ${src}`) as NodeJS.ErrnoException; + error.errno = ENOENT; + throw error; + } + + // CASE 3: dest dir does not exist or is in the same fs. + // To protect ourselves, simply launch standard copy, whatever the policies + // about destination dir doesn't exist. + const destFS = this.fss.find(fs => fs.existsSync(destDir)); + if (!destFS || srcFS == destFS) { + return this.syncMethod('copyFileSync', [src, dest, flags]); + } + + // CASE 4: different FS. Workaround: read src, write dest. + destFS.writeFileSync(dest, srcFS.readFileSync(src)); + } + public readdirPromise = async (...args): Promise> => { let lastError: IUnionFsError | null = null; let result = new Map(); From 52b6e5d23fb8db5a2880078bb2e652208161abc5 Mon Sep 17 00:00:00 2001 From: Alexander Vega Date: Mon, 21 Nov 2022 16:29:39 +0000 Subject: [PATCH 2/2] Added try-catch to copyFileSync fs finding --- src/union.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/union.ts b/src/union.ts index ab730acc..32d57e16 100644 --- a/src/union.ts +++ b/src/union.ts @@ -257,7 +257,11 @@ export class Union { } // CASE 2: src doesn't exist in any fs. - const srcFS = this.fss.find(fs => fs.existsSync(src)); + const srcFS = this.fss.find(fs => { + try { return fs.existsSync(src) } + catch (error) { return false }; + }) + if (!srcFS) { const error = new Error(`no such source file: ${src}`) as NodeJS.ErrnoException; error.errno = ENOENT; @@ -267,7 +271,11 @@ export class Union { // CASE 3: dest dir does not exist or is in the same fs. // To protect ourselves, simply launch standard copy, whatever the policies // about destination dir doesn't exist. - const destFS = this.fss.find(fs => fs.existsSync(destDir)); + const destFS = this.fss.find(fs => { + try { return fs.existsSync(destDir) } + catch (error) { return false }; + }); + if (!destFS || srcFS == destFS) { return this.syncMethod('copyFileSync', [src, dest, flags]); }