Skip to content

Commit da4ffbc

Browse files
committed
rebase to master
fix order by which tests rimraf their leftovers
1 parent ca5c202 commit da4ffbc

13 files changed

+340
-1756
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules/
22
coverage/
33
.idea/
44
.*.swp
5+
package-lock.json

appveyor.yml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
environment:
44
matrix:
55
- nodejs_version: "6"
6+
- nodejs_version: "7"
67
- nodejs_version: "8"
78
- nodejs_version: "9"
89
- nodejs_version: "10"

lib/tmp.js

+111-94
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ const crypto = require('crypto');
1616
const _c = fs.constants && os.constants ?
1717
{ fs: fs.constants, os: os.constants } :
1818
process.binding('constants');
19+
const rimraf = require('rimraf');
1920

2021
/*
2122
* The working inner variables.
@@ -302,45 +303,6 @@ function fileSync(options) {
302303
};
303304
}
304305

305-
/**
306-
* Removes files and folders in a directory recursively.
307-
*
308-
* @param {string} root
309-
* @private
310-
*/
311-
function _rmdirRecursiveSync(root) {
312-
const dirs = [root];
313-
314-
do {
315-
var
316-
dir = dirs.pop(),
317-
deferred = false,
318-
files = fs.readdirSync(dir);
319-
320-
for (var i = 0, length = files.length; i < length; i++) {
321-
var
322-
file = path.join(dir, files[i]),
323-
stat = fs.lstatSync(file); // lstat so we don't recurse into symlinked directories
324-
325-
if (stat.isDirectory()) {
326-
/* istanbul ignore else */
327-
if (!deferred) {
328-
deferred = true;
329-
dirs.push(dir);
330-
}
331-
dirs.push(file);
332-
} else {
333-
fs.unlinkSync(file);
334-
}
335-
}
336-
337-
/* istanbul ignore else */
338-
if (!deferred) {
339-
fs.rmdirSync(dir);
340-
}
341-
} while (dirs.length !== 0);
342-
}
343-
344306
/**
345307
* Creates a temporary directory.
346308
*
@@ -390,52 +352,94 @@ function dirSync(options) {
390352
}
391353

392354
/**
393-
* Prepares the callback for removal of the temporary file.
355+
* Removes files asynchronously.
394356
*
395-
* @param {string} name the path of the file
396-
* @param {number} fd file descriptor
397-
* @param {Object} opts
398-
* @returns {fileCallback}
357+
* @param {Object} fdPath
358+
* @param {Function} next
399359
* @private
400360
*/
401-
function _prepareTmpFileRemoveCallback(name, fd, opts) {
402-
const removeCallback = _prepareRemoveCallback(function _removeCallback(fdPath) {
403-
try {
404-
/* istanbul ignore else */
405-
if (0 <= fdPath[0]) {
406-
fs.closeSync(fdPath[0]);
407-
}
408-
}
409-
catch (e) {
410-
// under some node/windows related circumstances, a temporary file
411-
// may have not be created as expected or the file was already closed
412-
// by the user, in which case we will simply ignore the error
413-
/* istanbul ignore else */
414-
if (!isEBADF(e) && !isENOENT(e)) {
415-
// reraise any unanticipated error
416-
throw e;
417-
}
361+
function _removeFileAsync(fdPath, next) {
362+
const _handler = function (err) {
363+
if (err && !isENOENT(err)) {
364+
// reraise any unanticipated error
365+
return next(err);
418366
}
367+
next();
368+
}
369+
370+
if (0 <= fdPath[0])
371+
fs.close(fdPath[0], function (err) {
372+
fs.unlink(fdPath[1], _handler);
373+
});
374+
else fs.unlink(fdPath[1], _handler);
375+
}
376+
377+
/**
378+
* Removes files synchronously.
379+
*
380+
* @param {Object} fdPath
381+
* @private
382+
*/
383+
function _removeFileSync(fdPath) {
384+
try {
385+
if (0 <= fdPath[0]) fs.closeSync(fdPath[0]);
386+
} catch (e) {
387+
// reraise any unanticipated error
388+
if (!isEBADF(e) && !isENOENT(e)) throw e;
389+
} finally {
419390
try {
420391
fs.unlinkSync(fdPath[1]);
421392
}
422393
catch (e) {
423-
/* istanbul ignore else */
424-
if (!isENOENT(e)) {
425-
// reraise any unanticipated error
426-
throw e;
427-
}
394+
// reraise any unanticipated error
395+
if (!isENOENT(e)) throw e;
428396
}
429-
}, [fd, name]);
430-
431-
/* istanbul ignore else */
432-
if (!opts.keep) {
433-
_removeObjects.unshift(removeCallback);
434397
}
398+
}
399+
400+
/**
401+
* Prepares the callback for removal of the temporary file.
402+
*
403+
* @param {string} name the path of the file
404+
* @param {number} fd file descriptor
405+
* @param {Object} opts
406+
* @returns {fileCallback}
407+
* @private
408+
*/
409+
function _prepareTmpFileRemoveCallback(name, fd, opts) {
410+
const removeCallbackSync = _prepareRemoveCallback(_removeFileSync, [fd, name]);
411+
const removeCallback = _prepareRemoveCallback(_removeFileAsync, [fd, name], removeCallbackSync);
412+
413+
if (!opts.keep) _removeObjects.unshift(removeCallbackSync);
435414

436415
return removeCallback;
437416
}
438417

418+
/**
419+
* Simple wrapper for rimraf.
420+
*
421+
* @param {string} dirPath
422+
* @param {Function} next
423+
* @private
424+
*/
425+
function _rimrafRemoveDirWrapper(dirPath, next) {
426+
rimraf(dirPath, next);
427+
}
428+
429+
/**
430+
* Simple wrapper for rimraf.sync.
431+
*
432+
* @param {string} dirPath
433+
* @private
434+
*/
435+
function _rimrafRemoveDirSyncWrapper(dirPath, next) {
436+
try {
437+
return next(null, rimraf.sync(dirPath));
438+
} catch (err) {
439+
return next(err);
440+
}
441+
}
442+
439443
/**
440444
* Prepares the callback for removal of the temporary directory.
441445
*
@@ -445,13 +449,11 @@ function _prepareTmpFileRemoveCallback(name, fd, opts) {
445449
* @private
446450
*/
447451
function _prepareTmpDirRemoveCallback(name, opts) {
448-
const removeFunction = opts.unsafeCleanup ? _rmdirRecursiveSync : fs.rmdirSync.bind(fs);
449-
const removeCallback = _prepareRemoveCallback(removeFunction, name);
450-
451-
/* istanbul ignore else */
452-
if (!opts.keep) {
453-
_removeObjects.unshift(removeCallback);
454-
}
452+
const removeFunction = opts.unsafeCleanup ? _rimrafRemoveDirWrapper : fs.rmdir.bind(fs);
453+
const removeFunctionSync = opts.unsafeCleanup ? _rimrafRemoveDirSyncWrapper : fs.rmdirSync.bind(fs);
454+
const removeCallbackSync = _prepareRemoveCallback(removeFunctionSync, name);
455+
const removeCallback = _prepareRemoveCallback(removeFunction, name, removeCallbackSync);
456+
if (!opts.keep) _removeObjects.unshift(removeCallbackSync);
455457

456458
return removeCallback;
457459
}
@@ -464,24 +466,32 @@ function _prepareTmpDirRemoveCallback(name, opts) {
464466
* @returns {Function}
465467
* @private
466468
*/
467-
function _prepareRemoveCallback(removeFunction, arg) {
469+
function _prepareRemoveCallback(removeFunction, arg, cleanupCallbackSync) {
468470
var called = false;
469471

470472
return function _cleanupCallback(next) {
471-
/* istanbul ignore else */
473+
next = next || function () {};
472474
if (!called) {
473-
const index = _removeObjects.indexOf(_cleanupCallback);
475+
const toRemove = cleanupCallbackSync || _cleanupCallback;
476+
const index = _removeObjects.indexOf(toRemove);
474477
/* istanbul ignore else */
475-
if (index >= 0) {
476-
_removeObjects.splice(index, 1);
477-
}
478+
if (index >= 0) _removeObjects.splice(index, 1);
478479

479480
called = true;
480-
removeFunction(arg);
481-
}
482-
483-
/* istanbul ignore else */
484-
if (next) next(null);
481+
// sync?
482+
if (removeFunction.length == 1) {
483+
try {
484+
removeFunction(arg);
485+
return next(null);
486+
}
487+
catch (err) {
488+
// if no next is provided and since we are
489+
// in silent cleanup mode on process exit,
490+
// we will ignore the error
491+
return next(err);
492+
}
493+
} else return removeFunction(arg, next);
494+
} else return next(new Error('cleanup callback has already been called'));
485495
};
486496
}
487497

@@ -492,15 +502,13 @@ function _prepareRemoveCallback(removeFunction, arg) {
492502
*/
493503
function _garbageCollector() {
494504
/* istanbul ignore else */
495-
if (!_gracefulCleanup) {
496-
return;
497-
}
505+
if (!_gracefulCleanup) return;
498506

499507
// the function being called removes itself from _removeObjects,
500508
// loop until _removeObjects is empty
501509
while (_removeObjects.length) {
502510
try {
503-
_removeObjects[0].call(null);
511+
_removeObjects[0]();
504512
} catch (e) {
505513
// already removed?
506514
}
@@ -555,12 +563,21 @@ function setGracefulCleanup() {
555563
/**
556564
* If there are multiple different versions of tmp in place, make sure that
557565
* we recognize the old listeners.
566+
*
567+
* @param {Function} listener
568+
* @private
569+
* @returns {Boolean} true whether listener is a legacy listener
558570
*/
559571
function _is_legacy_listener(listener) {
560572
return (listener.name == '_exit' || listener.name == '_uncaughtExceptionThrown')
561573
&& listener.toString().indexOf('_garbageCollector();') > -1;
562574
}
563575

576+
/**
577+
* Safely install process exit listeners.
578+
*
579+
* @private
580+
*/
564581
function _safely_install_listener() {
565582
var listeners = process.listeners(EVENT);
566583

@@ -570,7 +587,7 @@ function _safely_install_listener() {
570587
var lstnr = listeners[i];
571588
/* istanbul ignore else */
572589
if (lstnr.name == '_tmp$safe_listener' || _is_legacy_listener(lstnr)) {
573-
/* istanbul ignore else */
590+
// we must forget about the uncaughtException listener
574591
if (lstnr.name != '_uncaughtExceptionThrown') existingListeners.push(lstnr);
575592
process.removeListener(EVENT, lstnr);
576593
}

0 commit comments

Comments
 (0)