~ps-jenkins/ubuntu-push/ubuntu-vivid-proposed

« back to all changes in this revision

Viewing changes to docs/example-server/node_modules/mocha/node_modules/glob/glob.js

  • Committer: Roberto Alsina
  • Date: 2014-09-05 14:57:17 UTC
  • mto: (91.179.25 automatic)
  • mto: This revision was merged to the branch mainline in revision 129.
  • Revision ID: roberto.alsina@canonical.com-20140905145717-0ufcsv27w25i1nnu
added example app server

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Approach:
 
2
//
 
3
// 1. Get the minimatch set
 
4
// 2. For each pattern in the set, PROCESS(pattern)
 
5
// 3. Store matches per-set, then uniq them
 
6
//
 
7
// PROCESS(pattern)
 
8
// Get the first [n] items from pattern that are all strings
 
9
// Join these together.  This is PREFIX.
 
10
//   If there is no more remaining, then stat(PREFIX) and
 
11
//   add to matches if it succeeds.  END.
 
12
// readdir(PREFIX) as ENTRIES
 
13
//   If fails, END
 
14
//   If pattern[n] is GLOBSTAR
 
15
//     // handle the case where the globstar match is empty
 
16
//     // by pruning it out, and testing the resulting pattern
 
17
//     PROCESS(pattern[0..n] + pattern[n+1 .. $])
 
18
//     // handle other cases.
 
19
//     for ENTRY in ENTRIES (not dotfiles)
 
20
//       // attach globstar + tail onto the entry
 
21
//       PROCESS(pattern[0..n] + ENTRY + pattern[n .. $])
 
22
//
 
23
//   else // not globstar
 
24
//     for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)
 
25
//       Test ENTRY against pattern[n]
 
26
//       If fails, continue
 
27
//       If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])
 
28
//
 
29
// Caveat:
 
30
//   Cache all stats and readdirs results to minimize syscall.  Since all
 
31
//   we ever care about is existence and directory-ness, we can just keep
 
32
//   `true` for files, and [children,...] for directories, or `false` for
 
33
//   things that don't exist.
 
34
 
 
35
 
 
36
 
 
37
module.exports = glob
 
38
 
 
39
var fs = require("graceful-fs")
 
40
, minimatch = require("minimatch")
 
41
, Minimatch = minimatch.Minimatch
 
42
, inherits = require("inherits")
 
43
, EE = require("events").EventEmitter
 
44
, path = require("path")
 
45
, isDir = {}
 
46
, assert = require("assert").ok
 
47
 
 
48
function glob (pattern, options, cb) {
 
49
  if (typeof options === "function") cb = options, options = {}
 
50
  if (!options) options = {}
 
51
 
 
52
  if (typeof options === "number") {
 
53
    deprecated()
 
54
    return
 
55
  }
 
56
 
 
57
  var g = new Glob(pattern, options, cb)
 
58
  return g.sync ? g.found : g
 
59
}
 
60
 
 
61
glob.fnmatch = deprecated
 
62
 
 
63
function deprecated () {
 
64
  throw new Error("glob's interface has changed. Please see the docs.")
 
65
}
 
66
 
 
67
glob.sync = globSync
 
68
function globSync (pattern, options) {
 
69
  if (typeof options === "number") {
 
70
    deprecated()
 
71
    return
 
72
  }
 
73
 
 
74
  options = options || {}
 
75
  options.sync = true
 
76
  return glob(pattern, options)
 
77
}
 
78
 
 
79
 
 
80
glob.Glob = Glob
 
81
inherits(Glob, EE)
 
