Skip to content

Commit 2ca231c

Browse files
committed
rebase to master
fix order by which tests rimraf their leftovers
1 parent 6c3db68 commit 2ca231c

13 files changed

+341
-1955
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ environment:
66
- nodejs_version: "5"
77
- nodejs_version: "6"
88
- nodejs_version: "7"
9+
- nodejs_version: "8"
10+
- nodejs_version: "9"
911

1012
install:
1113
- ps: Install-Product node $env:nodejs_version

lib/tmp.js

Lines changed: 112 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ const os = require('os');
1414
const path = require('path');
1515
const crypto = require('crypto');
1616
const osTmpDir = require('os-tmpdir');
17-
const _c = fs.constants && os.constants ?
18-
{ fs: fs.constants, os: os.constants } :
19-
process.binding('constants');
17+
const rimraf = require('rimraf');
18+
const _c = process.binding('constants');
2019

2120
/*
2221
* The working inner variables.
@@ -303,45 +302,6 @@ function fileSync(options) {
303302
};
304303
}
305304

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

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

437414
return removeCallback;
438415
}
439416

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

457457
return removeCallback;
458458
}
@@ -465,24 +465,32 @@ function _prepareTmpDirRemoveCallback(name, opts) {
465465
* @returns {Function}
466466
* @private
467467
*/
468-
function _prepareRemoveCallback(removeFunction, arg) {
468+
function _prepareRemoveCallback(removeFunction, arg, cleanupCallbackSync) {
469469
var called = false;
470470

471471
return function _cleanupCallback(next) {
472-
/* istanbul ignore else */
472+
next = next || function () {};
473473
if (!called) {
474-
const index = _removeObjects.indexOf(_cleanupCallback);
474+
const toRemove = cleanupCallbackSync || _cleanupCallback;
475+
const index = _removeObjects.indexOf(toRemove);
475476
/* istanbul ignore else */
476-
if (index >= 0) {
477-
_removeObjects.splice(index, 1);
478-
}
477+
if (index >= 0) _removeObjects.splice(index, 1);
479478

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

@@ -493,15 +501,13 @@ function _prepareRemoveCallback(removeFunction, arg) {
493501
*/
494502
function _garbageCollector() {
495503
/* istanbul ignore else */
496-
if (!_gracefulCleanup) {
497-
return;
498-
}
504+
if (!_gracefulCleanup) return;
499505

500506
// the function being called removes itself from _removeObjects,
501507
// loop until _removeObjects is empty
502508
while (_removeObjects.length) {
503509
try {
504-
_removeObjects[0].call(null);
510+
_removeObjects[0]();
505511
} catch (e) {
506512
// already removed?
507513
}
@@ -556,12 +562,21 @@ function setGracefulCleanup() {
556562
/**
557563
* If there are multiple different versions of tmp in place, make sure that
558564
* we recognize the old listeners.
565+
*
566+
* @param {Function} listener
567+
* @private
568+
* @returns {Boolean} true whether listener is a legacy listener
559569
*/
560570
function _is_legacy_listener(listener) {
561571
return (listener.name == '_exit' || listener.name == '_uncaughtExceptionThrown')
562572
&& listener.toString().indexOf('_garbageCollector();') > -1;
563573
}
564574

575+
/**
576+
* Safely install process exit listeners.
577+
*
578+
* @private
579+
*/
565580
function _safely_install_listener() {
566581
var listeners = process.listeners(EVENT);
567582

@@ -571,7 +586,7 @@ function _safely_install_listener() {
571586
var lstnr = listeners[i];
572587
/* istanbul ignore else */
573588
if (lstnr.name == '_tmp$safe_listener' || _is_legacy_listener(lstnr)) {
574-
/* istanbul ignore else */
589+
// we must forget about the uncaughtException listener
575590
if (lstnr.name != '_uncaughtExceptionThrown') existingListeners.push(lstnr);
576591
process.removeListener(EVENT, lstnr);
577592
}

0 commit comments

Comments
 (0)