💾 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

View Raw

More Information

⬅️ Previous capture (2023-01-29)

-=-=-=-=-=-=-

git-off

Log

Files

Refs

README

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 }