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