82
function Glob (pattern, options, cb) {
 
83
  if (!(this instanceof Glob)) {
 
84
    return new Glob(pattern, options, cb)
 
85
  }
 
86
 
 
87
  if (typeof cb === "function") {
 
88
    this.on("error", cb)
 
89
    this.on("end", function (matches) {
 
90
      cb(null, matches)
 
91
    })
 
92
  }
 
93
 
 
94
  options = options || {}
 
95
 
 
96
  this.EOF = {}
 
97
  this._emitQueue = []
 
98
 
 
99
  this.maxDepth = options.maxDepth || 1000
 
100
  this.maxLength = options.maxLength || Infinity
 
101
  this.cache = options.cache || {}
 
102
  this.statCache = options.statCache || {}
 
103
 
 
104
  this.changedCwd = false
 
105
  var cwd = process.cwd()
 
106
  if (!options.hasOwnProperty("cwd")) this.cwd = cwd
 
107
  else {
 
108
    this.cwd = options.cwd
 
109
    this.changedCwd = path.resolve(options.cwd) !== cwd
 
110
  }
 
111
 
 
112
  this.root = options.root || path.resolve(this.cwd, "/")
 
113
  this.root = path.resolve(this.root)
 
114
  if (process.platform === "win32")
 
115
    this.root = this.root.replace(/\\/g, "/")
 
116
 
 
117
  this.nomount = !!options.nomount
 
118
 
 
119
  if (!pattern) {
 
120
    throw new Error("must provide pattern")
 
121
  }
 
122
 
 
123
  // base-matching: just use globstar for that.
 
124
  if (options.matchBase && -1 === pattern.indexOf("/")) {
 
125
    if (options.noglobstar) {
 
126
      throw new Error("base matching requires globstar")
 
127
    }
 
128
    pattern = "**/" + pattern
 
129
  }
 
130
 
 
131
  this.strict = options.strict !== false
 
132
  this.dot = !!options.dot
 
133
  this.mark = !!options.mark
 
134
  this.sync = !!options.sync
 
135
  this.nounique = !!options.nounique
 
136
  this.nonull = !!options.nonull
 
137
  this.nosort = !!options.nosort
 
138
  this.nocase = !!options.nocase
 
139
  this.stat = !!options.stat
 
140
 
 
141
  this.debug = !!options.debug || !!options.globDebug
 
142
  if (this.debug)
 
143
    this.log = console.error
 
144
 
 
145
  this.silent = !!options.silent
 
146
 
 
147
  var mm = this.minimatch = new Minimatch(pattern, options)
 
148
  this.options = mm.options
 
149
  pattern = this.pattern = mm.pattern
 
150
 
 
151
  this.error = null
 
152
  this.aborted = false
 
153
 
 
154
  // list of all the patterns that ** has resolved do, so
 
155
  // we can avoid visiting multiple times.
 
156
  this._globstars = {}
 
157
 
 
158
  EE.call(this)
 
159
 
 
160
  // process each pattern in the minimatch set
 
161
  var n = this.minimatch.set.length
 
162
 
 
163
  // The matches are stored as {<filename>: true,...} so that
 
164
  // duplicates are automagically pruned.
 
165
  // Later, we do an Object.keys() on these.
 
166
  // Keep them as a list so we can fill in when nonull is set.
 
167
  this.matches = new Array(n)
 
168
 
 
169
  this.minimatch.set.forEach(iterator.bind(this))
 
170
  function iterator (pattern, i, set) {
 
171
    this._process(pattern, 0, i, function (er) {
 
172
      if (er) this.emit("error", er)
 
173
      if (-- n <= 0) this._finish()
 
174
    })
 
175
  }
 
176
}
 
177
 
 
178
Glob.prototype.log = function () {}
 
179
 
 
180
Glob.prototype._finish = function () {
 
181
  assert(this instanceof Glob)
 
182
 
 
183
  var nou = this.nounique
 
184
  , all = nou ? [] : {}
 
185
 
 
186
  for (var i = 0, l = this.matches.length; i < l; i ++) {
 
187
    var matches = this.matches[i]
 
188
    this.log("matches[%d] =", i, matches)
 
189
    // do like the shell, and spit out the literal glob
 
190
    if (!matches) {
 
191
      if (this.nonull) {
 
192
        var literal = this.minimatch.globSet[i]
 
193
        if (nou) all.push(literal)
 
194
        else all[literal] = true
 
195
      }
 
196
    } else {
 
197
      // had matches
 
198
      var m = Object.keys(matches)
 
199
      if (nou) all.push.apply(all, m)
 
200
      else m.forEach(function (m) {
 
201
        all[m] = true
 
202
      })
 
203
    }
 
204
  }
 
205
 
 
206
  if (!nou) all = Object.keys(all)
 
207
 
 
208
  if (!this.nosort) {
 
209
    all = all.sort(this.nocase ? alphasorti : alphasort)
 
210
  }
 
211
 
 
212
  if (this.mark) {
 
213
    // at *some* point we statted all of these
 
214
    all = all.map(function (m) {
 
215
      var sc = this.cache[m]
 
216
      if (!sc)
 
217
        return m
 
218
      var isDir = (Array.isArray(sc) || sc === 2)
 
219
      if (isDir && m.slice(-1) !== "/") {
 
220
        return m + "/"
 
221
      }
 
222
      if (!isDir && m.slice(-1) === "/") {
 
223
        return m.replace(/\/+$/, "")
 
224
      }
 
225
      return m
 
226
    }, this)
 
227
  }
 
228
 
 
229
  this.log("emitting end", all)
 
230
 
 
231
  this.EOF = this.found = all
 
232
  this.emitMatch(this.EOF)
 
233
}
 
