mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +01:00
fs: move rmdir recursive option to end-of-life
Has been runtime deprecated for ~ 5 years now. It's time. PR-URL: https://github.com/nodejs/node/pull/58616 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Dario Piotrowicz <dario.piotrowicz@gmail.com> Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: LiviaMedeiros <livia@cirno.name> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
b04c4a44a5
commit
eec0302088
|
|
@ -3057,6 +3057,9 @@ The [`crypto.Certificate()` constructor][] is deprecated. Use
|
|||
|
||||
<!-- YAML
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/58616
|
||||
description: End-of-Life.
|
||||
- version: v16.0.0
|
||||
pr-url: https://github.com/nodejs/node/pull/37302
|
||||
description: Runtime deprecation.
|
||||
|
|
@ -3068,10 +3071,10 @@ changes:
|
|||
description: Documentation-only deprecation.
|
||||
-->
|
||||
|
||||
Type: Runtime
|
||||
Type: End-of-Life
|
||||
|
||||
In future versions of Node.js, `recursive` option will be ignored for
|
||||
`fs.rmdir`, `fs.rmdirSync`, and `fs.promises.rmdir`.
|
||||
The `fs.rmdir`, `fs.rmdirSync`, and `fs.promises.rmdir` methods used
|
||||
to support a `recursive` option. That option has been removed.
|
||||
|
||||
Use `fs.rm(path, { recursive: true, force: true })`,
|
||||
`fs.rmSync(path, { recursive: true, force: true })` or
|
||||
|
|
|
|||
|
|
@ -1589,6 +1589,9 @@ Renames `oldPath` to `newPath`.
|
|||
<!-- YAML
|
||||
added: v10.0.0
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/58616
|
||||
description: Remove `recursive` option.
|
||||
- version: v16.0.0
|
||||
pr-url: https://github.com/nodejs/node/pull/37216
|
||||
description: "Using `fsPromises.rmdir(path, { recursive: true })` on a `path`
|
||||
|
|
@ -1622,18 +1625,10 @@ changes:
|
|||
-->
|
||||
|
||||
* `path` {string|Buffer|URL}
|
||||
* `options` {Object}
|
||||
* `maxRetries` {integer} If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or
|
||||
`EPERM` error is encountered, Node.js retries the operation with a linear
|
||||
backoff wait of `retryDelay` milliseconds longer on each try. This option
|
||||
represents the number of retries. This option is ignored if the `recursive`
|
||||
option is not `true`. **Default:** `0`.
|
||||
* `recursive` {boolean} If `true`, perform a recursive directory removal. In
|
||||
recursive mode, operations are retried on failure. **Default:** `false`.
|
||||
**Deprecated.**
|
||||
* `retryDelay` {integer} The amount of time in milliseconds to wait between
|
||||
retries. This option is ignored if the `recursive` option is not `true`.
|
||||
**Default:** `100`.
|
||||
* `options` {Object} There are currently no options exposed. There used to
|
||||
be options for `recursive`, `maxBusyTries`, and `emfileWait` but they were
|
||||
deprecated and removed. The `options` argument is still accepted for
|
||||
backwards compatibility but it is not used.
|
||||
* Returns: {Promise} Fulfills with `undefined` upon success.
|
||||
|
||||
Removes the directory identified by `path`.
|
||||
|
|
@ -4255,6 +4250,9 @@ rename('oldFile.txt', 'newFile.txt', (err) => {
|
|||
<!-- YAML
|
||||
added: v0.0.2
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/58616
|
||||
description: Remove `recursive` option.
|
||||
- version: v18.0.0
|
||||
pr-url: https://github.com/nodejs/node/pull/41678
|
||||
description: Passing an invalid callback to the `callback` argument
|
||||
|
|
@ -4305,18 +4303,10 @@ changes:
|
|||
-->
|
||||
|
||||
* `path` {string|Buffer|URL}
|
||||
* `options` {Object}
|
||||
* `maxRetries` {integer} If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or
|
||||
`EPERM` error is encountered, Node.js retries the operation with a linear
|
||||
backoff wait of `retryDelay` milliseconds longer on each try. This option
|
||||
represents the number of retries. This option is ignored if the `recursive`
|
||||
option is not `true`. **Default:** `0`.
|
||||
* `recursive` {boolean} If `true`, perform a recursive directory removal. In
|
||||
recursive mode, operations are retried on failure. **Default:** `false`.
|
||||
**Deprecated.**
|
||||
* `retryDelay` {integer} The amount of time in milliseconds to wait between
|
||||
retries. This option is ignored if the `recursive` option is not `true`.
|
||||
**Default:** `100`.
|
||||
* `options` {Object} There are currently no options exposed. There used to
|
||||
be options for `recursive`, `maxBusyTries`, and `emfileWait` but they were
|
||||
deprecated and removed. The `options` argument is still accepted for
|
||||
backwards compatibility but it is not used.
|
||||
* `callback` {Function}
|
||||
* `err` {Error}
|
||||
|
||||
|
|
@ -6234,6 +6224,9 @@ See the POSIX rename(2) documentation for more details.
|
|||
<!-- YAML
|
||||
added: v0.1.21
|
||||
changes:
|
||||
- version: REPLACEME
|
||||
pr-url: https://github.com/nodejs/node/pull/58616
|
||||
description: Remove `recursive` option.
|
||||
- version: v16.0.0
|
||||
pr-url: https://github.com/nodejs/node/pull/37216
|
||||
description: "Using `fs.rmdirSync(path, { recursive: true })` on a `path`
|
||||
|
|
@ -6271,18 +6264,10 @@ changes:
|
|||
-->
|
||||
|
||||
* `path` {string|Buffer|URL}
|
||||
* `options` {Object}
|
||||
* `maxRetries` {integer} If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or
|
||||
`EPERM` error is encountered, Node.js retries the operation with a linear
|
||||
backoff wait of `retryDelay` milliseconds longer on each try. This option
|
||||
represents the number of retries. This option is ignored if the `recursive`
|
||||
option is not `true`. **Default:** `0`.
|
||||
* `recursive` {boolean} If `true`, perform a recursive directory removal. In
|
||||
recursive mode, operations are retried on failure. **Default:** `false`.
|
||||
**Deprecated.**
|
||||
* `retryDelay` {integer} The amount of time in milliseconds to wait between
|
||||
retries. This option is ignored if the `recursive` option is not `true`.
|
||||
**Default:** `100`.
|
||||
* `options` {Object} There are currently no options exposed. There used to
|
||||
be options for `recursive`, `maxBusyTries`, and `emfileWait` but they were
|
||||
deprecated and removed. The `options` argument is still accepted for
|
||||
backwards compatibility but it is not used.
|
||||
|
||||
Synchronous rmdir(2). Returns `undefined`.
|
||||
|
||||
|
|
|
|||
62
lib/fs.js
62
lib/fs.js
|
|
@ -102,7 +102,6 @@ const {
|
|||
},
|
||||
copyObject,
|
||||
Dirent,
|
||||
emitRecursiveRmdirWarning,
|
||||
getDirent,
|
||||
getDirents,
|
||||
getOptions,
|
||||
|
|
@ -1109,11 +1108,7 @@ function lazyLoadRimraf() {
|
|||
/**
|
||||
* Asynchronously removes a directory.
|
||||
* @param {string | Buffer | URL} path
|
||||
* @param {{
|
||||
* maxRetries?: number;
|
||||
* recursive?: boolean;
|
||||
* retryDelay?: number;
|
||||
* }} [options]
|
||||
* @param {{}} [options]
|
||||
* @param {(err?: Error) => any} callback
|
||||
* @returns {void}
|
||||
*/
|
||||
|
|
@ -1123,60 +1118,45 @@ function rmdir(path, options, callback) {
|
|||
options = undefined;
|
||||
}
|
||||
|
||||
if (options?.recursive !== undefined) {
|
||||
// This API previously accepted a `recursive` option that was deprecated
|
||||
// and removed. However, in order to make the change more visible, we
|
||||
// opted to throw an error if recursive is specified rather than removing it
|
||||
// entirely.
|
||||
throw new ERR_INVALID_ARG_VALUE(
|
||||
'options.recursive',
|
||||
options.recursive,
|
||||
'is no longer supported',
|
||||
);
|
||||
}
|
||||
|
||||
callback = makeCallback(callback);
|
||||
path = getValidatedPath(path);
|
||||
|
||||
if (options?.recursive) {
|
||||
emitRecursiveRmdirWarning();
|
||||
validateRmOptions(
|
||||
path,
|
||||
{ ...options, force: false },
|
||||
true,
|
||||
(err, options) => {
|
||||
if (err === false) {
|
||||
const req = new FSReqCallback();
|
||||
req.oncomplete = callback;
|
||||
binding.rmdir(path, req);
|
||||
return;
|
||||
}
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
lazyLoadRimraf();
|
||||
rimraf(path, options, callback);
|
||||
});
|
||||
} else {
|
||||
validateRmdirOptions(options);
|
||||
const req = new FSReqCallback();
|
||||
req.oncomplete = callback;
|
||||
binding.rmdir(path, req);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously removes a directory.
|
||||
* @param {string | Buffer | URL} path
|
||||
* @param {{
|
||||
* maxRetries?: number;
|
||||
* recursive?: boolean;
|
||||
* retryDelay?: number;
|
||||
* }} [options]
|
||||
* @param {{}} [options]
|
||||
* @returns {void}
|
||||
*/
|
||||
function rmdirSync(path, options) {
|
||||
path = getValidatedPath(path);
|
||||
|
||||
if (options?.recursive) {
|
||||
emitRecursiveRmdirWarning();
|
||||
options = validateRmOptionsSync(path, { ...options, force: false }, true);
|
||||
if (options !== false) {
|
||||
return binding.rmSync(path, options.maxRetries, options.recursive, options.retryDelay);
|
||||
}
|
||||
} else {
|
||||
validateRmdirOptions(options);
|
||||
if (options?.recursive !== undefined) {
|
||||
throw new ERR_INVALID_ARG_VALUE(
|
||||
'options.recursive',
|
||||
options.recursive,
|
||||
'is no longer supported',
|
||||
);
|
||||
}
|
||||
|
||||
validateRmdirOptions(options);
|
||||
binding.rmdir(path);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ const {
|
|||
kWriteFileMaxChunkSize,
|
||||
},
|
||||
copyObject,
|
||||
emitRecursiveRmdirWarning,
|
||||
getDirents,
|
||||
getOptions,
|
||||
getStatFsFromBinding,
|
||||
|
|
@ -812,16 +811,17 @@ async function rm(path, options) {
|
|||
|
||||
async function rmdir(path, options) {
|
||||
path = getValidatedPath(path);
|
||||
options = validateRmdirOptions(options);
|
||||
|
||||
if (options.recursive) {
|
||||
emitRecursiveRmdirWarning();
|
||||
const stats = await stat(path);
|
||||
if (stats.isDirectory()) {
|
||||
return lazyRimRaf()(path, options);
|
||||
}
|
||||
if (options?.recursive !== undefined) {
|
||||
throw new ERR_INVALID_ARG_VALUE(
|
||||
'options.recursive',
|
||||
options.recursive,
|
||||
'is no longer supported',
|
||||
);
|
||||
}
|
||||
|
||||
options = validateRmdirOptions(options);
|
||||
|
||||
return await PromisePrototypeThen(
|
||||
binding.rmdir(path, kUsePromises),
|
||||
undefined,
|
||||
|
|
|
|||
|
|
@ -778,12 +778,6 @@ const defaultRmOptions = {
|
|||
maxRetries: 0,
|
||||
};
|
||||
|
||||
const defaultRmdirOptions = {
|
||||
retryDelay: 100,
|
||||
maxRetries: 0,
|
||||
recursive: false,
|
||||
};
|
||||
|
||||
const validateCpOptions = hideStackFrames((options) => {
|
||||
if (options === undefined)
|
||||
return { ...defaultCpOptions };
|
||||
|
|
@ -807,7 +801,10 @@ const validateCpOptions = hideStackFrames((options) => {
|
|||
|
||||
const validateRmOptions = hideStackFrames((path, options, expectDir, cb) => {
|
||||
options = validateRmdirOptions(options, defaultRmOptions);
|
||||
validateBoolean(options.force, 'options.force');
|
||||
validateBoolean.withoutStackTrace(options.force, 'options.force');
|
||||
validateBoolean.withoutStackTrace(options.recursive, 'options.recursive');
|
||||
validateInt32.withoutStackTrace(options.retryDelay, 'options.retryDelay', 0);
|
||||
validateUint32.withoutStackTrace(options.maxRetries, 'options.maxRetries');
|
||||
|
||||
lazyLoadFs().lstat(path, (err, stats) => {
|
||||
if (err) {
|
||||
|
|
@ -839,6 +836,10 @@ const validateRmOptions = hideStackFrames((path, options, expectDir, cb) => {
|
|||
const validateRmOptionsSync = hideStackFrames((path, options, expectDir) => {
|
||||
options = validateRmdirOptions.withoutStackTrace(options, defaultRmOptions);
|
||||
validateBoolean.withoutStackTrace(options.force, 'options.force');
|
||||
validateBoolean.withoutStackTrace(options.recursive, 'options.recursive');
|
||||
validateInt32.withoutStackTrace(options.retryDelay, 'options.retryDelay', 0);
|
||||
validateUint32.withoutStackTrace(options.maxRetries, 'options.maxRetries');
|
||||
|
||||
|
||||
if (!options.force || expectDir || !options.recursive) {
|
||||
const isDirectory = lazyLoadFs()
|
||||
|
|
@ -862,35 +863,14 @@ const validateRmOptionsSync = hideStackFrames((path, options, expectDir) => {
|
|||
return options;
|
||||
});
|
||||
|
||||
let recursiveRmdirWarned;
|
||||
function emitRecursiveRmdirWarning() {
|
||||
if (recursiveRmdirWarned === undefined) {
|
||||
// TODO(joyeecheung): use getOptionValue('--no-deprecation') instead.
|
||||
recursiveRmdirWarned = process.noDeprecation;
|
||||
}
|
||||
if (!recursiveRmdirWarned) {
|
||||
process.emitWarning(
|
||||
'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
|
||||
'will be removed. Use fs.rm(path, { recursive: true }) instead',
|
||||
'DeprecationWarning',
|
||||
'DEP0147',
|
||||
);
|
||||
recursiveRmdirWarned = true;
|
||||
}
|
||||
}
|
||||
|
||||
const validateRmdirOptions = hideStackFrames(
|
||||
(options, defaults = defaultRmdirOptions) => {
|
||||
(options, defaults = { __proto__: null }) => {
|
||||
if (options === undefined)
|
||||
return defaults;
|
||||
validateObject.withoutStackTrace(options, 'options');
|
||||
|
||||
options = { ...defaults, ...options };
|
||||
|
||||
validateBoolean.withoutStackTrace(options.recursive, 'options.recursive');
|
||||
validateInt32.withoutStackTrace(options.retryDelay, 'options.retryDelay', 0);
|
||||
validateUint32.withoutStackTrace(options.maxRetries, 'options.maxRetries');
|
||||
|
||||
return options;
|
||||
});
|
||||
|
||||
|
|
@ -950,7 +930,6 @@ module.exports = {
|
|||
copyObject,
|
||||
Dirent,
|
||||
DirentFromStats,
|
||||
emitRecursiveRmdirWarning,
|
||||
getDirent,
|
||||
getDirents,
|
||||
getOptions,
|
||||
|
|
|
|||
31
test/parallel/test-fs-rmdir-recursive-error.js
Normal file
31
test/parallel/test-fs-rmdir-recursive-error.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const assert = require('assert');
|
||||
const {
|
||||
rmdir,
|
||||
rmdirSync,
|
||||
promises: { rmdir: rmdirPromise }
|
||||
} = require('fs');
|
||||
|
||||
assert.throws(() => {
|
||||
rmdir('nonexistent', {
|
||||
recursive: true,
|
||||
}, common.mustNotCall());
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
rmdirSync('nonexistent', {
|
||||
recursive: true,
|
||||
});
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_VALUE',
|
||||
});
|
||||
|
||||
rmdirPromise('nonexistent', {
|
||||
recursive: true,
|
||||
}).then(common.mustNotCall(), common.mustCall((err) => {
|
||||
assert.strictEqual(err.code, 'ERR_INVALID_ARG_VALUE');
|
||||
}));
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
'use strict';
|
||||
const common = require('../common');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
|
||||
tmpdir.refresh();
|
||||
|
||||
{
|
||||
// Should warn when trying to delete a nonexistent path
|
||||
common.expectWarning(
|
||||
'DeprecationWarning',
|
||||
'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
|
||||
'will be removed. Use fs.rm(path, { recursive: true }) instead',
|
||||
'DEP0147'
|
||||
);
|
||||
assert.throws(
|
||||
() => fs.rmdirSync(tmpdir.resolve('noexist.txt'),
|
||||
{ recursive: true }),
|
||||
{ code: 'ENOENT' }
|
||||
);
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
'use strict';
|
||||
const common = require('../common');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
|
||||
tmpdir.refresh();
|
||||
|
||||
{
|
||||
common.expectWarning(
|
||||
'DeprecationWarning',
|
||||
'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
|
||||
'will be removed. Use fs.rm(path, { recursive: true }) instead',
|
||||
'DEP0147'
|
||||
);
|
||||
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
||||
fs.writeFileSync(filePath, '');
|
||||
assert.throws(
|
||||
() => fs.rmdirSync(filePath, { recursive: true }),
|
||||
{ code: common.isWindows ? 'ENOENT' : 'ENOTDIR' }
|
||||
);
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
'use strict';
|
||||
const common = require('../common');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const fs = require('fs');
|
||||
|
||||
tmpdir.refresh();
|
||||
|
||||
{
|
||||
// Should warn when trying to delete a nonexistent path
|
||||
common.expectWarning(
|
||||
'DeprecationWarning',
|
||||
'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
|
||||
'will be removed. Use fs.rm(path, { recursive: true }) instead',
|
||||
'DEP0147'
|
||||
);
|
||||
fs.rmdir(
|
||||
tmpdir.resolve('noexist.txt'),
|
||||
{ recursive: true },
|
||||
common.mustCall()
|
||||
);
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
'use strict';
|
||||
const common = require('../common');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
|
||||
tmpdir.refresh();
|
||||
|
||||
{
|
||||
common.expectWarning(
|
||||
'DeprecationWarning',
|
||||
'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
|
||||
'will be removed. Use fs.rm(path, { recursive: true }) instead',
|
||||
'DEP0147'
|
||||
);
|
||||
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
||||
fs.writeFileSync(filePath, '');
|
||||
fs.rmdir(filePath, { recursive: true }, common.mustCall((err) => {
|
||||
assert.strictEqual(err.code, common.isWindows ? 'ENOENT' : 'ENOTDIR');
|
||||
}));
|
||||
}
|
||||
|
|
@ -1,219 +0,0 @@
|
|||
// Flags: --expose-internals
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const assert = require('assert');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { validateRmdirOptions } = require('internal/fs/utils');
|
||||
|
||||
common.expectWarning(
|
||||
'DeprecationWarning',
|
||||
'In future versions of Node.js, fs.rmdir(path, { recursive: true }) ' +
|
||||
'will be removed. Use fs.rm(path, { recursive: true }) instead',
|
||||
'DEP0147'
|
||||
);
|
||||
|
||||
tmpdir.refresh();
|
||||
|
||||
let count = 0;
|
||||
const nextDirPath = (name = 'rmdir-recursive') =>
|
||||
tmpdir.resolve(`${name}-${count++}`);
|
||||
|
||||
function makeNonEmptyDirectory(depth, files, folders, dirname, createSymLinks) {
|
||||
fs.mkdirSync(dirname, { recursive: true });
|
||||
fs.writeFileSync(path.join(dirname, 'text.txt'), 'hello', 'utf8');
|
||||
|
||||
const options = { flag: 'wx' };
|
||||
|
||||
for (let f = files; f > 0; f--) {
|
||||
fs.writeFileSync(path.join(dirname, `f-${depth}-${f}`), '', options);
|
||||
}
|
||||
|
||||
if (createSymLinks) {
|
||||
// Valid symlink
|
||||
fs.symlinkSync(
|
||||
`f-${depth}-1`,
|
||||
path.join(dirname, `link-${depth}-good`),
|
||||
'file'
|
||||
);
|
||||
|
||||
// Invalid symlink
|
||||
fs.symlinkSync(
|
||||
'does-not-exist',
|
||||
path.join(dirname, `link-${depth}-bad`),
|
||||
'file'
|
||||
);
|
||||
}
|
||||
|
||||
// File with a name that looks like a glob
|
||||
fs.writeFileSync(path.join(dirname, '[a-z0-9].txt'), '', options);
|
||||
|
||||
depth--;
|
||||
if (depth <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let f = folders; f > 0; f--) {
|
||||
fs.mkdirSync(
|
||||
path.join(dirname, `folder-${depth}-${f}`),
|
||||
{ recursive: true }
|
||||
);
|
||||
makeNonEmptyDirectory(
|
||||
depth,
|
||||
files,
|
||||
folders,
|
||||
path.join(dirname, `d-${depth}-${f}`),
|
||||
createSymLinks
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function removeAsync(dir) {
|
||||
// Removal should fail without the recursive option.
|
||||
fs.rmdir(dir, common.mustCall((err) => {
|
||||
assert.strictEqual(err.syscall, 'rmdir');
|
||||
|
||||
// Removal should fail without the recursive option set to true.
|
||||
fs.rmdir(dir, { recursive: false }, common.mustCall((err) => {
|
||||
assert.strictEqual(err.syscall, 'rmdir');
|
||||
|
||||
// Recursive removal should succeed.
|
||||
fs.rmdir(dir, { recursive: true }, common.mustSucceed(() => {
|
||||
// An error should occur if recursive and the directory does not exist.
|
||||
fs.rmdir(dir, { recursive: true }, common.mustCall((err) => {
|
||||
assert.strictEqual(err.code, 'ENOENT');
|
||||
// Attempted removal should fail now because the directory is gone.
|
||||
fs.rmdir(dir, common.mustCall((err) => {
|
||||
assert.strictEqual(err.syscall, 'rmdir');
|
||||
}));
|
||||
}));
|
||||
}));
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
// Test the asynchronous version
|
||||
{
|
||||
// Create a 4-level folder hierarchy including symlinks
|
||||
let dir = nextDirPath();
|
||||
makeNonEmptyDirectory(4, 10, 2, dir, true);
|
||||
removeAsync(dir);
|
||||
|
||||
// Create a 2-level folder hierarchy without symlinks
|
||||
dir = nextDirPath();
|
||||
makeNonEmptyDirectory(2, 10, 2, dir, false);
|
||||
removeAsync(dir);
|
||||
|
||||
// Create a flat folder including symlinks
|
||||
dir = nextDirPath();
|
||||
makeNonEmptyDirectory(1, 10, 2, dir, true);
|
||||
removeAsync(dir);
|
||||
}
|
||||
|
||||
// Test the synchronous version.
|
||||
{
|
||||
const dir = nextDirPath();
|
||||
makeNonEmptyDirectory(4, 10, 2, dir, true);
|
||||
|
||||
// Removal should fail without the recursive option set to true.
|
||||
assert.throws(() => {
|
||||
fs.rmdirSync(dir);
|
||||
}, { syscall: 'rmdir' });
|
||||
assert.throws(() => {
|
||||
fs.rmdirSync(dir, { recursive: false });
|
||||
}, { syscall: 'rmdir' });
|
||||
|
||||
// Recursive removal should succeed.
|
||||
fs.rmdirSync(dir, { recursive: true });
|
||||
|
||||
// An error should occur if recursive and the directory does not exist.
|
||||
assert.throws(() => fs.rmdirSync(dir, { recursive: true }),
|
||||
{ code: 'ENOENT' });
|
||||
|
||||
// Attempted removal should fail now because the directory is gone.
|
||||
assert.throws(() => fs.rmdirSync(dir), { syscall: 'rmdir' });
|
||||
}
|
||||
|
||||
// Test the Promises based version.
|
||||
(async () => {
|
||||
const dir = nextDirPath();
|
||||
makeNonEmptyDirectory(4, 10, 2, dir, true);
|
||||
|
||||
// Removal should fail without the recursive option set to true.
|
||||
await assert.rejects(fs.promises.rmdir(dir), { syscall: 'rmdir' });
|
||||
await assert.rejects(fs.promises.rmdir(dir, { recursive: false }), {
|
||||
syscall: 'rmdir'
|
||||
});
|
||||
|
||||
// Recursive removal should succeed.
|
||||
await fs.promises.rmdir(dir, { recursive: true });
|
||||
|
||||
// An error should occur if recursive and the directory does not exist.
|
||||
await assert.rejects(fs.promises.rmdir(dir, { recursive: true }),
|
||||
{ code: 'ENOENT' });
|
||||
|
||||
// Attempted removal should fail now because the directory is gone.
|
||||
await assert.rejects(fs.promises.rmdir(dir), { syscall: 'rmdir' });
|
||||
})().then(common.mustCall());
|
||||
|
||||
// Test input validation.
|
||||
{
|
||||
const defaults = {
|
||||
retryDelay: 100,
|
||||
maxRetries: 0,
|
||||
recursive: false
|
||||
};
|
||||
const modified = {
|
||||
retryDelay: 953,
|
||||
maxRetries: 5,
|
||||
recursive: true
|
||||
};
|
||||
|
||||
assert.deepStrictEqual(validateRmdirOptions(), defaults);
|
||||
assert.deepStrictEqual(validateRmdirOptions({}), defaults);
|
||||
assert.deepStrictEqual(validateRmdirOptions(modified), modified);
|
||||
assert.deepStrictEqual(validateRmdirOptions({
|
||||
maxRetries: 99
|
||||
}), {
|
||||
retryDelay: 100,
|
||||
maxRetries: 99,
|
||||
recursive: false
|
||||
});
|
||||
|
||||
[null, 'foo', 5, NaN].forEach((bad) => {
|
||||
assert.throws(() => {
|
||||
validateRmdirOptions(bad);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /^The "options" argument must be of type object\./
|
||||
});
|
||||
});
|
||||
|
||||
[undefined, null, 'foo', Infinity, function() {}].forEach((bad) => {
|
||||
assert.throws(() => {
|
||||
validateRmdirOptions({ recursive: bad });
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE',
|
||||
name: 'TypeError',
|
||||
message: /^The "options\.recursive" property must be of type boolean\./
|
||||
});
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
validateRmdirOptions({ retryDelay: -1 });
|
||||
}, {
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
name: 'RangeError',
|
||||
message: /^The value of "options\.retryDelay" is out of range\./
|
||||
});
|
||||
|
||||
assert.throws(() => {
|
||||
validateRmdirOptions({ maxRetries: -1 });
|
||||
}, {
|
||||
code: 'ERR_OUT_OF_RANGE',
|
||||
name: 'RangeError',
|
||||
message: /^The value of "options\.maxRetries" is out of range\./
|
||||
});
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ tmpdir.refresh();
|
|||
{
|
||||
assert.throws(
|
||||
() =>
|
||||
fs.rmdirSync(tmpdir.resolve('noexist.txt'), { recursive: true }),
|
||||
fs.rmdirSync(tmpdir.resolve('noexist.txt')),
|
||||
{
|
||||
code: 'ENOENT',
|
||||
}
|
||||
|
|
@ -18,7 +18,6 @@ tmpdir.refresh();
|
|||
{
|
||||
fs.rmdir(
|
||||
tmpdir.resolve('noexist.txt'),
|
||||
{ recursive: true },
|
||||
common.mustCall((err) => {
|
||||
assert.strictEqual(err.code, 'ENOENT');
|
||||
})
|
||||
|
|
@ -26,8 +25,7 @@ tmpdir.refresh();
|
|||
}
|
||||
{
|
||||
assert.rejects(
|
||||
() => fs.promises.rmdir(tmpdir.resolve('noexist.txt'),
|
||||
{ recursive: true }),
|
||||
() => fs.promises.rmdir(tmpdir.resolve('noexist.txt')),
|
||||
{
|
||||
code: 'ENOENT',
|
||||
}
|
||||
|
|
@ -11,18 +11,18 @@ const code = common.isWindows ? 'ENOENT' : 'ENOTDIR';
|
|||
{
|
||||
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
||||
fs.writeFileSync(filePath, '');
|
||||
assert.throws(() => fs.rmdirSync(filePath, { recursive: true }), { code });
|
||||
assert.throws(() => fs.rmdirSync(filePath), { code });
|
||||
}
|
||||
{
|
||||
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
||||
fs.writeFileSync(filePath, '');
|
||||
fs.rmdir(filePath, { recursive: true }, common.mustCall((err) => {
|
||||
fs.rmdir(filePath, common.mustCall((err) => {
|
||||
assert.strictEqual(err.code, code);
|
||||
}));
|
||||
}
|
||||
{
|
||||
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
||||
fs.writeFileSync(filePath, '');
|
||||
assert.rejects(() => fs.promises.rmdir(filePath, { recursive: true }),
|
||||
assert.rejects(() => fs.promises.rmdir(filePath),
|
||||
{ code }).then(common.mustCall());
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user