rimraf 2.6.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin.js +41 -23
- package/package.json +6 -3
- package/rimraf.js +75 -71
package/bin.js
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const rimraf = require('./')
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const path = require('path')
|
|
6
|
+
|
|
7
|
+
const isRoot = arg => /^(\/|[a-zA-Z]:\\)$/.test(path.resolve(arg))
|
|
8
|
+
const filterOutRoot = arg => {
|
|
9
|
+
const ok = preserveRoot === false || !isRoot(arg)
|
|
10
|
+
if (!ok) {
|
|
11
|
+
console.error(`refusing to remove ${arg}`)
|
|
12
|
+
console.error('Set --no-preserve-root to allow this')
|
|
13
|
+
}
|
|
14
|
+
return ok
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let help = false
|
|
18
|
+
let dashdash = false
|
|
19
|
+
let noglob = false
|
|
20
|
+
let preserveRoot = true
|
|
21
|
+
const args = process.argv.slice(2).filter(arg => {
|
|
9
22
|
if (dashdash)
|
|
10
23
|
return !!arg
|
|
11
24
|
else if (arg === '--')
|
|
@@ -16,35 +29,40 @@ var args = process.argv.slice(2).filter(function(arg) {
|
|
|
16
29
|
noglob = false
|
|
17
30
|
else if (arg.match(/^(-+|\/)(h(elp)?|\?)$/))
|
|
18
31
|
help = true
|
|
32
|
+
else if (arg === '--preserve-root')
|
|
33
|
+
preserveRoot = true
|
|
34
|
+
else if (arg === '--no-preserve-root')
|
|
35
|
+
preserveRoot = false
|
|
19
36
|
else
|
|
20
37
|
return !!arg
|
|
21
|
-
})
|
|
38
|
+
}).filter(arg => !preserveRoot || filterOutRoot(arg))
|
|
39
|
+
|
|
40
|
+
const go = n => {
|
|
41
|
+
if (n >= args.length)
|
|
42
|
+
return
|
|
43
|
+
const options = noglob ? { glob: false } : {}
|
|
44
|
+
rimraf(args[n], options, er => {
|
|
45
|
+
if (er)
|
|
46
|
+
throw er
|
|
47
|
+
go(n+1)
|
|
48
|
+
})
|
|
49
|
+
}
|
|
22
50
|
|
|
23
51
|
if (help || args.length === 0) {
|
|
24
52
|
// If they didn't ask for help, then this is not a "success"
|
|
25
|
-
|
|
53
|
+
const log = help ? console.log : console.error
|
|
26
54
|
log('Usage: rimraf <path> [<path> ...]')
|
|
27
55
|
log('')
|
|
28
56
|
log(' Deletes all files and folders at "path" recursively.')
|
|
29
57
|
log('')
|
|
30
58
|
log('Options:')
|
|
31
59
|
log('')
|
|
32
|
-
log(' -h, --help
|
|
33
|
-
log(' -G, --no-glob
|
|
34
|
-
log(' -g, --glob
|
|
60
|
+
log(' -h, --help Display this usage info')
|
|
61
|
+
log(' -G, --no-glob Do not expand glob patterns in arguments')
|
|
62
|
+
log(' -g, --glob Expand glob patterns in arguments (default)')
|
|
63
|
+
log(' --preserve-root Do not remove \'/\' (default)')
|
|
64
|
+
log(' --no-preserve-root Do not treat \'/\' specially')
|
|
65
|
+
log(' -- Stop parsing flags')
|
|
35
66
|
process.exit(help ? 0 : 1)
|
|
36
67
|
} else
|
|
37
68
|
go(0)
|
|
38
|
-
|
|
39
|
-
function go (n) {
|
|
40
|
-
if (n >= args.length)
|
|
41
|
-
return
|
|
42
|
-
var options = {}
|
|
43
|
-
if (noglob)
|
|
44
|
-
options = { glob: false }
|
|
45
|
-
rimraf(args[n], options, function (er) {
|
|
46
|
-
if (er)
|
|
47
|
-
throw er
|
|
48
|
-
go(n+1)
|
|
49
|
-
})
|
|
50
|
-
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rimraf",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"main": "rimraf.js",
|
|
5
5
|
"description": "A deep deletion module for node (like `rm -rf`)",
|
|
6
6
|
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
|
|
7
7
|
"license": "ISC",
|
|
8
8
|
"repository": "git://github.com/isaacs/rimraf.git",
|
|
9
9
|
"scripts": {
|
|
10
|
+
"preversion": "npm test",
|
|
11
|
+
"postversion": "npm publish",
|
|
12
|
+
"postpublish": "git push origin --follow-tags",
|
|
10
13
|
"test": "tap test/*.js"
|
|
11
14
|
},
|
|
12
15
|
"bin": "./bin.js",
|
|
13
16
|
"dependencies": {
|
|
14
|
-
"glob": "^7.
|
|
17
|
+
"glob": "^7.1.3"
|
|
15
18
|
},
|
|
16
19
|
"files": [
|
|
17
20
|
"LICENSE",
|
|
@@ -21,6 +24,6 @@
|
|
|
21
24
|
],
|
|
22
25
|
"devDependencies": {
|
|
23
26
|
"mkdirp": "^0.5.1",
|
|
24
|
-
"tap": "^
|
|
27
|
+
"tap": "^12.1.1"
|
|
25
28
|
}
|
|
26
29
|
}
|
package/rimraf.js
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
const assert = require("assert")
|
|
2
|
+
const path = require("path")
|
|
3
|
+
const fs = require("fs")
|
|
4
|
+
let glob = undefined
|
|
5
|
+
try {
|
|
6
|
+
glob = require("glob")
|
|
7
|
+
} catch (_err) {
|
|
8
|
+
// treat glob as optional.
|
|
9
|
+
}
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
const defaultGlobOpts = {
|
|
11
12
|
nosort: true,
|
|
12
13
|
silent: true
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
// for EMFILE handling
|
|
16
|
-
|
|
17
|
+
let timeout = 0
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
const isWindows = (process.platform === "win32")
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
const defaults = options => {
|
|
22
|
+
const methods = [
|
|
22
23
|
'unlink',
|
|
23
24
|
'chmod',
|
|
24
25
|
'stat',
|
|
@@ -26,7 +27,7 @@ function defaults (options) {
|
|
|
26
27
|
'rmdir',
|
|
27
28
|
'readdir'
|
|
28
29
|
]
|
|
29
|
-
methods.forEach(
|
|
30
|
+
methods.forEach(m => {
|
|
30
31
|
options[m] = options[m] || fs[m]
|
|
31
32
|
m = m + 'Sync'
|
|
32
33
|
options[m] = options[m] || fs[m]
|
|
@@ -37,11 +38,14 @@ function defaults (options) {
|
|
|
37
38
|
if (options.glob === false) {
|
|
38
39
|
options.disableGlob = true
|
|
39
40
|
}
|
|
41
|
+
if (options.disableGlob !== true && glob === undefined) {
|
|
42
|
+
throw Error('glob dependency not found, set `options.disableGlob = true` if intentional')
|
|
43
|
+
}
|
|
40
44
|
options.disableGlob = options.disableGlob || false
|
|
41
45
|
options.glob = options.glob || defaultGlobOpts
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
|
|
48
|
+
const rimraf = (p, options, cb) => {
|
|
45
49
|
if (typeof options === 'function') {
|
|
46
50
|
cb = options
|
|
47
51
|
options = {}
|
|
@@ -55,27 +59,17 @@ function rimraf (p, options, cb) {
|
|
|
55
59
|
|
|
56
60
|
defaults(options)
|
|
57
61
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (options.disableGlob || !glob.hasMagic(p))
|
|
63
|
-
return afterGlob(null, [p])
|
|
62
|
+
let busyTries = 0
|
|
63
|
+
let errState = null
|
|
64
|
+
let n = 0
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
if (!er)
|
|
67
|
-
return afterGlob(null, [p])
|
|
68
|
-
|
|
69
|
-
glob(p, options.glob, afterGlob)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
function next (er) {
|
|
66
|
+
const next = (er) => {
|
|
73
67
|
errState = errState || er
|
|
74
68
|
if (--n === 0)
|
|
75
69
|
cb(errState)
|
|
76
70
|
}
|
|
77
71
|
|
|
78
|
-
|
|
72
|
+
const afterGlob = (er, results) => {
|
|
79
73
|
if (er)
|
|
80
74
|
return cb(er)
|
|
81
75
|
|
|
@@ -83,24 +77,19 @@ function rimraf (p, options, cb) {
|
|
|
83
77
|
if (n === 0)
|
|
84
78
|
return cb()
|
|
85
79
|
|
|
86
|
-
results.forEach(
|
|
87
|
-
|
|
80
|
+
results.forEach(p => {
|
|
81
|
+
const CB = (er) => {
|
|
88
82
|
if (er) {
|
|
89
83
|
if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") &&
|
|
90
84
|
busyTries < options.maxBusyTries) {
|
|
91
85
|
busyTries ++
|
|
92
|
-
var time = busyTries * 100
|
|
93
86
|
// try again, with the same exact callback as this one.
|
|
94
|
-
return setTimeout(
|
|
95
|
-
rimraf_(p, options, CB)
|
|
96
|
-
}, time)
|
|
87
|
+
return setTimeout(() => rimraf_(p, options, CB), busyTries * 100)
|
|
97
88
|
}
|
|
98
89
|
|
|
99
90
|
// this one won't happen if graceful-fs is used.
|
|
100
91
|
if (er.code === "EMFILE" && timeout < options.emfileWait) {
|
|
101
|
-
return setTimeout(
|
|
102
|
-
rimraf_(p, options, CB)
|
|
103
|
-
}, timeout ++)
|
|
92
|
+
return setTimeout(() => rimraf_(p, options, CB), timeout ++)
|
|
104
93
|
}
|
|
105
94
|
|
|
106
95
|
// already gone
|
|
@@ -109,9 +98,21 @@ function rimraf (p, options, cb) {
|
|
|
109
98
|
|
|
110
99
|
timeout = 0
|
|
111
100
|
next(er)
|
|
112
|
-
}
|
|
101
|
+
}
|
|
102
|
+
rimraf_(p, options, CB)
|
|
113
103
|
})
|
|
114
104
|
}
|
|
105
|
+
|
|
106
|
+
if (options.disableGlob || !glob.hasMagic(p))
|
|
107
|
+
return afterGlob(null, [p])
|
|
108
|
+
|
|
109
|
+
options.lstat(p, (er, stat) => {
|
|
110
|
+
if (!er)
|
|
111
|
+
return afterGlob(null, [p])
|
|
112
|
+
|
|
113
|
+
glob(p, options.glob, afterGlob)
|
|
114
|
+
})
|
|
115
|
+
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
// Two possible strategies.
|
|
@@ -125,14 +126,14 @@ function rimraf (p, options, cb) {
|
|
|
125
126
|
//
|
|
126
127
|
// If anyone ever complains about this, then I guess the strategy could
|
|
127
128
|
// be made configurable somehow. But until then, YAGNI.
|
|
128
|
-
|
|
129
|
+
const rimraf_ = (p, options, cb) => {
|
|
129
130
|
assert(p)
|
|
130
131
|
assert(options)
|
|
131
132
|
assert(typeof cb === 'function')
|
|
132
133
|
|
|
133
134
|
// sunos lets the root user unlink directories, which is... weird.
|
|
134
135
|
// so we have to lstat here and make sure it's not a dir.
|
|
135
|
-
options.lstat(p,
|
|
136
|
+
options.lstat(p, (er, st) => {
|
|
136
137
|
if (er && er.code === "ENOENT")
|
|
137
138
|
return cb(null)
|
|
138
139
|
|
|
@@ -143,7 +144,7 @@ function rimraf_ (p, options, cb) {
|
|
|
143
144
|
if (st && st.isDirectory())
|
|
144
145
|
return rmdir(p, options, er, cb)
|
|
145
146
|
|
|
146
|
-
options.unlink(p,
|
|
147
|
+
options.unlink(p, er => {
|
|
147
148
|
if (er) {
|
|
148
149
|
if (er.code === "ENOENT")
|
|
149
150
|
return cb(null)
|
|
@@ -159,18 +160,18 @@ function rimraf_ (p, options, cb) {
|
|
|
159
160
|
})
|
|
160
161
|
}
|
|
161
162
|
|
|
162
|
-
|
|
163
|
+
const fixWinEPERM = (p, options, er, cb) => {
|
|
163
164
|
assert(p)
|
|
164
165
|
assert(options)
|
|
165
166
|
assert(typeof cb === 'function')
|
|
166
167
|
if (er)
|
|
167
168
|
assert(er instanceof Error)
|
|
168
169
|
|
|
169
|
-
options.chmod(p,
|
|
170
|
+
options.chmod(p, 0o666, er2 => {
|
|
170
171
|
if (er2)
|
|
171
172
|
cb(er2.code === "ENOENT" ? null : er)
|
|
172
173
|
else
|
|
173
|
-
options.stat(p,
|
|
174
|
+
options.stat(p, (er3, stats) => {
|
|
174
175
|
if (er3)
|
|
175
176
|
cb(er3.code === "ENOENT" ? null : er)
|
|
176
177
|
else if (stats.isDirectory())
|
|
@@ -181,14 +182,14 @@ function fixWinEPERM (p, options, er, cb) {
|
|
|
181
182
|
})
|
|
182
183
|
}
|
|
183
184
|
|
|
184
|
-
|
|
185
|
+
const fixWinEPERMSync = (p, options, er) => {
|
|
185
186
|
assert(p)
|
|
186
187
|
assert(options)
|
|
187
188
|
if (er)
|
|
188
189
|
assert(er instanceof Error)
|
|
189
190
|
|
|
190
191
|
try {
|
|
191
|
-
options.chmodSync(p,
|
|
192
|
+
options.chmodSync(p, 0o666)
|
|
192
193
|
} catch (er2) {
|
|
193
194
|
if (er2.code === "ENOENT")
|
|
194
195
|
return
|
|
@@ -196,8 +197,9 @@ function fixWinEPERMSync (p, options, er) {
|
|
|
196
197
|
throw er
|
|
197
198
|
}
|
|
198
199
|
|
|
200
|
+
let stats
|
|
199
201
|
try {
|
|
200
|
-
|
|
202
|
+
stats = options.statSync(p)
|
|
201
203
|
} catch (er3) {
|
|
202
204
|
if (er3.code === "ENOENT")
|
|
203
205
|
return
|
|
@@ -211,7 +213,7 @@ function fixWinEPERMSync (p, options, er) {
|
|
|
211
213
|
options.unlinkSync(p)
|
|
212
214
|
}
|
|
213
215
|
|
|
214
|
-
|
|
216
|
+
const rmdir = (p, options, originalEr, cb) => {
|
|
215
217
|
assert(p)
|
|
216
218
|
assert(options)
|
|
217
219
|
if (originalEr)
|
|
@@ -221,7 +223,7 @@ function rmdir (p, options, originalEr, cb) {
|
|
|
221
223
|
// try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS)
|
|
222
224
|
// if we guessed wrong, and it's not a directory, then
|
|
223
225
|
// raise the original error.
|
|
224
|
-
options.rmdir(p,
|
|
226
|
+
options.rmdir(p, er => {
|
|
225
227
|
if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM"))
|
|
226
228
|
rmkids(p, options, cb)
|
|
227
229
|
else if (er && er.code === "ENOTDIR")
|
|
@@ -231,20 +233,20 @@ function rmdir (p, options, originalEr, cb) {
|
|
|
231
233
|
})
|
|
232
234
|
}
|
|
233
235
|
|
|
234
|
-
|
|
236
|
+
const rmkids = (p, options, cb) => {
|
|
235
237
|
assert(p)
|
|
236
238
|
assert(options)
|
|
237
239
|
assert(typeof cb === 'function')
|
|
238
240
|
|
|
239
|
-
options.readdir(p,
|
|
241
|
+
options.readdir(p, (er, files) => {
|
|
240
242
|
if (er)
|
|
241
243
|
return cb(er)
|
|
242
|
-
|
|
244
|
+
let n = files.length
|
|
243
245
|
if (n === 0)
|
|
244
246
|
return options.rmdir(p, cb)
|
|
245
|
-
|
|
246
|
-
files.forEach(
|
|
247
|
-
rimraf(path.join(p, f), options,
|
|
247
|
+
let errState
|
|
248
|
+
files.forEach(f => {
|
|
249
|
+
rimraf(path.join(p, f), options, er => {
|
|
248
250
|
if (errState)
|
|
249
251
|
return
|
|
250
252
|
if (er)
|
|
@@ -259,7 +261,7 @@ function rmkids(p, options, cb) {
|
|
|
259
261
|
// this looks simpler, and is strictly *faster*, but will
|
|
260
262
|
// tie up the JavaScript thread and fail on excessively
|
|
261
263
|
// deep directory trees.
|
|
262
|
-
|
|
264
|
+
const rimrafSync = (p, options) => {
|
|
263
265
|
options = options || {}
|
|
264
266
|
defaults(options)
|
|
265
267
|
|
|
@@ -268,7 +270,7 @@ function rimrafSync (p, options) {
|
|
|
268
270
|
assert(options, 'rimraf: missing options')
|
|
269
271
|
assert.equal(typeof options, 'object', 'rimraf: options should be object')
|
|
270
272
|
|
|
271
|
-
|
|
273
|
+
let results
|
|
272
274
|
|
|
273
275
|
if (options.disableGlob || !glob.hasMagic(p)) {
|
|
274
276
|
results = [p]
|
|
@@ -284,11 +286,12 @@ function rimrafSync (p, options) {
|
|
|
284
286
|
if (!results.length)
|
|
285
287
|
return
|
|
286
288
|
|
|
287
|
-
for (
|
|
288
|
-
|
|
289
|
+
for (let i = 0; i < results.length; i++) {
|
|
290
|
+
const p = results[i]
|
|
289
291
|
|
|
292
|
+
let st
|
|
290
293
|
try {
|
|
291
|
-
|
|
294
|
+
st = options.lstatSync(p)
|
|
292
295
|
} catch (er) {
|
|
293
296
|
if (er.code === "ENOENT")
|
|
294
297
|
return
|
|
@@ -317,7 +320,7 @@ function rimrafSync (p, options) {
|
|
|
317
320
|
}
|
|
318
321
|
}
|
|
319
322
|
|
|
320
|
-
|
|
323
|
+
const rmdirSync = (p, options, originalEr) => {
|
|
321
324
|
assert(p)
|
|
322
325
|
assert(options)
|
|
323
326
|
if (originalEr)
|
|
@@ -335,12 +338,10 @@ function rmdirSync (p, options, originalEr) {
|
|
|
335
338
|
}
|
|
336
339
|
}
|
|
337
340
|
|
|
338
|
-
|
|
341
|
+
const rmkidsSync = (p, options) => {
|
|
339
342
|
assert(p)
|
|
340
343
|
assert(options)
|
|
341
|
-
options.readdirSync(p).forEach(
|
|
342
|
-
rimrafSync(path.join(p, f), options)
|
|
343
|
-
})
|
|
344
|
+
options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options))
|
|
344
345
|
|
|
345
346
|
// We only end up here once we got ENOTEMPTY at least once, and
|
|
346
347
|
// at this point, we are guaranteed to have removed all the kids.
|
|
@@ -348,12 +349,12 @@ function rmkidsSync (p, options) {
|
|
|
348
349
|
// try really hard to delete stuff on windows, because it has a
|
|
349
350
|
// PROFOUNDLY annoying habit of not closing handles promptly when
|
|
350
351
|
// files are deleted, resulting in spurious ENOTEMPTY errors.
|
|
351
|
-
|
|
352
|
-
|
|
352
|
+
const retries = isWindows ? 100 : 1
|
|
353
|
+
let i = 0
|
|
353
354
|
do {
|
|
354
|
-
|
|
355
|
+
let threw = true
|
|
355
356
|
try {
|
|
356
|
-
|
|
357
|
+
const ret = options.rmdirSync(p, options)
|
|
357
358
|
threw = false
|
|
358
359
|
return ret
|
|
359
360
|
} finally {
|
|
@@ -362,3 +363,6 @@ function rmkidsSync (p, options) {
|
|
|
362
363
|
}
|
|
363
364
|
} while (true)
|
|
364
365
|
}
|
|
366
|
+
|
|
367
|
+
module.exports = rimraf
|
|
368
|
+
rimraf.sync = rimrafSync
|