234
 
 
235
function alphasorti (a, b) {
 
236
  a = a.toLowerCase()
 
237
  b = b.toLowerCase()
 
238
  return alphasort(a, b)
 
239
}
 
240
 
 
241
function alphasort (a, b) {
 
242
  return a > b ? 1 : a < b ? -1 : 0
 
243
}
 
244
 
 
245
Glob.prototype.abort = function () {
 
246
  this.aborted = true
 
247
  this.emit("abort")
 
248
}
 
249
 
 
250
Glob.prototype.pause = function () {
 
251
  if (this.paused) return
 
252
  if (this.sync)
 
253
    this.emit("error", new Error("Can't pause/resume sync glob"))
 
254
  this.paused = true
 
255
  this.emit("pause")
 
256
}
 
257
 
 
258
Glob.prototype.resume = function () {
 
259
  if (!this.paused) return
 
260
  if (this.sync)
 
261
    this.emit("error", new Error("Can't pause/resume sync glob"))
 
262
  this.paused = false
 
263
  this.emit("resume")
 
264
  this._processEmitQueue()
 
265
  //process.nextTick(this.emit.bind(this, "resume"))
 
266
}
 
267
 
 
268
Glob.prototype.emitMatch = function (m) {
 
269
  if (!this.stat || this.statCache[m] || m === this.EOF) {
 
270
    this._emitQueue.push(m)
 
271
    this._processEmitQueue()
 
272
  } else {
 
273
    this._stat(m, function(exists, isDir) {
 
274
      if (exists) {
 
275
        this._emitQueue.push(m)
 
276
        this._processEmitQueue()
 
277
      }
 
278
    })
 
279
  }
 
280
}
 
281
 
 
282
Glob.prototype._processEmitQueue = function (m) {
 
283
  while (!this._processingEmitQueue &&
 
284
         !this.paused) {
 
285
    this._processingEmitQueue = true
 
286
    var m = this._emitQueue.shift()
 
287
    if (!m) {
 
288
      this._processingEmitQueue = false
 
289
      break
 
290
    }
 
291
 
 
292
    this.log('emit!', m === this.EOF ? "end" : "match")
 
293
 
 
294
    this.emit(m === this.EOF ? "end" : "match", m)
 
295
    this._processingEmitQueue = false
 
296
  }
 
297
}
 
