💾 Archived View for gmi.noulin.net › gitRepositories › git-off › file › src › node_modules › rimraf … captured on 2024-09-29 at 01:12:46. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
rimraf.js (8341B)
1 module.exports = rimraf 2 rimraf.sync = rimrafSync 3 4 var assert = require("assert") 5 var path = require("path") 6 var fs = require("fs") 7 var glob = require("glob") 8 9 var defaultGlobOpts = { 10 nosort: true, 11 silent: true 12 } 13 14 // for EMFILE handling 15 var timeout = 0 16 17 var isWindows = (process.platform === "win32") 18 19 function defaults (options) { 20 var methods = [ 21 'unlink', 22 'chmod', 23 'stat', 24 'lstat', 25 'rmdir', 26 'readdir' 27 ] 28 methods.forEach(function(m) { 29 options[m] = options[m] || fs[m] 30 m = m + 'Sync' 31 options[m] = options[m] || fs[m] 32 }) 33 34 options.maxBusyTries = options.maxBusyTries || 3 35 options.emfileWait = options.emfileWait || 1000 36 if (options.glob === false) { 37 options.disableGlob = true 38 } 39 options.disableGlob = options.disableGlob || false 40 options.glob = options.glob || defaultGlobOpts 41 } 42 43 function rimraf (p, options, cb) { 44 if (typeof options === 'function') { 45 cb = options 46 options = {} 47 } 48 49 assert(p, 'rimraf: missing path') 50 assert.equal(typeof p, 'string', 'rimraf: path should be a string') 51 assert.equal(typeof cb, 'function', 'rimraf: callback function required') 52 assert(options, 'rimraf: invalid options argument provided') 53 assert.equal(typeof options, 'object', 'rimraf: options should be object') 54 55 defaults(options) 56 57 var busyTries = 0 58 var errState = null 59 var n = 0 60 61 if (options.disableGlob || !glob.hasMagic(p)) 62 return afterGlob(null, [p]) 63 64 options.lstat(p, function (er, stat) { 65 if (!er) 66 return afterGlob(null, [p]) 67 68 glob(p, options.glob, afterGlob) 69 }) 70 71 function next (er) { 72 errState = errState || er 73 if (--n === 0) 74 cb(errState) 75 } 76 77 function afterGlob (er, results) { 78 if (er) 79 return cb(er) 80 81 n = results.length 82 if (n === 0) 83 return cb() 84 85 results.forEach(function (p) { 86 rimraf_(p, options, function CB (er) { 87 if (er) { 88 if (isWindows && (er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") && 89 busyTries < options.maxBusyTries) { 90 busyTries ++ 91 var time = busyTries * 100 92 // try again, with the same exact callback as this one. 93 return setTimeout(function () { 94 rimraf_(p, options, CB) 95 }, time) 96 } 97 98 // this one won't happen if graceful-fs is used. 99 if (er.code === "EMFILE" && timeout < options.emfileWait) { 100 return setTimeout(function () { 101 rimraf_(p, options, CB) 102 }, timeout ++) 103 } 104 105 // already gone 106 if (er.code === "ENOENT") er = null 107 } 108 109 timeout = 0 110 next(er) 111 }) 112 }) 113 } 114 } 115 116 // Two possible strategies. 117 // 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR 118 // 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR 119 // 120 // Both result in an extra syscall when you guess wrong. However, there 121 // are likely far more normal files in the world than directories. This 122 // is based on the assumption that a the average number of files per 123 // directory is >= 1. 124 // 125 // If anyone ever complains about this, then I guess the strategy could 126 // be made configurable somehow. But until then, YAGNI. 127 function rimraf_ (p, options, cb) { 128 assert(p) 129 assert(options) 130 assert(typeof cb === 'function') 131 132 // sunos lets the root user unlink directories, which is... weird. 133 // so we have to lstat here and make sure it's not a dir. 134 options.lstat(p, function (er, st) { 135 if (er && er.code === "ENOENT") 136 return cb(null) 137 138 // Windows can EPERM on stat. Life is suffering. 139 if (er && er.code === "EPERM" && isWindows) 140 fixWinEPERM(p, options, er, cb) 141 142 if (st && st.isDirectory()) 143 return rmdir(p, options, er, cb) 144 145 options.unlink(p, function (er) { 146 if (er) { 147 if (er.code === "ENOENT") 148 return cb(null) 149 if (er.code === "EPERM") 150 return (isWindows) 151 ? fixWinEPERM(p, options, er, cb) 152 : rmdir(p, options, er, cb) 153 if (er.code === "EISDIR") 154 return rmdir(p, options, er, cb) 155 } 156 return cb(er) 157 }) 158 }) 159 } 160 161 function fixWinEPERM (p, options, er, cb) { 162 assert(p) 163 assert(options) 164 assert(typeof cb === 'function') 165 if (er) 166 assert(er instanceof Error) 167 168 options.chmod(p, 666, function (er2) { 169 if (er2) 170 cb(er2.code === "ENOENT" ? null : er) 171 else 172 options.stat(p, function(er3, stats) { 173 if (er3) 174 cb(er3.code === "ENOENT" ? null : er) 175 else if (stats.isDirectory()) 176 rmdir(p, options, er, cb) 177 else 178 options.unlink(p, cb) 179 }) 180 }) 181 } 182 183 function fixWinEPERMSync (p, options, er) { 184 assert(p) 185 assert(options) 186 if (er) 187 assert(er instanceof Error) 188 189 try { 190 options.chmodSync(p, 666) 191 } catch (er2) { 192 if (er2.code === "ENOENT") 193 return 194 else 195 throw er 196 } 197 198 try { 199 var stats = options.statSync(p) 200 } catch (er3) { 201 if (er3.code === "ENOENT") 202 return 203 else 204 throw er 205 } 206 207 if (stats.isDirectory()) 208 rmdirSync(p, options, er) 209 else 210 options.unlinkSync(p) 211 } 212 213 function rmdir (p, options, originalEr, cb) { 214 assert(p) 215 assert(options) 216 if (originalEr) 217 assert(originalEr instanceof Error) 218 assert(typeof cb === 'function') 219 220 // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS) 221 // if we guessed wrong, and it's not a directory, then 222 // raise the original error. 223 options.rmdir(p, function (er) { 224 if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")) 225 rmkids(p, options, cb) 226 else if (er && er.code === "ENOTDIR") 227 cb(originalEr) 228 else 229 cb(er) 230 }) 231 } 232 233 function rmkids(p, options, cb) { 234 assert(p) 235 assert(options) 236 assert(typeof cb === 'function') 237 238 options.readdir(p, function (er, files) { 239 if (er) 240 return cb(er) 241 var n = files.length 242 if (n === 0) 243 return options.rmdir(p, cb) 244 var errState 245 files.forEach(function (f) { 246 rimraf(path.join(p, f), options, function (er) { 247 if (errState) 248 return 249 if (er) 250 return cb(errState = er) 251 if (--n === 0) 252 options.rmdir(p, cb) 253 }) 254 }) 255 }) 256 } 257 258 // this looks simpler, and is strictly *faster*, but will 259 // tie up the JavaScript thread and fail on excessively 260 // deep directory trees. 261 function rimrafSync (p, options) { 262 options = options || {} 263 defaults(options) 264 265 assert(p, 'rimraf: missing path') 266 assert.equal(typeof p, 'string', 'rimraf: path should be a string') 267 assert(options, 'rimraf: missing options') 268 assert.equal(typeof options, 'object', 'rimraf: options should be object') 269 270 var results 271 272 if (options.disableGlob || !glob.hasMagic(p)) { 273 results = [p] 274 } else { 275 try { 276 options.lstatSync(p) 277 results = [p] 278 } catch (er) { 279 results = glob.sync(p, options.glob) 280 } 281 } 282 283 if (!results.length) 284 return 285 286 for (var i = 0; i < results.length; i++) { 287 var p = results[i] 288 289 try { 290 var st = options.lstatSync(p) 291 } catch (er) { 292 if (er.code === "ENOENT") 293 return 294 295 // Windows can EPERM on stat. Life is suffering. 296 if (er.code === "EPERM" && isWindows) 297 fixWinEPERMSync(p, options, er) 298 } 299 300 try { 301 // sunos lets the root user unlink directories, which is... weird. 302 if (st && st.isDirectory()) 303 rmdirSync(p, options, null) 304 else 305 options.unlinkSync(p) 306 } catch (er) { 307 if (er.code === "ENOENT") 308 return 309 if (er.code === "EPERM") 310 return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er) 311 if (er.code !== "EISDIR") 312 throw er 313 rmdirSync(p, options, er) 314 } 315 } 316 } 317 318 function rmdirSync (p, options, originalEr) { 319 assert(p) 320 assert(options) 321 if (originalEr) 322 assert(originalEr instanceof Error) 323 324 try { 325 options.rmdirSync(p) 326 } catch (er) { 327 if (er.code === "ENOENT") 328 return 329 if (er.code === "ENOTDIR") 330 throw originalEr 331 if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM") 332 rmkidsSync(p, options) 333 } 334 } 335 336 function rmkidsSync (p, options) { 337 assert(p) 338 assert(options) 339 options.readdirSync(p).forEach(function (f) { 340 rimrafSync(path.join(p, f), options) 341 }) 342 options.rmdirSync(p, options) 343 }