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
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
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 .. $])
23 // else // not globstar
24 // for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)
25 // Test ENTRY against pattern[n]
27 // If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])
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.
39 var fs = require("fs")
40 , minimatch = require("minimatch")
41 , Minimatch = minimatch.Minimatch
42 , inherits = require("inherits")
43 , EE = require("events").EventEmitter
44 , path = require("path")
46 , assert = require("assert").ok
48 function glob (pattern, options, cb) {
49 if (typeof options === "function") cb = options, options = {}
50 if (!options) options = {}
52 if (typeof options === "number") {
57 var g = new Glob(pattern, options, cb)
58 return g.sync ? g.found : g
61 glob.fnmatch = deprecated
63 function deprecated () {
64 throw new Error("glob's interface has changed. Please see the docs.")
68 function globSync (pattern, options) {
69 if (typeof options === "number") {
74 options = options || {}
76 return glob(pattern, options)
79 this._processingEmitQueue = false
83 function Glob (pattern, options, cb) {
84 if (!(this instanceof Glob)) {
85 return new Glob(pattern, options, cb)
88 if (typeof options === "function") {
93 if (typeof cb === "function") {
95 this.on("end", function (matches) {
100 options = options || {}
102 this._endEmitted = false
107 this._processingEmitQueue = false
109 this.maxDepth = options.maxDepth || 1000
110 this.maxLength = options.maxLength || Infinity
111 this.cache = options.cache || {}
112 this.statCache = options.statCache || {}
114 this.changedCwd = false
115 var cwd = process.cwd()
116 if (!options.hasOwnProperty("cwd")) this.cwd = cwd
118 this.cwd = options.cwd
119 this.changedCwd = path.resolve(options.cwd) !== cwd
122 this.root = options.root || path.resolve(this.cwd, "/")
123 this.root = path.resolve(this.root)
124 if (process.platform === "win32")
125 this.root = this.root.replace(/\\/g, "/")
127 this.nomount = !!options.nomount
130 throw new Error("must provide pattern")
133 // base-matching: just use globstar for that.
134 if (options.matchBase && -1 === pattern.indexOf("/")) {
135 if (options.noglobstar) {
136 throw new Error("base matching requires globstar")
138 pattern = "**/" + pattern
141 this.strict = options.strict !== false
142 this.dot = !!options.dot
143 this.mark = !!options.mark
144 this.sync = !!options.sync
145 this.nounique = !!options.nounique
146 this.nonull = !!options.nonull
147 this.nosort = !!options.nosort
148 this.nocase = !!options.nocase
149 this.stat = !!options.stat
151 this.debug = !!options.debug || !!options.globDebug
153 this.log = console.error
155 this.silent = !!options.silent
157 var mm = this.minimatch = new Minimatch(pattern, options)
158 this.options = mm.options
159 pattern = this.pattern = mm.pattern
164 // list of all the patterns that ** has resolved do, so
165 // we can avoid visiting multiple times.
170 // process each pattern in the minimatch set
171 var n = this.minimatch.set.length
173 // The matches are stored as {<filename>: true,...} so that
174 // duplicates are automagically pruned.
175 // Later, we do an Object.keys() on these.
176 // Keep them as a list so we can fill in when nonull is set.
177 this.matches = new Array(n)
179 this.minimatch.set.forEach(iterator.bind(this))
180 function iterator (pattern, i, set) {
181 this._process(pattern, 0, i, function (er) {
182 if (er) this.emit("error", er)
183 if (-- n <= 0) this._finish()
188 Glob.prototype.log = function () {}
190 Glob.prototype._finish = function () {
191 assert(this instanceof Glob)
193 var nou = this.nounique
194 , all = nou ? [] : {}
196 for (var i = 0, l = this.matches.length; i < l; i ++) {
197 var matches = this.matches[i]
198 this.log("matches[%d] =", i, matches)
199 // do like the shell, and spit out the literal glob
202 var literal = this.minimatch.globSet[i]
203 if (nou) all.push(literal)
204 else all[literal] = true
208 var m = Object.keys(matches)
209 if (nou) all.push.apply(all, m)
210 else m.forEach(function (m) {
216 if (!nou) all = Object.keys(all)
219 all = all.sort(this.nocase ? alphasorti : alphasort)
223 // at *some* point we statted all of these
224 all = all.map(this._mark, this)
227 this.log("emitting end", all)
229 this.EOF = this.found = all
230 this.emitMatch(this.EOF)
233 function alphasorti (a, b) {
236 return alphasort(a, b)
239 function alphasort (a, b) {
240 return a > b ? 1 : a < b ? -1 : 0
243 Glob.prototype._mark = function (p) {
244 var c = this.cache[p]
247 var isDir = c === 2 || Array.isArray(c)
248 var slash = p.slice(-1) === '/'
252 else if (!isDir && slash)
256 this.statCache[m] = this.statCache[p]
257 this.cache[m] = this.cache[p]
264 Glob.prototype.abort = function () {
269 Glob.prototype.pause = function () {
270 if (this.paused) return
272 this.emit("error", new Error("Can't pause/resume sync glob"))
277 Glob.prototype.resume = function () {
278 if (!this.paused) return
280 this.emit("error", new Error("Can't pause/resume sync glob"))
283 this._processEmitQueue()
284 //process.nextTick(this.emit.bind(this, "resume"))
287 Glob.prototype.emitMatch = function (m) {
288 this.log('emitMatch', m)
289 this._emitQueue.push(m)
290 this._processEmitQueue()
293 Glob.prototype._processEmitQueue = function (m) {
294 this.log("pEQ paused=%j processing=%j m=%j", this.paused,
295 this._processingEmitQueue, m)
297 while (!this._processingEmitQueue &&
299 this._processingEmitQueue = true
300 var m = this._emitQueue.shift()
301 this.log(">processEmitQueue", m === this.EOF ? ":EOF:" : m)
303 this.log(">processEmitQueue, falsey m")
304 this._processingEmitQueue = false
308 if (m === this.EOF || !(this.mark && !this.stat)) {
309 this.log("peq: unmarked, or eof")
310 next.call(this, 0, false)
311 } else if (this.statCache[m]) {
312 var sc = this.statCache[m]
315 exists = sc.isDirectory() ? 2 : 1
316 this.log("peq: stat cached")
317 next.call(this, exists, exists === 2)
319 this.log("peq: _stat, then next")
323 function next(exists, isDir) {
324 this.log("next", m, exists, isDir)
325 var ev = m === this.EOF ? "end" : "match"
327 // "end" can only happen once.
328 assert(!this._endEmitted)
330 this._endEmitted = true
333 // Doesn't mean it necessarily doesn't exist, it's possible
334 // we just didn't check because we don't care that much, or
335 // this is EOF anyway.
336 if (isDir && !m.match(/\/$/)) {
338 } else if (!isDir && m.match(/\/$/)) {
339 m = m.replace(/\/+$/, "")
342 this.log("emit", ev, m)
344 this._processingEmitQueue = false
345 if (done && m !== this.EOF && !this.paused)
346 this._processEmitQueue()
352 Glob.prototype._process = function (pattern, depth, index, cb_) {
353 assert(this instanceof Glob)
355 var cb = function cb (er, res) {
356 assert(this instanceof Glob)
358 if (!this._processQueue) {
359 this._processQueue = []
360 this.once("resume", function () {
361 var q = this._processQueue
362 this._processQueue = null
363 q.forEach(function (cb) { cb() })
366 this._processQueue.push(cb_.bind(this, er, res))
368 cb_.call(this, er, res)
372 if (this.aborted) return cb()
374 if (depth > this.maxDepth) return cb()
376 // Get the first [n] parts of pattern that are all strings.
378 while (typeof pattern[n] === "string") {
381 // now n is the index of the first one that is *not* a string.
383 // see if there's anything else
386 // if not, then this is rather simple
388 prefix = pattern.join("/")
389 this._stat(prefix, function (exists, isDir) {
390 // either it's there, or it isn't.
391 // nothing more to do, either way.
393 if (prefix && isAbsolute(prefix) && !this.nomount) {
394 if (prefix.charAt(0) === "/") {
395 prefix = path.join(this.root, prefix)
397 prefix = path.resolve(this.root, prefix)
401 if (process.platform === "win32")
402 prefix = prefix.replace(/\\/g, "/")
404 this.matches[index] = this.matches[index] || {}
405 this.matches[index][prefix] = true
406 this.emitMatch(prefix)
413 // pattern *starts* with some non-trivial item.
414 // going to readdir(cwd), but not include the prefix in matches.
419 // pattern has some string bits in the front.
420 // whatever it starts with, whether that's "absolute" like /foo/bar,
421 // or "relative" like "../baz"
422 prefix = pattern.slice(0, n)
423 prefix = prefix.join("/")
427 // get the list of entries.
429 if (prefix === null) read = "."
430 else if (isAbsolute(prefix) || isAbsolute(pattern.join("/"))) {
431 if (!prefix || !isAbsolute(prefix)) {
432 prefix = path.join("/", prefix)
434 read = prefix = path.resolve(prefix)
436 // if (process.platform === "win32")
437 // read = prefix = prefix.replace(/^[a-zA-Z]:|\\/g, "/")
439 this.log('absolute: ', prefix, this.root, pattern, read)
444 this.log('readdir(%j)', read, this.cwd, this.root)
446 return this._readdir(read, function (er, entries) {
449 // this means that, whatever else comes after this, it can never match
453 // globstar is special
454 if (pattern[n] === minimatch.GLOBSTAR) {
455 // test without the globstar, and with every child both below
456 // and replacing the globstar.
457 var s = [ pattern.slice(0, n).concat(pattern.slice(n + 1)) ]
458 entries.forEach(function (e) {
459 if (e.charAt(0) === "." && !this.dot) return
460 // instead of the globstar
461 s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1)))
462 // below the globstar
463 s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n)))
466 s = s.filter(function (pattern) {
467 var key = gsKey(pattern)
468 var seen = !this._globstars[key]
469 this._globstars[key] = true
476 // now asyncForEach over this
479 s.forEach(function (gsPattern) {
480 this._process(gsPattern, depth + 1, index, function (er) {
482 if (er) return cb(errState = er)
483 if (--l <= 0) return cb()
491 // It will only match dot entries if it starts with a dot, or if
492 // dot is set. Stuff like @(.foo|.bar) isn't allowed.
494 var rawGlob = pattern[n]._glob
495 , dotOk = this.dot || rawGlob.charAt(0) === "."
497 entries = entries.filter(function (e) {
498 return (e.charAt(0) !== "." || dotOk) &&
502 // If n === pattern.length - 1, then there's no need for the extra stat
503 // *unless* the user has specified "mark" or "stat" explicitly.
504 // We know that they exist, since the readdir returned them.
505 if (n === pattern.length - 1 &&
508 entries.forEach(function (e) {
510 if (prefix !== "/") e = prefix + "/" + e
513 if (e.charAt(0) === "/" && !this.nomount) {
514 e = path.join(this.root, e)
517 if (process.platform === "win32")
518 e = e.replace(/\\/g, "/")
520 this.matches[index] = this.matches[index] || {}
521 this.matches[index][e] = true
528 // now test all the remaining entries as stand-ins for that part
530 var l = entries.length
532 if (l === 0) return cb() // no matches possible
533 entries.forEach(function (e) {
534 var p = pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1))
535 this._process(p, depth + 1, index, function (er) {
537 if (er) return cb(errState = er)
538 if (--l === 0) return cb.call(this)
545 function gsKey (pattern) {
546 return '**' + pattern.map(function (p) {
547 return (p === minimatch.GLOBSTAR) ? '**' : (''+p)
551 Glob.prototype._stat = function (f, cb) {
552 assert(this instanceof Glob)
554 if (f.charAt(0) === "/") {
555 abs = path.join(this.root, f)
556 } else if (this.changedCwd) {
557 abs = path.resolve(this.cwd, f)
560 if (f.length > this.maxLength) {
561 var er = new Error("Path name too long")
562 er.code = "ENAMETOOLONG"
564 return this._afterStat(f, abs, cb, er)
567 this.log('stat', [this.cwd, f, '=', abs])
569 if (!this.stat && this.cache.hasOwnProperty(f)) {
570 var exists = this.cache[f]
571 , isDir = exists && (Array.isArray(exists) || exists === 2)
572 if (this.sync) return cb.call(this, !!exists, isDir)
573 return process.nextTick(cb.bind(this, !!exists, isDir))
576 var stat = this.statCache[abs]
577 if (this.sync || stat) {
580 stat = fs.statSync(abs)
584 this._afterStat(f, abs, cb, er, stat)
586 fs.stat(abs, this._afterStat.bind(this, f, abs, cb))
590 Glob.prototype._afterStat = function (f, abs, cb, er, stat) {
592 assert(this instanceof Glob)
594 if (abs.slice(-1) === "/" && stat && !stat.isDirectory()) {
595 this.log("should be ENOTDIR, fake it")
597 er = new Error("ENOTDIR, not a directory '" + abs + "'")
603 var emit = !this.statCache[abs]
604 this.statCache[abs] = stat
609 exists = stat.isDirectory() ? 2 : 1
611 this.emit('stat', f, stat)
613 this.cache[f] = this.cache[f] || exists
614 cb.call(this, !!exists, exists === 2)
617 Glob.prototype._readdir = function (f, cb) {
618 assert(this instanceof Glob)
620 if (f.charAt(0) === "/") {
621 abs = path.join(this.root, f)
622 } else if (isAbsolute(f)) {
624 } else if (this.changedCwd) {
625 abs = path.resolve(this.cwd, f)
628 if (f.length > this.maxLength) {
629 var er = new Error("Path name too long")
630 er.code = "ENAMETOOLONG"
632 return this._afterReaddir(f, abs, cb, er)
635 this.log('readdir', [this.cwd, f, abs])
636 if (this.cache.hasOwnProperty(f)) {
637 var c = this.cache[f]
638 if (Array.isArray(c)) {
639 if (this.sync) return cb.call(this, null, c)
640 return process.nextTick(cb.bind(this, null, c))
644 // either ENOENT or ENOTDIR
645 var code = c ? "ENOTDIR" : "ENOENT"
646 , er = new Error((c ? "Not a directory" : "Not found") + ": " + f)
650 if (this.sync) return cb.call(this, er)
651 return process.nextTick(cb.bind(this, er))
654 // at this point, c === 2, meaning it's a dir, but we haven't
655 // had to read it yet, or c === true, meaning it's *something*
656 // but we don't have any idea what. Need to read it, either way.
662 entries = fs.readdirSync(abs)
666 return this._afterReaddir(f, abs, cb, er, entries)
669 fs.readdir(abs, this._afterReaddir.bind(this, f, abs, cb))
672 Glob.prototype._afterReaddir = function (f, abs, cb, er, entries) {
673 assert(this instanceof Glob)
674 if (entries && !er) {
675 this.cache[f] = entries
676 // if we haven't asked to stat everything for suresies, then just
677 // assume that everything in there exists, so we can avoid
678 // having to stat it a second time. This also gets us one step
679 // further into ELOOP territory.
680 if (!this.mark && !this.stat) {
681 entries.forEach(function (e) {
682 if (f === "/") e = f + e
688 return cb.call(this, er, entries)
691 // now handle errors, and cache the information
692 if (er) switch (er.code) {
693 case "ENOTDIR": // totally normal. means it *does* exist.
695 return cb.call(this, er)
696 case "ENOENT": // not terribly unusual
700 this.cache[f] = false
701 return cb.call(this, er)
702 default: // some unusual error. Treat as failure.
703 this.cache[f] = false
704 if (this.strict) this.emit("error", er)
705 if (!this.silent) console.error("glob error", er)
706 return cb.call(this, er)
710 var isAbsolute = process.platform === "win32" ? absWin : absUnix
712 function absWin (p) {
713 if (absUnix(p)) return true
714 // pull off the device/UNC bit from a windows path.
715 // from node's lib/path.js
717 /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/
718 , result = splitDeviceRe.exec(p)
719 , device = result[1] || ''
720 , isUnc = device && device.charAt(1) !== ':'
721 , isAbsolute = !!result[2] || isUnc // UNC paths are always absolute
726 function absUnix (p) {
727 return p.charAt(0) === "/" || p === ""