298
 
 
299
Glob.prototype._process = function (pattern, depth, index, cb_) {
 
300
  assert(this instanceof Glob)
 
301
 
 
302
  var cb = function cb (er, res) {
 
303
    assert(this instanceof Glob)
 
304
    if (this.paused) {
 
305
      if (!this._processQueue) {
 
306
        this._processQueue = []
 
307
        this.once("resume", function () {
 
308
          var q = this._processQueue
 
309
          this._processQueue = null
 
310
          q.forEach(function (cb) { cb() })
 
311
        })
 
312
      }
 
313
      this._processQueue.push(cb_.bind(this, er, res))
 
314
    } else {
 
315
      cb_.call(this, er, res)
 
316
    }
 
317
  }.bind(this)
 
318
 
 
319
  if (this.aborted) return cb()
 
320
 
 
321
  if (depth > this.maxDepth) return cb()
 
322
 
 
323
  // Get the first [n] parts of pattern that are all strings.
 
324
  var n = 0
 
325
  while (typeof pattern[n] === "string") {
 
326
    n ++
 
327
  }
 
328
  // now n is the index of the first one that is *not* a string.
 
329
 
 
330
  // see if there's anything else
 
331
  var prefix
 
332
  switch (n) {
 
333
    // if not, then this is rather simple
 
334
    case pattern.length:
 
335
      prefix = pattern.join("/")
 
336
      this._stat(prefix, function (exists, isDir) {
 
337
        // either it's there, or it isn't.
 
338
        // nothing more to do, either way.
 
339
        if (exists) {
 
340
          if (prefix && isAbsolute(prefix) && !this.nomount) {
 
341
            if (prefix.charAt(0) === "/") {
 
342
              prefix = path.join(this.root, prefix)
 
343
            } else {
 
344
              prefix = path.resolve(this.root, prefix)
 
345
            }
 
346
          }
 
347
 
 
348
          if (process.platform === "win32")
 
349
            prefix = prefix.replace(/\\/g, "/")
 
350
 
 
351
          this.matches[index] = this.matches[index] || {}
 
352
          this.matches[index][prefix] = true
 
353
          this.emitMatch(prefix)
 
354
        }
 
355
        return cb()
 
356
      })
 
357
      return
 
358
 
 
359
    case 0:
 
360
      // pattern *starts* with some non-trivial item.
 
361
      // going to readdir(cwd), but not include the prefix in matches.
 
362
      prefix = null
 
363
      break
 
364
 
 
365
    default:
 
366
      // pattern has some string bits in the front.
 
367
      // whatever it starts with, whether that's "absolute" like /foo/bar,
 
368
      // or "relative" like "../baz"
 
369
      prefix = pattern.slice(0, n)
 
370
      prefix = prefix.join("/")
 
371
      break
 
372
  }
 
373
 
 
374
  // get the list of entries.
 
375
  var read
 
376
  if (prefix === null) read = "."
 
377
  else if (isAbsolute(prefix) || isAbsolute(pattern.join("/"))) {
 
378
    if (!prefix || !isAbsolute(prefix)) {
 
379
      prefix = path.join("/", prefix)
 
380
    }
 
381
    read = prefix = path.resolve(prefix)
 
382
 
 
383
    // if (process.platform === "win32")
 
384
    //   read = prefix = prefix.replace(/^[a-zA-Z]:|\\/g, "/")
 
385
 
 
386
    this.log('absolute: ', prefix, this.root, pattern, read)
 
387
  } else {
 
388
    read = prefix
 
389
  }
 
390
 
 
391
  this.log('readdir(%j)', read, this.cwd, this.root)
 
392
 
 
393
  return this._readdir(read, function (er, entries) {
 
394
    if (er) {
 
395
      // not a directory!
 
396
      // this means that, whatever else comes after this, it can never match
 
397
      return cb()
 
398
    }
 
399
 
 
400
    // globstar is special
 
401
    if (pattern[n] === minimatch.GLOBSTAR) {
 
402
      // test without the globstar, and with every child both below
 
403
      // and replacing the globstar.
 
404
      var s = [ pattern.slice(0, n).concat(pattern.slice(n + 1)) ]
 
405
      entries.forEach(function (e) {
 
406
        if (e.charAt(0) === "." && !this.dot) return
 
407
        // instead of the globstar
 
408
        s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1)))
 
409
        // below the globstar
 
410
        s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n)))
 
411
      }, this)
 
412
 
 
413
      s = s.filter(function (pattern) {
 
414
        var key = gsKey(pattern)
 
415
        var seen = !this._globstars[key]
 
416
        this._globstars[key] = true
 
417
        return seen
 
418
      }, this)
 
419
 
 
420
      if (!s.length)
 
421
        return cb()
 
422
 
 
423
      // now asyncForEach over this
 
424
      var l = s.length
 
425
      , errState = null
 
426
      s.forEach(function (gsPattern) {
 
427
        this._process(gsPattern, depth + 1, index, function (er) {
 
428
          if (errState) return
 
429
          if (er) return cb(errState = er)
 
430
          if (--l <= 0) return cb()
 
431
        })
 
432
      }, this)
 
433
 
 
434
      return
 
435
    }
 
436
 
 
437
    // not a globstar
 
438
    // It will only match dot entries if it starts with a dot, or if
 
439
    // dot is set.  Stuff like @(.foo|.bar) isn't allowed.
 
440
    var pn = pattern[n]
 
441
    var rawGlob = pattern[n]._glob
 
442
    , dotOk = this.dot || rawGlob.charAt(0) === "."
 
443
 
 
444
    entries = entries.filter(function (e) {
 
445
      return (e.charAt(0) !== "." || dotOk) &&
 
446
             e.match(pattern[n])
 
447
    })
 
448
 
 
449
    // If n === pattern.length - 1, then there's no need for the extra stat
 
450
    // *unless* the user has specified "mark" or "stat" explicitly.
 
451
    // We know that they exist, since the readdir returned them.
 
