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

test: use fs rimraf to refresh tmpdir #30569

Merged
merged 3 commits into from Dec 10, 2019
Merged
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
44 changes: 37 additions & 7 deletions lib/internal/fs/rimraf.js
Expand Up @@ -5,6 +5,7 @@
// - Bring your own custom fs module is not currently supported.
// - Some basic code cleanup.
'use strict';
const { Buffer } = require('buffer');
const {
chmod,
chmodSync,
Expand All @@ -19,7 +20,7 @@ const {
unlink,
unlinkSync
} = require('fs');
const { join } = require('path');
const { sep } = require('path');
const { setTimeout } = require('timers');
const { sleep } = require('internal/util');
const notEmptyErrorCodes = new Set(['ENOTEMPTY', 'EEXIST', 'EPERM']);
Expand All @@ -28,6 +29,8 @@ const retryErrorCodes = new Set(
const isWindows = process.platform === 'win32';
const epermHandler = isWindows ? fixWinEPERM : _rmdir;
const epermHandlerSync = isWindows ? fixWinEPERMSync : _rmdirSync;
const readdirEncoding = 'buffer';
const separator = Buffer.from(sep);


function rimraf(path, options, callback) {
Expand Down Expand Up @@ -116,7 +119,9 @@ function _rmdir(path, options, originalErr, callback) {


function _rmchildren(path, options, callback) {
readdir(path, (err, files) => {
const pathBuf = Buffer.from(path);

readdir(pathBuf, readdirEncoding, (err, files) => {
if (err)
return callback(err);

Expand All @@ -128,7 +133,9 @@ function _rmchildren(path, options, callback) {
let done = false;

files.forEach((child) => {
rimraf(join(path, child), options, (err) => {
const childPath = Buffer.concat([pathBuf, separator, child]);

rimraf(childPath, options, (err) => {
if (done)
return;

Expand Down Expand Up @@ -177,7 +184,7 @@ function rimrafSync(path, options) {
if (stats !== undefined && stats.isDirectory())
_rmdirSync(path, options, null);
else
unlinkSync(path);
_unlinkSync(path, options);
} catch (err) {
if (err.code === 'ENOENT')
return;
Expand All @@ -191,6 +198,25 @@ function rimrafSync(path, options) {
}


function _unlinkSync(path, options) {
const tries = options.maxRetries + 1;

for (let i = 1; i <= tries; i++) {
try {
return unlinkSync(path);
} catch (err) {
// Only sleep if this is not the last try, and the delay is greater
// than zero, and an error was encountered that warrants a retry.
if (retryErrorCodes.has(err.code) &&
i < tries &&
options.retryDelay > 0) {
sleep(i * options.retryDelay);
}
}
}
}


function _rmdirSync(path, options, originalErr) {
try {
rmdirSync(path);
Expand All @@ -205,8 +231,12 @@ function _rmdirSync(path, options, originalErr) {
// original removal. Windows has a habit of not closing handles promptly
// when files are deleted, resulting in spurious ENOTEMPTY failures. Work
// around that issue by retrying on Windows.
readdirSync(path).forEach((child) => {
rimrafSync(join(path, child), options);
const pathBuf = Buffer.from(path);

readdirSync(pathBuf, readdirEncoding).forEach((child) => {
const childPath = Buffer.concat([pathBuf, separator, child]);

rimrafSync(childPath, options);
});

const tries = options.maxRetries + 1;
Expand Down Expand Up @@ -253,7 +283,7 @@ function fixWinEPERMSync(path, options, originalErr) {
if (stats.isDirectory())
_rmdirSync(path, options, originalErr);
else
unlinkSync(path);
_unlinkSync(path, options);
}


Expand Down
50 changes: 1 addition & 49 deletions test/common/tmpdir.js
Expand Up @@ -36,60 +36,12 @@ function rimrafSync(pathname, { spawn = true } = {}) {
}
}

try {
if (st.isDirectory())
rmdirSync(pathname, null);
else
fs.unlinkSync(pathname);
} catch (e) {
debug(e);
switch (e.code) {
case 'ENOENT':
// It's not there anymore. Work is done. Exiting.
return;

case 'EPERM':
// This can happen, try again with `rmdirSync`.
break;

case 'EISDIR':
// Got 'EISDIR' even after testing `st.isDirectory()`...
// Try again with `rmdirSync`.
break;

default:
throw e;
}
rmdirSync(pathname, e);
}
fs.rmdirSync(pathname, { recursive: true, maxRetries: 5 });

if (fs.existsSync(pathname))
throw new Error(`Unable to rimraf ${pathname}`);
}

function rmdirSync(p, originalEr) {
try {
fs.rmdirSync(p);
} catch (e) {
if (e.code === 'ENOTDIR')
throw originalEr;
if (e.code === 'ENOTEMPTY' || e.code === 'EEXIST' || e.code === 'EPERM') {
const enc = process.platform === 'linux' ? 'buffer' : 'utf8';
fs.readdirSync(p, enc).forEach((f) => {
if (f instanceof Buffer) {
const buf = Buffer.concat([Buffer.from(p), Buffer.from(path.sep), f]);
rimrafSync(buf);
} else {
rimrafSync(path.join(p, f));
}
});
fs.rmdirSync(p);
return;
}
throw e;
}
}

const testRoot = process.env.NODE_TEST_DIR ?
fs.realpathSync(process.env.NODE_TEST_DIR) : path.resolve(__dirname, '..');

Expand Down