jprichardson / node-fs-extra

Node.js: extra methods for the fs object like copy(), remove(), mkdirs()
MIT License
9.44k stars 776 forks source link

copy errors with EEXIST #957

Closed joelanman closed 2 years ago

joelanman commented 2 years ago

Apologies if I've got any usage or expectations wrong here, first time using the library.

I'm using this code:

    fs.copy('app/assets', 'public', { filter: filterFunc }, err => {
        if (err) return console.error(err)
    })

While this asynchronous code runs, I'm also running another function that makes and puts things in the public folder.

I get this error:

[Error: EEXIST: file already exists, mkdir 'public'] {
  errno: -17,
  code: 'EEXIST',
  syscall: 'mkdir',
  path: 'public'
}

and none of the copy happens.

If I mkdir public before running copy, everything is fine, but I wouldn't think I'd need to do that

RyanZim commented 2 years ago

The confusion here is the way the destination path works. You're copying a directory, app/assets, and you specified the destination as public. fs-extra assumes you want to put the contents of app/assets in public. I'm guessing you actually want to copy assets to public, so you end up with public/assets. For that, you need to do fs.copy('app/assets', 'public/assets', ..)

joelanman commented 2 years ago

no, I want to put the contents of app/assets in public

RyanZim commented 2 years ago

In that case, you either have to ensure this copy is running first, before other things output to public, or else you have to do fs.readdir on src/assets, and copy each item to public.

joelanman commented 2 years ago

that's a bit confusing given the documentation says it will overwrite by default, but it isn't, its throwing an EEXIST error

RyanZim commented 2 years ago

OK, I must admit I don't fully understand why that particular error is being thrown. However, my point about usage still stands. If it did overwrite, it would overwrite the other things you're putting in public at the same time.

joelanman commented 2 years ago

In my case it wouldn't as I'm putting different things there. This function is copying assets like images, the other is rendering sass to css, both into the public folder

RyanZim commented 2 years ago

fs-extra as you're using it is not copying items into the public folder, it is copying the assets folder to public, attempting to overwrite any existing public folder.

targeral commented 1 year ago

I also had the same problem, and the reproduction scenario on my side was like this:

This is my script:

import path from 'path';
import fs from 'fs-extra';
import pMap from 'p-map';
const __dirname = process.cwd();

// [p-map](https://github.com/sindresorhus/p-map): "Map over promises concurrently"
pMap(Array.from({length: 2}), async () => {
    // await fs.ensureDir(path.join(__dirname, './playground/dist'));
    await fs.copy(path.join(__dirname, './playground/src'), path.join(__dirname, './playground/dist')) 
})

Project dependencies:

"dependencies": {
    "fs-extra": "^11.1.1",
    "p-map": "^6.0.0"
  }

The directory structure looks like this:

- playground/
   - src/index.js
node:internal/process/promises:279
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[Error: EEXIST: file already exists, mkdir '/Users/bytedance/demo/try-npm-librarys/playground/dist'] {
  errno: -17,
  code: 'EEXIST',
  syscall: 'mkdir',
  path: '/Users/bytedance/demo/try-npm-librarys/playground/dist'
}