452
    if (n === pattern.length - 1 &&
 
453
        !this.mark &&
 
454
        !this.stat) {
 
455
      entries.forEach(function (e) {
 
456
        if (prefix) {
 
457
          if (prefix !== "/") e = prefix + "/" + e
 
458
          else e = prefix + e
 
459
        }
 
460
        if (e.charAt(0) === "/" && !this.nomount) {
 
461
          e = path.join(this.root, e)
 
462
        }
 
463
 
 
464
        if (process.platform === "win32")
 
465
          e = e.replace(/\\/g, "/")
 
466
 
 
467
        this.matches[index] = this.matches[index] || {}
 
468
        this.matches[index][e] = true
 
469
        this.emitMatch(e)
 
470
      }, this)
 
471
      return cb.call(this)
 
472
    }
 
473
 
 
474
 
 
475
    // now test all the remaining entries as stand-ins for that part
 
476
    // of the pattern.
 
477
    var l = entries.length
 
478
    , errState = null
 
479
    if (l === 0) return cb() // no matches possible
 
480
    entries.forEach(function (e) {
 
481
      var p = pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1))
 
482
      this._process(p, depth + 1, index, function (er) {
 
483
        if (errState) return
 
484
        if (er) return cb(errState = er)
 
485
        if (--l === 0) return cb.call(this)
 
486
      })
 
487
    }, this)
 
488
  })
 
489
 
 
490
}
 
491
 
 
492
function gsKey (pattern) {
 
493
  return '**' + pattern.map(function (p) {
 
494
    return (p === minimatch.GLOBSTAR) ? '**' : (''+p)
 
495
  }).join('/')
 
496
}
 
497
 
 
498
Glob.prototype._stat = function (f, cb) {
 
499
  assert(this instanceof Glob)
 
500
  var abs = f
 
501
  if (f.charAt(0) === "/") {
 
502
    abs = path.join(this.root, f)
 
503
  } else if (this.changedCwd) {
 
504
    abs = path.resolve(this.cwd, f)
 
505
  }
 
506
 
 
507
  if (f.length > this.maxLength) {
 
508
    var er = new Error("Path name too long")
 
509
    er.code = "ENAMETOOLONG"
 
510
    er.path = f
 
511
    return this._afterStat(f, abs, cb, er)
 
512
  }
 
513
 
 
514
  this.log('stat', [this.cwd, f, '=', abs])
 
515
 
 
516
  if (!this.stat && this.cache.hasOwnProperty(f)) {
 
517
    var exists = this.cache[f]
 
518
    , isDir = exists && (Array.isArray(exists) || exists === 2)
 
519
    if (this.sync) return cb.call(this, !!exists, isDir)
 
520
    return process.nextTick(cb.bind(this, !!exists, isDir))
 
521
  }
 
522
 
 
523
  var stat = this.statCache[abs]
 
524
  if (this.sync || stat) {
 
525
    var er
 
526
    try {
 
527
      stat = fs.statSync(abs)
 
528
    } catch (e) {
 
529
      er = e
 
530
    }
 
531
    this._afterStat(f, abs, cb, er, stat)
 
532
  } else {
 
533
    fs.stat(abs, this._afterStat.bind(this, f, abs, cb))
 
534
  }
 
535
}
 
536
 
 
537
Glob.prototype._afterStat = function (f, abs, cb, er, stat) {
 
538
  var exists
 
539
  assert(this instanceof Glob)
 
540
 
 
541
  if (abs.slice(-1) === "/" && stat && !stat.isDirectory()) {
 
542
    this.log("should be ENOTDIR, fake it")
 
543
 
 
544
    er = new Error("ENOTDIR, not a directory '" + abs + "'")
 
545
    er.path = abs
 
546
    er.code = "ENOTDIR"
 
547
    stat = null
 
548
  }
 
549
 
 
550
  var emit = !this.statCache[abs]
 
551
  this.statCache[abs] = stat
 
552
 
 
553
  if (er || !stat) {
 
554
    exists = false
 
555
  } else {
 
556
    exists = stat.isDirectory() ? 2 : 1
 
557
    if (emit)
 
558
      this.emit('stat', f, stat)
 
559
  }
 
560
  this.cache[f] = this.cache[f] || exists
 
561
  cb.call(this, !!exists, exists === 2)
 
562
}
 
