Skip to content

Instantly share code, notes, and snippets.

@isaacs
Forked from laverdet/rimraf.js
Created August 8, 2011 03:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save isaacs/1131136 to your computer and use it in GitHub Desktop.
Save isaacs/1131136 to your computer and use it in GitHub Desktop.
rimraf with futures
module.exports = rimraf
var path = require("path")
, fs = require("fs")
// for EBUSY handling
var waitBusy = {}
// for EMFILE handling
var resetTimer = null
, timeout = 0
function rimraf (p, opt, cb_) {
if (typeof cb_ !== "function") cb_ = opt, opt = {}
opt.maxBusyTries = opt.maxBusyTries || 3
rimraf_(p, function cb (er) {
if (er) {
if (er.message.match(/^EBUSY/)) {
// windows is annoying.
if (!waitBusy.hasOwnProperty(p)) waitBusy[p] = opt.maxBusyTries
if (waitBusy[p]) {
waitBusy[p] --
// give it 100ms more each time
var time = (opt.maxBusyTries - waitBusy[p]) * 100
return setTimeout(function () { rimraf_(p, cb) }, time)
}
}
if (er.message.match(/^EMFILE/)) {
setTimeout(function () {
rimraf_(p, cb)
}, timeout ++)
return
}
}
timeout = 0
cb_(er)
})
}
function rimraf_ (p, cb) {
fs.lstat(p, function (er, s) {
if (er) return cb()
if (!s.isDirectory()) return fs.unlink(p, cb)
fs.readdir(p, function (er, files) {
if (er) return cb(er)
asyncForEach(files.map(function (f) {
return path.join(p, f)
}), function (f, cb) {
rimraf(f, opt, cb)
}, function (er) {
if (er) return cb(er)
fs.rmdir(p, cb)
})
})
})
}
// this is the flow control util
function asyncForEach (list, fn, cb) {
if (!list.length) cb()
var c = list.length
, errState = null
list.forEach(function (item, i, list) {
fn(item, function (er) {
if (errState) return
if (er) return cb(errState = er)
if (-- c === 0) return cb()
})
})
}
var path = require('path'),
fs = require('fs'),
Future = require('fibers/future');
// Create future-returning fs functions
var fs2 = {};
for (var ii in fs) {
fs2[ii] = Future.wrap(fs[ii]);
}
// Return a future which just pauses for a certain amount of time
function timer(ms) {
var future = new Future;
setTimeout(function() {
future.return();
}, ms);
return future;
}
var timeout = 0;
var rimraf = module.exports = function(p, opts) {
opts = opts || {};
opts.maxBusyTries = opts.maxBusyTries || 3;
var busyTries = 0;
while (true) {
try {
try {
var stat = fs2.lstat(p).wait();
} catch (ex) {
continue;
}
if (!stat.isDirectory()) return fs2.unlink(p).wait();
var rimrafs = fs2.readdir(p).wait().map(function(file) {
return rimraf(path.join(p, file), opts);
});
Future.wait(rimrafs);
fs2.rmdir(p).wait();
timeout = 0;
return;
} catch (ex) {
if (ex.message.match(/^EMFILE/)) {
timer(timeout += 10).wait();
} else if (ex.message.match(/^EBUSY/) && busyTries < opt.maxBusyTries) {
timer(++busyTries * 100).wait();
} else {
throw ex;
}
}
}
}.future();
@isaacs
Copy link
Author

isaacs commented Aug 8, 2011

Oh, I should have asked already, but can I assume you have no problem including this in the rimraf repo under the MIT license?

@laverdet
Copy link

laverdet commented Aug 8, 2011 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment