Initial commit
[yaffs-website] / node_modules / node-sass / node_modules / globule / node_modules / glob / sync.js
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   // Get the first [n] parts of pattern that are all strings.
81   var n = 0
82   while (typeof pattern[n] === 'string') {
83     n ++
84   }
85   // now n is the index of the first one that is *not* a string.
86
87   // See if there's anything else
88   var prefix
89   switch (n) {
90     // if not, then this is rather simple
91     case pattern.length:
92       this._processSimple(pattern.join('/'), index)
93       return
94
95     case 0:
96       // pattern *starts* with some non-trivial item.
97       // going to readdir(cwd), but not include the prefix in matches.
98       prefix = null
99       break
100
101     default:
102       // pattern has some string bits in the front.
103       // whatever it starts with, whether that's 'absolute' like /foo/bar,
104       // or 'relative' like '../baz'
105       prefix = pattern.slice(0, n).join('/')
106       break
107   }
108
109   var remain = pattern.slice(n)
110
111   // get the list of entries.
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   //if ignored, skip processing
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   // if the abs isn't a dir, then nothing can match!
140   if (!entries)
141     return
142
143   // It will only match dot entries if it starts with a dot, or if
144   // dot is set.  Stuff like @(.foo|.bar) isn't allowed.
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   // If there are no matched entries, then nothing matches.
167   if (len === 0)
168     return
169
170   // if this is the last remaining pattern bit, then no need for
171   // an additional stat *unless* the user has specified mark or
172   // stat explicitly.  We know they exist, since readdir returned
173   // them.
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     // This was the last one, and no stats were needed
194     return
195   }
196
197   // now test all matched entries as stand-ins for that part
198   // of the pattern.
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   // follow all symlinked directories forever
243   // just proceed as if this is a non-globstar situation
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       // lstat failed, doesn't exist
255       return null
256     }
257   }
258
259   var isSym = lstat && lstat.isSymbolicLink()
260   this.symlinks[abs] = isSym
261
262   // If it's not a symlink or a dir, then it's definitely a regular file.
263   // don't bother doing a readdir in that case.
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   // if we haven't asked to stat everything, then just
297   // assume that everything in there exists, so we can avoid
298   // having to stat it a second time.
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   // mark and cache dir-ness
313   return entries
314 }
315
316 GlobSync.prototype._readdirError = function (f, er) {
317   // handle errors, and cache the information
318   switch (er.code) {
319     case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205
320     case 'ENOTDIR': // totally normal. means it *does* exist.
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': // not terribly unusual
332     case 'ELOOP':
333     case 'ENAMETOOLONG':
334     case 'UNKNOWN':
335       this.cache[this._makeAbs(f)] = false
336       break
337
338     default: // some unusual error.  Treat as failure.
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   // no entries means not a dir, so it can never have matches
353   // foo.txt/** doesn't match foo.txt
354   if (!entries)
355     return
356
357   // test without the globstar, and with every child both below
358   // and replacing the globstar.
359   var remainWithoutGlobStar = remain.slice(1)
360   var gspref = prefix ? [ prefix ] : []
361   var noGlobStar = gspref.concat(remainWithoutGlobStar)
362
363   // the noGlobStar pattern exits the inGlobStar state
364   this._process(noGlobStar, index, false)
365
366   var len = entries.length
367   var isSym = this.symlinks[abs]
368
369   // If it's a symlink, and we're in a globstar, then stop
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     // these two cases enter the inGlobStar state
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   // XXX review this.  Shouldn't it be doing the mounting etc
389   // before doing stat?  kinda weird?
390   var exists = this._stat(prefix)
391
392   if (!this.matches[index])
393     this.matches[index] = Object.create(null)
394
395   // If it doesn't exist, then just mark the lack of results
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   // Mark this as a match
414   this._emitMatch(index, prefix)
415 }
416
417 // Returns either 'DIR', 'FILE', or false
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     // It exists, but maybe not how we need it
432     if (!needDir || c === 'DIR')
433       return c
434
435     if (needDir && c === 'FILE')
436       return false
437
438     // otherwise we have to stat, because maybe c=true
439     // if we know it exists, but not what it is.
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 }