563
 
 
564
Glob.prototype._readdir = function (f, cb) {
 
565
  assert(this instanceof Glob)
 
566
  var abs = f
 
567
  if (f.charAt(0) === "/") {
 
568
    abs = path.join(this.root, f)
 
569
  } else if (isAbsolute(f)) {
 
570
    abs = f
 
571
  } else if (this.changedCwd) {
 
572
    abs = path.resolve(this.cwd, f)
 
573
  }
 
574
 
 
575
  if (f.length > this.maxLength) {
 
576
    var er = new Error("Path name too long")
 
577
    er.code = "ENAMETOOLONG"
 
578
    er.path = f
 
579
    return this._afterReaddir(f, abs, cb, er)
 
580
  }
 
581
 
 
582
  this.log('readdir', [this.cwd, f, abs])
 
583
  if (this.cache.hasOwnProperty(f)) {
 
584
    var c = this.cache[f]
 
585
    if (Array.isArray(c)) {
 
586
      if (this.sync) return cb.call(this, null, c)
 
587
      return process.nextTick(cb.bind(this, null, c))
 
588
    }
 
589
 
 
590
    if (!c || c === 1) {
 
591
      // either ENOENT or ENOTDIR
 
592
      var code = c ? "ENOTDIR" : "ENOENT"
 
593
      , er = new Error((c ? "Not a directory" : "Not found") + ": " + f)
 
594
      er.path = f
 
595
      er.code = code
 
596
      this.log(f, er)
 
597
      if (this.sync) return cb.call(this, er)
 
598
      return process.nextTick(cb.bind(this, er))
 
599
    }
 
600
 
 
601
    // at this point, c === 2, meaning it's a dir, but we haven't
 
602
    // had to read it yet, or c === true, meaning it's *something*
 
603
    // but we don't have any idea what.  Need to read it, either way.
 
604
  }
 
605
 
 
606
  if (this.sync) {
 
607
    var er, entries
 
608
    try {
 
609
      entries = fs.readdirSync(abs)
 
610
    } catch (e) {
 
611
      er = e
 
612
    }
 
613
    return this._afterReaddir(f, abs, cb, er, entries)
 
614
  }
 
615
 
 
616
  fs.readdir(abs, this._afterReaddir.bind(this, f, abs, cb))
 
617
}
 
618
 
 
619
Glob.prototype._afterReaddir = function (f, abs, cb, er, entries) {
 
620
  assert(this instanceof Glob)
 
621
  if (entries && !er) {
 
622
    this.cache[f] = entries
 
623
    // if we haven't asked to stat everything for suresies, then just
 
624
    // assume that everything in there exists, so we can avoid
 
625
    // having to stat it a second time.  This also gets us one step
 
626
    // further into ELOOP territory.
 
627
    if (!this.mark && !this.stat) {
 
628
      entries.forEach(function (e) {
 
629
        if (f === "/") e = f + e
 
630
        else e = f + "/" + e
 
631
        this.cache[e] = true
 
632
      }, this)
 
633
    }
 
634
 
 
635
    return cb.call(this, er, entries)
 
636
  }
 
637
 
 
638
  // now handle errors, and cache the information
 
639
  if (er) switch (er.code) {
 
640
    case "ENOTDIR": // totally normal. means it *does* exist.
 
641
      this.cache[f] = 1
 
642
      return cb.call(this, er)
 
643
    case "ENOENT": // not terribly unusual
 
644
    case "ELOOP":
 
645
    case "ENAMETOOLONG":
 
646
    case "UNKNOWN":
 
647
      this.cache[f] = false
 
648
      return cb.call(this, er)
 
649
    default: // some unusual error.  Treat as failure.
 
650
      this.cache[f] = false
 
651
      if (this.strict) this.emit("error", er)
 
652
      if (!this.silent) console.error("glob error", er)
 
653
      return cb.call(this, er)
 
654
  }
 
655
}
 
656
 
 
657
var isAbsolute = process.platform === "win32" ? absWin : absUnix
 
658
 
 
659
function absWin (p) {
 
660
  if (absUnix(p)) return true
 
661
  // pull off the device/UNC bit from a windows path.
 
662
  // from node's lib/path.js
 
663
  var splitDeviceRe =
 
664
      /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/
 
665
    , result = splitDeviceRe.exec(p)
 
666
    , device = result[1] || ''
 
667
    , isUnc = device && device.charAt(1) !== ':'
 
668
    , isAbsolute = !!result[2] || isUnc // UNC paths are always absolute
 
669
 
 
670
  return isAbsolute
 
671
}
 
672
 
 
673
function absUnix (p) {
 
674
  return p.charAt(0) === "/" || p === ""
 
675
}