Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove: Option for Error on Missing File or Directory #785

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 7 additions & 2 deletions docs/remove.md
@@ -1,8 +1,13 @@
# remove(path[, callback])
# remove(path[, options][, callback])

Removes a file or directory. The directory can have contents. If the path does not exist, silently does nothing. Like `rm -rf`.
Removes a file or directory. The directory can have contents.

If `options.shoutMissing` is not set and the path does not exist, silently does nothing. Like `rm -rf`.

- `path` `<String>`
- `options` `<Object>`
- `shoutMissing` `<boolean>`: Throw an error if path does not exist, default is `false`.
- `maxBusyTries` `<number>`: Maximum number of attempts at removal if file or directory is busy or locked, default is `3`.
- `callback` `<Function>`

## Example:
Expand Down
8 changes: 8 additions & 0 deletions lib/remove/__tests__/remove-dir.test.js
Expand Up @@ -25,5 +25,13 @@ describe('remove / async / dir', () => {
done()
})
})
it('should throw an error if shoutMissing is set', done => {
const someDir = path.join(TEST_DIR, 'some-dir/')
assert.strictEqual(fs.existsSync(someDir), false)
fse.remove(someDir, { shoutMissing: true }, err => {
assert.strictEqual(err.code, 'ENOENT')
done()
})
})
})
})
16 changes: 16 additions & 0 deletions lib/remove/__tests__/remove.test.js
Expand Up @@ -120,5 +120,21 @@ describe('remove', () => {
done()
})
})

it('should shout while not deleting glob matches when file doesn’t exist and shoutMissing is set', done => {
const nonexistentFile = path.join(TEST_DIR, 'file?')

const wrongFile = path.join(TEST_DIR, 'file1')
fs.writeFileSync(wrongFile, 'yo')

assert(!fs.existsSync(nonexistentFile))
assert(fs.existsSync(wrongFile))
fse.remove(nonexistentFile, { shoutMissing: true }, err => {
assert.strictEqual(err.code, 'ENOENT')
assert(!fs.existsSync(nonexistentFile))
assert(fs.existsSync(wrongFile))
done()
})
})
})
})
27 changes: 20 additions & 7 deletions lib/remove/rimraf.js
Expand Up @@ -22,6 +22,7 @@ function defaults (options) {
})

options.maxBusyTries = options.maxBusyTries || 3
options.shoutMissing = options.shoutMissing || false
}

function rimraf (p, options, cb) {
Expand Down Expand Up @@ -50,8 +51,12 @@ function rimraf (p, options, cb) {
return setTimeout(() => rimraf_(p, options, CB), time)
}

// already gone
if (er.code === 'ENOENT') er = null
if (er.code === 'ENOENT') {
// was never there
if (busyTries === 0) er = options.shoutMissing ? er : null
// already gone
else er = null
}
}

cb(er)
Expand All @@ -78,7 +83,7 @@ function rimraf_ (p, options, cb) {
// so we have to lstat here and make sure it's not a dir.
options.lstat(p, (er, st) => {
if (er && er.code === 'ENOENT') {
return cb(null)
return options.shoutMissing ? cb(er) : cb(null) // just return cb(er); cb checks ENOENT
}

// Windows can EPERM on stat. Life is suffering.
Expand All @@ -92,8 +97,8 @@ function rimraf_ (p, options, cb) {

options.unlink(p, er => {
if (er) {
if (er.code === 'ENOENT') {
return cb(null)
if (er.code === 'ENOENT') { // this "if" can be removed; cb checks ENOENT
return options.shoutMissing ? cb(er) : cb(null)
}
if (er.code === 'EPERM') {
return (isWindows)
Expand All @@ -119,11 +124,19 @@ function fixWinEPERM (p, options, er, cb) {

options.chmod(p, 0o666, er2 => {
if (er2) {
cb(er2.code === 'ENOENT' ? null : er)
if (er2.code === 'ENOENT') { // replace with cb(er2.code === 'ENOENT' ? er2 : er)
options.shoutMissing ? cb(er2) : cb(null)
} else {
cb(er)
}
} else {
options.stat(p, (er3, stats) => {
if (er3) {
cb(er3.code === 'ENOENT' ? null : er)
if (er3.code === 'ENOENT') { // replace with cb(er3.code === 'ENOENT' ? er3 : er)
options.shoutMissing ? cb(er3) : cb(null)
} else {
cb(er)
}
} else if (stats.isDirectory()) {
rmdir(p, options, er, cb)
} else {
Expand Down