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
|
<!-- YAML
|
||||||
changes:
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/58616
|
||||||
|
description: End-of-Life.
|
||||||
- version: v16.0.0
|
- version: v16.0.0
|
||||||
pr-url: https://github.com/nodejs/node/pull/37302
|
pr-url: https://github.com/nodejs/node/pull/37302
|
||||||
description: Runtime deprecation.
|
description: Runtime deprecation.
|
||||||
|
|
@ -3068,10 +3071,10 @@ changes:
|
||||||
description: Documentation-only deprecation.
|
description: Documentation-only deprecation.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
Type: Runtime
|
Type: End-of-Life
|
||||||
|
|
||||||
In future versions of Node.js, `recursive` option will be ignored for
|
The `fs.rmdir`, `fs.rmdirSync`, and `fs.promises.rmdir` methods used
|
||||||
`fs.rmdir`, `fs.rmdirSync`, and `fs.promises.rmdir`.
|
to support a `recursive` option. That option has been removed.
|
||||||
|
|
||||||
Use `fs.rm(path, { recursive: true, force: true })`,
|
Use `fs.rm(path, { recursive: true, force: true })`,
|
||||||
`fs.rmSync(path, { recursive: true, force: true })` or
|
`fs.rmSync(path, { recursive: true, force: true })` or
|
||||||
|
|
|
||||||
|
|
@ -1589,6 +1589,9 @@ Renames `oldPath` to `newPath`.
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v10.0.0
|
added: v10.0.0
|
||||||
changes:
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/58616
|
||||||
|
description: Remove `recursive` option.
|
||||||
- version: v16.0.0
|
- version: v16.0.0
|
||||||
pr-url: https://github.com/nodejs/node/pull/37216
|
pr-url: https://github.com/nodejs/node/pull/37216
|
||||||
description: "Using `fsPromises.rmdir(path, { recursive: true })` on a `path`
|
description: "Using `fsPromises.rmdir(path, { recursive: true })` on a `path`
|
||||||
|
|
@ -1622,18 +1625,10 @@ changes:
|
||||||
-->
|
-->
|
||||||
|
|
||||||
* `path` {string|Buffer|URL}
|
* `path` {string|Buffer|URL}
|
||||||
* `options` {Object}
|
* `options` {Object} There are currently no options exposed. There used to
|
||||||
* `maxRetries` {integer} If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or
|
be options for `recursive`, `maxBusyTries`, and `emfileWait` but they were
|
||||||
`EPERM` error is encountered, Node.js retries the operation with a linear
|
deprecated and removed. The `options` argument is still accepted for
|
||||||
backoff wait of `retryDelay` milliseconds longer on each try. This option
|
backwards compatibility but it is not used.
|
||||||
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`.
|
|
||||||
* Returns: {Promise} Fulfills with `undefined` upon success.
|
* Returns: {Promise} Fulfills with `undefined` upon success.
|
||||||
|
|
||||||
Removes the directory identified by `path`.
|
Removes the directory identified by `path`.
|
||||||
|
|
@ -4255,6 +4250,9 @@ rename('oldFile.txt', 'newFile.txt', (err) => {
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.0.2
|
added: v0.0.2
|
||||||
changes:
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/58616
|
||||||
|
description: Remove `recursive` option.
|
||||||
- version: v18.0.0
|
- version: v18.0.0
|
||||||
pr-url: https://github.com/nodejs/node/pull/41678
|
pr-url: https://github.com/nodejs/node/pull/41678
|
||||||
description: Passing an invalid callback to the `callback` argument
|
description: Passing an invalid callback to the `callback` argument
|
||||||
|
|
@ -4305,18 +4303,10 @@ changes:
|
||||||
-->
|
-->
|
||||||
|
|
||||||
* `path` {string|Buffer|URL}
|
* `path` {string|Buffer|URL}
|
||||||
* `options` {Object}
|
* `options` {Object} There are currently no options exposed. There used to
|
||||||
* `maxRetries` {integer} If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or
|
be options for `recursive`, `maxBusyTries`, and `emfileWait` but they were
|
||||||
`EPERM` error is encountered, Node.js retries the operation with a linear
|
deprecated and removed. The `options` argument is still accepted for
|
||||||
backoff wait of `retryDelay` milliseconds longer on each try. This option
|
backwards compatibility but it is not used.
|
||||||
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`.
|
|
||||||
* `callback` {Function}
|
* `callback` {Function}
|
||||||
* `err` {Error}
|
* `err` {Error}
|
||||||
|
|
||||||
|
|
@ -6234,6 +6224,9 @@ See the POSIX rename(2) documentation for more details.
|
||||||
<!-- YAML
|
<!-- YAML
|
||||||
added: v0.1.21
|
added: v0.1.21
|
||||||
changes:
|
changes:
|
||||||
|
- version: REPLACEME
|
||||||
|
pr-url: https://github.com/nodejs/node/pull/58616
|
||||||
|
description: Remove `recursive` option.
|
||||||
- version: v16.0.0
|
- version: v16.0.0
|
||||||
pr-url: https://github.com/nodejs/node/pull/37216
|
pr-url: https://github.com/nodejs/node/pull/37216
|
||||||
description: "Using `fs.rmdirSync(path, { recursive: true })` on a `path`
|
description: "Using `fs.rmdirSync(path, { recursive: true })` on a `path`
|
||||||
|
|
@ -6271,18 +6264,10 @@ changes:
|
||||||
-->
|
-->
|
||||||
|
|
||||||
* `path` {string|Buffer|URL}
|
* `path` {string|Buffer|URL}
|
||||||
* `options` {Object}
|
* `options` {Object} There are currently no options exposed. There used to
|
||||||
* `maxRetries` {integer} If an `EBUSY`, `EMFILE`, `ENFILE`, `ENOTEMPTY`, or
|
be options for `recursive`, `maxBusyTries`, and `emfileWait` but they were
|
||||||
`EPERM` error is encountered, Node.js retries the operation with a linear
|
deprecated and removed. The `options` argument is still accepted for
|
||||||
backoff wait of `retryDelay` milliseconds longer on each try. This option
|
backwards compatibility but it is not used.
|
||||||
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`.
|
|
||||||
|
|
||||||
Synchronous rmdir(2). Returns `undefined`.
|
Synchronous rmdir(2). Returns `undefined`.
|
||||||
|
|
||||||
|
|
|
||||||
70
lib/fs.js
70
lib/fs.js
|
|
@ -102,7 +102,6 @@ const {
|
||||||
},
|
},
|
||||||
copyObject,
|
copyObject,
|
||||||
Dirent,
|
Dirent,
|
||||||
emitRecursiveRmdirWarning,
|
|
||||||
getDirent,
|
getDirent,
|
||||||
getDirents,
|
getDirents,
|
||||||
getOptions,
|
getOptions,
|
||||||
|
|
@ -1109,11 +1108,7 @@ function lazyLoadRimraf() {
|
||||||
/**
|
/**
|
||||||
* Asynchronously removes a directory.
|
* Asynchronously removes a directory.
|
||||||
* @param {string | Buffer | URL} path
|
* @param {string | Buffer | URL} path
|
||||||
* @param {{
|
* @param {{}} [options]
|
||||||
* maxRetries?: number;
|
|
||||||
* recursive?: boolean;
|
|
||||||
* retryDelay?: number;
|
|
||||||
* }} [options]
|
|
||||||
* @param {(err?: Error) => any} callback
|
* @param {(err?: Error) => any} callback
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
|
|
@ -1123,60 +1118,45 @@ function rmdir(path, options, callback) {
|
||||||
options = undefined;
|
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);
|
callback = makeCallback(callback);
|
||||||
path = getValidatedPath(path);
|
path = getValidatedPath(path);
|
||||||
|
|
||||||
if (options?.recursive) {
|
validateRmdirOptions(options);
|
||||||
emitRecursiveRmdirWarning();
|
const req = new FSReqCallback();
|
||||||
validateRmOptions(
|
req.oncomplete = callback;
|
||||||
path,
|
binding.rmdir(path, req);
|
||||||
{ ...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.
|
* Synchronously removes a directory.
|
||||||
* @param {string | Buffer | URL} path
|
* @param {string | Buffer | URL} path
|
||||||
* @param {{
|
* @param {{}} [options]
|
||||||
* maxRetries?: number;
|
|
||||||
* recursive?: boolean;
|
|
||||||
* retryDelay?: number;
|
|
||||||
* }} [options]
|
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function rmdirSync(path, options) {
|
function rmdirSync(path, options) {
|
||||||
path = getValidatedPath(path);
|
path = getValidatedPath(path);
|
||||||
|
|
||||||
if (options?.recursive) {
|
if (options?.recursive !== undefined) {
|
||||||
emitRecursiveRmdirWarning();
|
throw new ERR_INVALID_ARG_VALUE(
|
||||||
options = validateRmOptionsSync(path, { ...options, force: false }, true);
|
'options.recursive',
|
||||||
if (options !== false) {
|
options.recursive,
|
||||||
return binding.rmSync(path, options.maxRetries, options.recursive, options.retryDelay);
|
'is no longer supported',
|
||||||
}
|
);
|
||||||
} else {
|
|
||||||
validateRmdirOptions(options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateRmdirOptions(options);
|
||||||
binding.rmdir(path);
|
binding.rmdir(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ const {
|
||||||
kWriteFileMaxChunkSize,
|
kWriteFileMaxChunkSize,
|
||||||
},
|
},
|
||||||
copyObject,
|
copyObject,
|
||||||
emitRecursiveRmdirWarning,
|
|
||||||
getDirents,
|
getDirents,
|
||||||
getOptions,
|
getOptions,
|
||||||
getStatFsFromBinding,
|
getStatFsFromBinding,
|
||||||
|
|
@ -812,16 +811,17 @@ async function rm(path, options) {
|
||||||
|
|
||||||
async function rmdir(path, options) {
|
async function rmdir(path, options) {
|
||||||
path = getValidatedPath(path);
|
path = getValidatedPath(path);
|
||||||
options = validateRmdirOptions(options);
|
|
||||||
|
|
||||||
if (options.recursive) {
|
if (options?.recursive !== undefined) {
|
||||||
emitRecursiveRmdirWarning();
|
throw new ERR_INVALID_ARG_VALUE(
|
||||||
const stats = await stat(path);
|
'options.recursive',
|
||||||
if (stats.isDirectory()) {
|
options.recursive,
|
||||||
return lazyRimRaf()(path, options);
|
'is no longer supported',
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options = validateRmdirOptions(options);
|
||||||
|
|
||||||
return await PromisePrototypeThen(
|
return await PromisePrototypeThen(
|
||||||
binding.rmdir(path, kUsePromises),
|
binding.rmdir(path, kUsePromises),
|
||||||
undefined,
|
undefined,
|
||||||
|
|
|
||||||
|
|
@ -778,12 +778,6 @@ const defaultRmOptions = {
|
||||||
maxRetries: 0,
|
maxRetries: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultRmdirOptions = {
|
|
||||||
retryDelay: 100,
|
|
||||||
maxRetries: 0,
|
|
||||||
recursive: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateCpOptions = hideStackFrames((options) => {
|
const validateCpOptions = hideStackFrames((options) => {
|
||||||
if (options === undefined)
|
if (options === undefined)
|
||||||
return { ...defaultCpOptions };
|
return { ...defaultCpOptions };
|
||||||
|
|
@ -807,7 +801,10 @@ const validateCpOptions = hideStackFrames((options) => {
|
||||||
|
|
||||||
const validateRmOptions = hideStackFrames((path, options, expectDir, cb) => {
|
const validateRmOptions = hideStackFrames((path, options, expectDir, cb) => {
|
||||||
options = validateRmdirOptions(options, defaultRmOptions);
|
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) => {
|
lazyLoadFs().lstat(path, (err, stats) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
@ -839,6 +836,10 @@ const validateRmOptions = hideStackFrames((path, options, expectDir, cb) => {
|
||||||
const validateRmOptionsSync = hideStackFrames((path, options, expectDir) => {
|
const validateRmOptionsSync = hideStackFrames((path, options, expectDir) => {
|
||||||
options = validateRmdirOptions.withoutStackTrace(options, defaultRmOptions);
|
options = validateRmdirOptions.withoutStackTrace(options, defaultRmOptions);
|
||||||
validateBoolean.withoutStackTrace(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');
|
||||||
|
|
||||||
|
|
||||||
if (!options.force || expectDir || !options.recursive) {
|
if (!options.force || expectDir || !options.recursive) {
|
||||||
const isDirectory = lazyLoadFs()
|
const isDirectory = lazyLoadFs()
|
||||||
|
|
@ -862,35 +863,14 @@ const validateRmOptionsSync = hideStackFrames((path, options, expectDir) => {
|
||||||
return options;
|
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(
|
const validateRmdirOptions = hideStackFrames(
|
||||||
(options, defaults = defaultRmdirOptions) => {
|
(options, defaults = { __proto__: null }) => {
|
||||||
if (options === undefined)
|
if (options === undefined)
|
||||||
return defaults;
|
return defaults;
|
||||||
validateObject.withoutStackTrace(options, 'options');
|
validateObject.withoutStackTrace(options, 'options');
|
||||||
|
|
||||||
options = { ...defaults, ...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;
|
return options;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -950,7 +930,6 @@ module.exports = {
|
||||||
copyObject,
|
copyObject,
|
||||||
Dirent,
|
Dirent,
|
||||||
DirentFromStats,
|
DirentFromStats,
|
||||||
emitRecursiveRmdirWarning,
|
|
||||||
getDirent,
|
getDirent,
|
||||||
getDirents,
|
getDirents,
|
||||||
getOptions,
|
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(
|
assert.throws(
|
||||||
() =>
|
() =>
|
||||||
fs.rmdirSync(tmpdir.resolve('noexist.txt'), { recursive: true }),
|
fs.rmdirSync(tmpdir.resolve('noexist.txt')),
|
||||||
{
|
{
|
||||||
code: 'ENOENT',
|
code: 'ENOENT',
|
||||||
}
|
}
|
||||||
|
|
@ -18,7 +18,6 @@ tmpdir.refresh();
|
||||||
{
|
{
|
||||||
fs.rmdir(
|
fs.rmdir(
|
||||||
tmpdir.resolve('noexist.txt'),
|
tmpdir.resolve('noexist.txt'),
|
||||||
{ recursive: true },
|
|
||||||
common.mustCall((err) => {
|
common.mustCall((err) => {
|
||||||
assert.strictEqual(err.code, 'ENOENT');
|
assert.strictEqual(err.code, 'ENOENT');
|
||||||
})
|
})
|
||||||
|
|
@ -26,8 +25,7 @@ tmpdir.refresh();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
assert.rejects(
|
assert.rejects(
|
||||||
() => fs.promises.rmdir(tmpdir.resolve('noexist.txt'),
|
() => fs.promises.rmdir(tmpdir.resolve('noexist.txt')),
|
||||||
{ recursive: true }),
|
|
||||||
{
|
{
|
||||||
code: 'ENOENT',
|
code: 'ENOENT',
|
||||||
}
|
}
|
||||||
|
|
@ -11,18 +11,18 @@ const code = common.isWindows ? 'ENOENT' : 'ENOTDIR';
|
||||||
{
|
{
|
||||||
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
||||||
fs.writeFileSync(filePath, '');
|
fs.writeFileSync(filePath, '');
|
||||||
assert.throws(() => fs.rmdirSync(filePath, { recursive: true }), { code });
|
assert.throws(() => fs.rmdirSync(filePath), { code });
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
||||||
fs.writeFileSync(filePath, '');
|
fs.writeFileSync(filePath, '');
|
||||||
fs.rmdir(filePath, { recursive: true }, common.mustCall((err) => {
|
fs.rmdir(filePath, common.mustCall((err) => {
|
||||||
assert.strictEqual(err.code, code);
|
assert.strictEqual(err.code, code);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
const filePath = tmpdir.resolve('rmdir-recursive.txt');
|
||||||
fs.writeFileSync(filePath, '');
|
fs.writeFileSync(filePath, '');
|
||||||
assert.rejects(() => fs.promises.rmdir(filePath, { recursive: true }),
|
assert.rejects(() => fs.promises.rmdir(filePath),
|
||||||
{ code }).then(common.mustCall());
|
{ code }).then(common.mustCall());
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user