1 | module.exports = globSync
|
2 | globSync.GlobSync = GlobSync
|
3 |
|
4 | var fs = require('fs')
|
5 | var rp = require('fs.realpath')
|
6 | var minimatch = require('minimatch')
|
7 | var Minimatch = minimatch.Minimatch
|
8 | var Glob = require('./glob.js').Glob
|
9 | var util = require('util')
|
10 | var path = require('path')
|
11 | var assert = require('assert')
|
12 | var isAbsolute = require('path-is-absolute')
|
13 | var common = require('./common.js')
|
14 | var alphasort = common.alphasort
|
15 | var alphasorti = common.alphasorti
|
16 | var setopts = common.setopts
|
17 | var ownProp = common.ownProp
|
18 | var childrenIgnored = common.childrenIgnored
|
19 | var isIgnored = common.isIgnored
|
20 |
|
21 | function globSync (pattern, options) {
|
22 | if (typeof options === 'function' || arguments.length === 3)
|
23 | throw new TypeError('callback provided to sync glob\n'+
|
24 | 'See: https://github.com/isaacs/node-glob/issues/167')
|
25 |
|
26 | return new GlobSync(pattern, options).found
|
27 | }
|
28 |
|
29 | function GlobSync (pattern, options) {
|
30 | if (!pattern)
|
31 | throw new Error('must provide pattern')
|
32 |
|
33 | if (typeof options === 'function' || arguments.length === 3)
|
34 | throw new TypeError('callback provided to sync glob\n'+
|
35 | 'See: https://github.com/isaacs/node-glob/issues/167')
|
36 |
|
37 | if (!(this instanceof GlobSync))
|
38 | return new GlobSync(pattern, options)
|
39 |
|
40 | setopts(this, pattern, options)
|
41 |
|
42 | if (this.noprocess)
|
43 | return this
|
44 |
|
45 | var n = this.minimatch.set.length
|
46 | this.matches = new Array(n)
|
47 | for (var i = 0; i < n; i ++) {
|
48 | this._process(this.minimatch.set[i], i, false)
|
49 | }
|
50 | this._finish()
|
51 | }
|
52 |
|
53 | GlobSync.prototype._finish = function () {
|
54 | assert(this instanceof GlobSync)
|
55 | if (this.realpath) {
|
56 | var self = this
|
57 | this.matches.forEach(function (matchset, index) {
|
58 | var set = self.matches[index] = Object.create(null)
|
59 | for (var p in matchset) {
|
60 | try {
|
61 | p = self._makeAbs(p)
|
62 | var real = rp.realpathSync(p, self.realpathCache)
|
63 | set[real] = true
|
64 | } catch (er) {
|
65 | if (er.syscall === 'stat')
|
66 | set[self._makeAbs(p)] = true
|
67 | else
|
68 | throw er
|
69 | }
|
70 | }
|
71 | })
|
72 | }
|
73 | common.finish(this)
|
74 | }
|
75 |
|
76 |
|
77 | GlobSync.prototype._process = function (pattern, index, inGlobStar) {
|
78 | assert(this instanceof GlobSync)
|
79 |
|
80 |
|
81 | var n = 0
|
82 | while (typeof pattern[n] === 'string') {
|
83 | n ++
|
84 | }
|
85 |
|
86 |
|
87 |
|
88 | var prefix
|
89 | switch (n) {
|
90 |
|
91 | case pattern.length:
|
92 | this._processSimple(pattern.join('/'), index)
|
93 | return
|
94 |
|
95 | case 0:
|
96 |
|
97 |
|
98 | prefix = null
|
99 | break
|
100 |
|
101 | default:
|
102 |
|
103 |
|
104 |
|
105 | prefix = pattern.slice(0, n).join('/')
|
106 | break
|
107 | }
|
108 |
|
109 | var remain = pattern.slice(n)
|
110 |
|
111 |
|
112 | var read
|
113 | if (prefix === null)
|
114 | read = '.'
|
115 | else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) {
|
116 | if (!prefix || !isAbsolute(prefix))
|
117 | prefix = '/' + prefix
|
118 | read = prefix
|
119 | } else
|
120 | read = prefix
|
121 |
|
122 | var abs = this._makeAbs(read)
|
123 |
|
124 |
|
125 | if (childrenIgnored(this, read))
|
126 | return
|
127 |
|
128 | var isGlobStar = remain[0] === minimatch.GLOBSTAR
|
129 | if (isGlobStar)
|
130 | this._processGlobStar(prefix, read, abs, remain, index, inGlobStar)
|
131 | else
|
132 | this._processReaddir(prefix, read, abs, remain, index, inGlobStar)
|
133 | }
|
134 |
|
135 |
|
136 | GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) {
|
137 | var entries = this._readdir(abs, inGlobStar)
|
138 |
|
139 |
|
140 | if (!entries)
|
141 | return
|
142 |
|
143 |
|
144 |
|
145 | var pn = remain[0]
|
146 | var negate = !!this.minimatch.negate
|
147 | var rawGlob = pn._glob
|
148 | var dotOk = this.dot || rawGlob.charAt(0) === '.'
|
149 |
|
150 | var matchedEntries = []
|
151 | for (var i = 0; i < entries.length; i++) {
|
152 | var e = entries[i]
|
153 | if (e.charAt(0) !== '.' || dotOk) {
|
154 | var m
|
155 | if (negate && !prefix) {
|
156 | m = !e.match(pn)
|
157 | } else {
|
158 | m = e.match(pn)
|
159 | }
|
160 | if (m)
|
161 | matchedEntries.push(e)
|
162 | }
|
163 | }
|
164 |
|
165 | var len = matchedEntries.length
|
166 |
|
167 | if (len === 0)
|
168 | return
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 | if (remain.length === 1 && !this.mark && !this.stat) {
|
176 | if (!this.matches[index])
|
177 | this.matches[index] = Object.create(null)
|
178 |
|
179 | for (var i = 0; i < len; i ++) {
|
180 | var e = matchedEntries[i]
|
181 | if (prefix) {
|
182 | if (prefix.slice(-1) !== '/')
|
183 | e = prefix + '/' + e
|
184 | else
|
185 | e = prefix + e
|
186 | }
|
187 |
|
188 | if (e.charAt(0) === '/' && !this.nomount) {
|
189 | e = path.join(this.root, e)
|
190 | }
|
191 | this._emitMatch(index, e)
|
192 | }
|
193 |
|
194 | return
|
195 | }
|
196 |
|
197 |
|
198 |
|
199 | remain.shift()
|
200 | for (var i = 0; i < len; i ++) {
|
201 | var e = matchedEntries[i]
|
202 | var newPattern
|
203 | if (prefix)
|
204 | newPattern = [prefix, e]
|
205 | else
|
206 | newPattern = [e]
|
207 | this._process(newPattern.concat(remain), index, inGlobStar)
|
208 | }
|
209 | }
|
210 |
|
211 |
|
212 | GlobSync.prototype._emitMatch = function (index, e) {
|
213 | if (isIgnored(this, e))
|
214 | return
|
215 |
|
216 | var abs = this._makeAbs(e)
|
217 |
|
218 | if (this.mark)
|
219 | e = this._mark(e)
|
220 |
|
221 | if (this.absolute) {
|
222 | e = abs
|
223 | }
|
224 |
|
225 | if (this.matches[index][e])
|
226 | return
|
227 |
|
228 | if (this.nodir) {
|
229 | var c = this.cache[abs]
|
230 | if (c === 'DIR' || Array.isArray(c))
|
231 | return
|
232 | }
|
233 |
|
234 | this.matches[index][e] = true
|
235 |
|
236 | if (this.stat)
|
237 | this._stat(e)
|
238 | }
|
239 |
|
240 |
|
241 | GlobSync.prototype._readdirInGlobStar = function (abs) {
|
242 |
|
243 |
|
244 | if (this.follow)
|
245 | return this._readdir(abs, false)
|
246 |
|
247 | var entries
|
248 | var lstat
|
249 | var stat
|
250 | try {
|
251 | lstat = fs.lstatSync(abs)
|
252 | } catch (er) {
|
253 | if (er.code === 'ENOENT') {
|
254 |
|
255 | return null
|
256 | }
|
257 | }
|
258 |
|
259 | var isSym = lstat && lstat.isSymbolicLink()
|
260 | this.symlinks[abs] = isSym
|
261 |
|
262 |
|
263 |
|
264 | if (!isSym && lstat && !lstat.isDirectory())
|
265 | this.cache[abs] = 'FILE'
|
266 | else
|
267 | entries = this._readdir(abs, false)
|
268 |
|
269 | return entries
|
270 | }
|
271 |
|
272 | GlobSync.prototype._readdir = function (abs, inGlobStar) {
|
273 | var entries
|
274 |
|
275 | if (inGlobStar && !ownProp(this.symlinks, abs))
|
276 | return this._readdirInGlobStar(abs)
|
277 |
|
278 | if (ownProp(this.cache, abs)) {
|
279 | var c = this.cache[abs]
|
280 | if (!c || c === 'FILE')
|
281 | return null
|
282 |
|
283 | if (Array.isArray(c))
|
284 | return c
|
285 | }
|
286 |
|
287 | try {
|
288 | return this._readdirEntries(abs, fs.readdirSync(abs))
|
289 | } catch (er) {
|
290 | this._readdirError(abs, er)
|
291 | return null
|
292 | }
|
293 | }
|
294 |
|
295 | GlobSync.prototype._readdirEntries = function (abs, entries) {
|
296 |
|
297 |
|
298 |
|
299 | if (!this.mark && !this.stat) {
|
300 | for (var i = 0; i < entries.length; i ++) {
|
301 | var e = entries[i]
|
302 | if (abs === '/')
|
303 | e = abs + e
|
304 | else
|
305 | e = abs + '/' + e
|
306 | this.cache[e] = true
|
307 | }
|
308 | }
|
309 |
|
310 | this.cache[abs] = entries
|
311 |
|
312 |
|
313 | return entries
|
314 | }
|
315 |
|
316 | GlobSync.prototype._readdirError = function (f, er) {
|
317 |
|
318 | switch (er.code) {
|
319 | case 'ENOTSUP':
|
320 | case 'ENOTDIR':
|
321 | var abs = this._makeAbs(f)
|
322 | this.cache[abs] = 'FILE'
|
323 | if (abs === this.cwdAbs) {
|
324 | var error = new Error(er.code + ' invalid cwd ' + this.cwd)
|
325 | error.path = this.cwd
|
326 | error.code = er.code
|
327 | throw error
|
328 | }
|
329 | break
|
330 |
|
331 | case 'ENOENT':
|
332 | case 'ELOOP':
|
333 | case 'ENAMETOOLONG':
|
334 | case 'UNKNOWN':
|
335 | this.cache[this._makeAbs(f)] = false
|
336 | break
|
337 |
|
338 | default:
|
339 | this.cache[this._makeAbs(f)] = false
|
340 | if (this.strict)
|
341 | throw er
|
342 | if (!this.silent)
|
343 | console.error('glob error', er)
|
344 | break
|
345 | }
|
346 | }
|
347 |
|
348 | GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) {
|
349 |
|
350 | var entries = this._readdir(abs, inGlobStar)
|
351 |
|
352 |
|
353 |
|
354 | if (!entries)
|
355 | return
|
356 |
|
357 |
|
358 |
|
359 | var remainWithoutGlobStar = remain.slice(1)
|
360 | var gspref = prefix ? [ prefix ] : []
|
361 | var noGlobStar = gspref.concat(remainWithoutGlobStar)
|
362 |
|
363 |
|
364 | this._process(noGlobStar, index, false)
|
365 |
|
366 | var len = entries.length
|
367 | var isSym = this.symlinks[abs]
|
368 |
|
369 |
|
370 | if (isSym && inGlobStar)
|
371 | return
|
372 |
|
373 | for (var i = 0; i < len; i++) {
|
374 | var e = entries[i]
|
375 | if (e.charAt(0) === '.' && !this.dot)
|
376 | continue
|
377 |
|
378 |
|
379 | var instead = gspref.concat(entries[i], remainWithoutGlobStar)
|
380 | this._process(instead, index, true)
|
381 |
|
382 | var below = gspref.concat(entries[i], remain)
|
383 | this._process(below, index, true)
|
384 | }
|
385 | }
|
386 |
|
387 | GlobSync.prototype._processSimple = function (prefix, index) {
|
388 |
|
389 |
|
390 | var exists = this._stat(prefix)
|
391 |
|
392 | if (!this.matches[index])
|
393 | this.matches[index] = Object.create(null)
|
394 |
|
395 |
|
396 | if (!exists)
|
397 | return
|
398 |
|
399 | if (prefix && isAbsolute(prefix) && !this.nomount) {
|
400 | var trail = /[\/\\]$/.test(prefix)
|
401 | if (prefix.charAt(0) === '/') {
|
402 | prefix = path.join(this.root, prefix)
|
403 | } else {
|
404 | prefix = path.resolve(this.root, prefix)
|
405 | if (trail)
|
406 | prefix += '/'
|
407 | }
|
408 | }
|
409 |
|
410 | if (process.platform === 'win32')
|
411 | prefix = prefix.replace(/\\/g, '/')
|
412 |
|
413 |
|
414 | this._emitMatch(index, prefix)
|
415 | }
|
416 |
|
417 |
|
418 | GlobSync.prototype._stat = function (f) {
|
419 | var abs = this._makeAbs(f)
|
420 | var needDir = f.slice(-1) === '/'
|
421 |
|
422 | if (f.length > this.maxLength)
|
423 | return false
|
424 |
|
425 | if (!this.stat && ownProp(this.cache, abs)) {
|
426 | var c = this.cache[abs]
|
427 |
|
428 | if (Array.isArray(c))
|
429 | c = 'DIR'
|
430 |
|
431 |
|
432 | if (!needDir || c === 'DIR')
|
433 | return c
|
434 |
|
435 | if (needDir && c === 'FILE')
|
436 | return false
|
437 |
|
438 |
|
439 |
|
440 | }
|
441 |
|
442 | var exists
|
443 | var stat = this.statCache[abs]
|
444 | if (!stat) {
|
445 | var lstat
|
446 | try {
|
447 | lstat = fs.lstatSync(abs)
|
448 | } catch (er) {
|
449 | if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) {
|
450 | this.statCache[abs] = false
|
451 | return false
|
452 | }
|
453 | }
|
454 |
|
455 | if (lstat && lstat.isSymbolicLink()) {
|
456 | try {
|
457 | stat = fs.statSync(abs)
|
458 | } catch (er) {
|
459 | stat = lstat
|
460 | }
|
461 | } else {
|
462 | stat = lstat
|
463 | }
|
464 | }
|
465 |
|
466 | this.statCache[abs] = stat
|
467 |
|
468 | var c = true
|
469 | if (stat)
|
470 | c = stat.isDirectory() ? 'DIR' : 'FILE'
|
471 |
|
472 | this.cache[abs] = this.cache[abs] || c
|
473 |
|
474 | if (needDir && c === 'FILE')
|
475 | return false
|
476 |
|
477 | return c
|
478 | }
|
479 |
|
480 | GlobSync.prototype._mark = function (p) {
|
481 | return common.mark(this, p)
|
482 | }
|
483 |
|
484 | GlobSync.prototype._makeAbs = function (f) {
|
485 | return common.makeAbs(this, f)
|
486 | }
|