mirror of
https://github.com/electron/node-gyp.git
synced 2025-09-17 22:33:40 +02:00
Update bundled node-glob.
This commit is contained in:
parent
a29d3f7d5f
commit
a35dd339c6
28 changed files with 2538 additions and 329 deletions
732
node_modules/glob/glob.js
generated
vendored
732
node_modules/glob/glob.js
generated
vendored
|
@ -1,3 +1,39 @@
|
|||
// Approach:
|
||||
//
|
||||
// 1. Get the minimatch set
|
||||
// 2. For each pattern in the set, PROCESS(pattern)
|
||||
// 3. Store matches per-set, then uniq them
|
||||
//
|
||||
// PROCESS(pattern)
|
||||
// Get the first [n] items from pattern that are all strings
|
||||
// Join these together. This is PREFIX.
|
||||
// If there is no more remaining, then stat(PREFIX) and
|
||||
// add to matches if it succeeds. END.
|
||||
// readdir(PREFIX) as ENTRIES
|
||||
// If fails, END
|
||||
// If pattern[n] is GLOBSTAR
|
||||
// // handle the case where the globstar match is empty
|
||||
// // by pruning it out, and testing the resulting pattern
|
||||
// PROCESS(pattern[0..n] + pattern[n+1 .. $])
|
||||
// // handle other cases.
|
||||
// for ENTRY in ENTRIES (not dotfiles)
|
||||
// // attach globstar + tail onto the entry
|
||||
// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $])
|
||||
//
|
||||
// else // not globstar
|
||||
// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)
|
||||
// Test ENTRY against pattern[n+1]
|
||||
// If fails, continue
|
||||
// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])
|
||||
//
|
||||
// Caveat:
|
||||
// Cache all stats and readdirs results to minimize syscall. Since all
|
||||
// we ever care about is existence and directory-ness, we can just keep
|
||||
// `true` for files, and [children,...] for directories, or `false` for
|
||||
// things that don't exist.
|
||||
|
||||
|
||||
|
||||
module.exports = glob
|
||||
|
||||
var fs = require("graceful-fs")
|
||||
|
@ -5,27 +41,9 @@ var fs = require("graceful-fs")
|
|||
, Minimatch = minimatch.Minimatch
|
||||
, inherits = require("inherits")
|
||||
, EE = require("events").EventEmitter
|
||||
, FastList = require("fast-list")
|
||||
, path = require("path")
|
||||
, isDir = {}
|
||||
|
||||
// Globbing is a *little* bit different than just matching, in some
|
||||
// key ways.
|
||||
//
|
||||
// First, and importantly, it matters a great deal whether a pattern
|
||||
// is "absolute" or "relative". Absolute patterns are patterns that
|
||||
// start with / on unix, or a full device/unc path on windows.
|
||||
//
|
||||
// Second, globs interact with the actual filesystem, so being able
|
||||
// to stop searching as soon as a match is no longer possible is of
|
||||
// the utmost importance. It would not do to traverse a large file
|
||||
// tree, and then eliminate all but one of the options, if it could
|
||||
// be possible to skip the traversal early.
|
||||
|
||||
// Get a Minimatch object from the pattern and options. Then, starting
|
||||
// from the options.root or the cwd, read the dir, and do a partial
|
||||
// match on all the files if it's a dir, or a regular match if it's not.
|
||||
|
||||
, assert = require("assert")
|
||||
|
||||
function glob (pattern, options, cb) {
|
||||
if (typeof options === "function") cb = options, options = {}
|
||||
|
@ -36,13 +54,8 @@ function glob (pattern, options, cb) {
|
|||
return
|
||||
}
|
||||
|
||||
var m = new Glob(pattern, options, cb)
|
||||
|
||||
if (options.sync) {
|
||||
return m.found
|
||||
} else {
|
||||
return m
|
||||
}
|
||||
var g = new Glob(pattern, options, cb)
|
||||
return g.sync ? g.found : g
|
||||
}
|
||||
|
||||
glob.fnmatch = deprecated
|
||||
|
@ -73,330 +86,457 @@ function Glob (pattern, options, cb) {
|
|||
|
||||
if (typeof cb === "function") {
|
||||
this.on("error", cb)
|
||||
this.on("end", function (matches) { cb(null, matches) })
|
||||
this.on("end", function (matches) {
|
||||
// console.error("cb with matches", matches)
|
||||
cb(null, matches)
|
||||
})
|
||||
}
|
||||
|
||||
options = options || {}
|
||||
|
||||
if (!options.hasOwnProperty("maxDepth")) options.maxDepth = 1000
|
||||
if (!options.hasOwnProperty("maxLength")) options.maxLength = 4096
|
||||
this.maxDepth = options.maxDepth || 1000
|
||||
this.maxLength = options.maxLength || Infinity
|
||||
this.statCache = options.statCache || {}
|
||||
|
||||
var cwd = this.cwd = options.cwd =
|
||||
options.cwd || process.cwd()
|
||||
this.changedCwd = false
|
||||
var cwd = process.cwd()
|
||||
if (!options.hasOwnProperty("cwd")) this.cwd = cwd
|
||||
else {
|
||||
this.cwd = options.cwd
|
||||
this.changedCwd = path.resolve(options.cwd) !== cwd
|
||||
}
|
||||
|
||||
this.root = options.root =
|
||||
options.root || path.resolve(cwd, "/")
|
||||
this.root = options.root || path.resolve(this.cwd, "/")
|
||||
this.root = path.resolve(this.root)
|
||||
|
||||
this.nomount = !!options.nomount
|
||||
|
||||
if (!pattern) {
|
||||
throw new Error("must provide pattern")
|
||||
}
|
||||
|
||||
// base-matching: just use globstar for that.
|
||||
if (options.matchBase && -1 === pattern.indexOf("/")) {
|
||||
if (options.noglobstar) {
|
||||
throw new Error("base matching requires globstar")
|
||||
}
|
||||
pattern = "**/" + pattern
|
||||
}
|
||||
|
||||
this.dot = !!options.dot
|
||||
this.mark = !!options.mark
|
||||
this.sync = !!options.sync
|
||||
this.nounique = !!options.nounique
|
||||
this.nonull = !!options.nonull
|
||||
this.nosort = !!options.nosort
|
||||
this.nocase = !!options.nocase
|
||||
this.stat = !!options.stat
|
||||
this.debug = !!options.debug || !!options.globDebug
|
||||
this.silent = !!options.silent
|
||||
|
||||
var mm = this.minimatch = new Minimatch(pattern, options)
|
||||
options = this.options = mm.options
|
||||
this.options = mm.options
|
||||
pattern = this.pattern = mm.pattern
|
||||
|
||||
this.error = null
|
||||
this.aborted = false
|
||||
|
||||
this.matches = new FastList()
|
||||
EE.call(this)
|
||||
var me = this
|
||||
|
||||
this._checkedRoot = false
|
||||
// process each pattern in the minimatch set
|
||||
var n = this.minimatch.set.length
|
||||
|
||||
// if we have any patterns starting with /, then we need to
|
||||
// start at the root. If we don't, then we can take a short
|
||||
// cut and just start at the cwd.
|
||||
var start = this.cwd
|
||||
for (var i = 0, l = this.minimatch.set.length; i < l; i ++) {
|
||||
if (this.minimatch.set[i].absolute) {
|
||||
start = this.root
|
||||
break
|
||||
}
|
||||
// The matches are stored as {<filename>: true,...} so that
|
||||
// duplicates are automagically pruned.
|
||||
// Later, we do an Object.keys() on these.
|
||||
// Keep them as a list so we can fill in when nonull is set.
|
||||
this.matches = new Array(n)
|
||||
|
||||
this.minimatch.set.forEach(iterator.bind(this))
|
||||
function iterator (pattern, i, set) {
|
||||
this._process(pattern, 0, i, function (er) {
|
||||
if (er) this.emit("error", er)
|
||||
if (-- n <= 0) this._finish()
|
||||
}.bind(this))
|
||||
}
|
||||
|
||||
if (me.options.debug) {
|
||||
console.error("start =", start)
|
||||
}
|
||||
|
||||
this._process(start, 1, this._finish.bind(this))
|
||||
}
|
||||
|
||||
Glob.prototype._finish = _finish
|
||||
function _finish () {
|
||||
var me = this
|
||||
if (me.options.debug) {
|
||||
console.error("!!! GLOB top level cb", me)
|
||||
}
|
||||
if (me.options.nonull && me.matches.length === 0) {
|
||||
return me.emit("end", [pattern])
|
||||
}
|
||||
Glob.prototype._finish = function () {
|
||||
assert(this instanceof Glob)
|
||||
|
||||
var found = me.found = me.matches.slice()
|
||||
var nou = this.nounique
|
||||
, all = nou ? [] : {}
|
||||
|
||||
found = me.found = found.map(function (m) {
|
||||
if (m.indexOf(me.options.cwd) === 0) {
|
||||
m = m.substr(me.options.cwd.length + 1)
|
||||
}
|
||||
return m
|
||||
})
|
||||
|
||||
if (!me.options.mark) return next()
|
||||
|
||||
// mark all directories with a /.
|
||||
// This may involve some stat calls for things that are unknown.
|
||||
var needStat = []
|
||||
found = me.found = found.map(function (f) {
|
||||
if (isDir[f] === undefined) needStat.push(f)
|
||||
else if (isDir[f] && f.slice(-1) !== "/") f += "/"
|
||||
return f
|
||||
})
|
||||
var c = needStat.length
|
||||
if (c === 0) return next()
|
||||
|
||||
var stat = me.options.follow ? "stat" : "lstat"
|
||||
needStat.forEach(function (f) {
|
||||
if (me.options.sync) {
|
||||
try {
|
||||
afterStat(f)(null, fs[stat + "Sync"](f))
|
||||
} catch (er) {
|
||||
afterStat(f)(er)
|
||||
}
|
||||
} else fs[stat](f, afterStat(f))
|
||||
})
|
||||
|
||||
function afterStat (f) { return function (er, st) {
|
||||
// ignore errors. if the user only wants to show
|
||||
// existing files, then set options.stat to exclude anything
|
||||
// that doesn't exist.
|
||||
if (st && st.isDirectory() && f.substr(-1) !== "/") {
|
||||
var i = found.indexOf(f)
|
||||
if (i !== -1) {
|
||||
found.splice(i, 1, f + "/")
|
||||
for (var i = 0, l = this.matches.length; i < l; i ++) {
|
||||
var matches = this.matches[i]
|
||||
if (this.debug) console.error("matches[%d] =", i, matches)
|
||||
// do like the shell, and spit out the literal glob
|
||||
if (!matches) {
|
||||
if (this.nonull) {
|
||||
var literal = this.minimatch.globSet[i]
|
||||
if (nou) all.push(literal)
|
||||
else nou[literal] = true
|
||||
}
|
||||
} else {
|
||||
// had matches
|
||||
var m = Object.keys(matches)
|
||||
if (nou) all.push.apply(all, m)
|
||||
else m.forEach(function (m) {
|
||||
all[m] = true
|
||||
})
|
||||
}
|
||||
if (-- c <= 0) return next()
|
||||
}}
|
||||
|
||||
function next () {
|
||||
if (!me.options.nosort) {
|
||||
found = found.sort(alphasort)
|
||||
}
|
||||
me.emit("end", found)
|
||||
}
|
||||
|
||||
if (!nou) all = Object.keys(all)
|
||||
|
||||
if (!this.nosort) {
|
||||
all = all.sort(this.nocase ? alphasorti : alphasort)
|
||||
}
|
||||
|
||||
if (this.mark) {
|
||||
// at *some* point we statted all of these
|
||||
all = all.map(function (m) {
|
||||
var sc = this.statCache[m]
|
||||
if (!sc) return m
|
||||
if (m.slice(-1) !== "/" && (Array.isArray(sc) || sc === 2)) {
|
||||
return m + "/"
|
||||
}
|
||||
if (m.slice(-1) === "/") {
|
||||
return m.replace(/\/$/, "")
|
||||
}
|
||||
return m
|
||||
})
|
||||
}
|
||||
|
||||
if (this.debug) console.error("emitting end", all)
|
||||
|
||||
this.found = all
|
||||
this.emit("end", all)
|
||||
}
|
||||
|
||||
function alphasorti (a, b) {
|
||||
a = a.toLowerCase()
|
||||
b = b.toLowerCase()
|
||||
return alphasort(a, b)
|
||||
}
|
||||
|
||||
function alphasort (a, b) {
|
||||
a = a.toLowerCase()
|
||||
b = b.toLowerCase()
|
||||
return a > b ? 1 : a < b ? -1 : 0
|
||||
}
|
||||
|
||||
Glob.prototype.abort = abort
|
||||
function abort () {
|
||||
Glob.prototype.abort = function () {
|
||||
this.aborted = true
|
||||
this.emit("abort")
|
||||
}
|
||||
|
||||
|
||||
Glob.prototype._process = _process
|
||||
function _process (f, depth, cb) {
|
||||
Glob.prototype._process = function (pattern, depth, index, cb) {
|
||||
assert(this instanceof Glob)
|
||||
cb = cb.bind(this)
|
||||
if (this.aborted) return cb()
|
||||
|
||||
var me = this
|
||||
if (depth > this.maxDepth) return cb()
|
||||
|
||||
// if f matches, then it's a match. emit it, move on.
|
||||
// if it *partially* matches, then it might be a dir.
|
||||
//
|
||||
// possible optimization: don't just minimatch everything
|
||||
// against the full pattern. if a bit of the pattern is
|
||||
// not magical, it'd be good to reduce the number of stats
|
||||
// that had to be made. so, in the pattern: "a/*/b", we could
|
||||
// readdir a, then stat a/<child>/b in all of them.
|
||||
//
|
||||
// however, that'll require a lot of muddying between minimatch
|
||||
// and glob, and at least for the time being, it's kind of nice to
|
||||
// keep them a little bit separate.
|
||||
|
||||
// if this thing is a match, then add to the matches list.
|
||||
var match = me.minimatch.match(f)
|
||||
if (!match) {
|
||||
if (me.options.debug) {
|
||||
console.error("not a match", f)
|
||||
}
|
||||
return me._processPartial(f, depth, cb)
|
||||
// Get the first [n] parts of pattern that are all strings.
|
||||
var n = 0
|
||||
while (typeof pattern[n] === "string") {
|
||||
n ++
|
||||
}
|
||||
// now n is the index of the first one that is *not* a string.
|
||||
|
||||
if (match) {
|
||||
if (me.options.debug) {
|
||||
console.error(" %s matches %s", f, me.pattern)
|
||||
}
|
||||
// make sure it exists if asked.
|
||||
if (me.options.stat) {
|
||||
var stat = me.options.follow ? "stat" : "lstat"
|
||||
if (me.options.sync) {
|
||||
try {
|
||||
afterStat(f)(null, fs[stat + "Sync"](f))
|
||||
} catch (ex) {
|
||||
afterStat(f)(ex)
|
||||
// see if there's anything else
|
||||
var prefix
|
||||
switch (n) {
|
||||
// if not, then this is rather simple
|
||||
case pattern.length:
|
||||
prefix = pattern.join("/")
|
||||
this._stat(prefix, function (exists, isDir) {
|
||||
// either it's there, or it isn't.
|
||||
// nothing more to do, either way.
|
||||
if (exists) {
|
||||
if (prefix.charAt(0) === "/" && !this.nomount) {
|
||||
prefix = path.join(this.root, prefix)
|
||||
}
|
||||
this.matches[index] = this.matches[index] || {}
|
||||
this.matches[index][prefix] = true
|
||||
this.emit("match", prefix)
|
||||
}
|
||||
} else fs[stat](f, afterStat(f))
|
||||
} else if (me.options.sync) {
|
||||
emitMatch()
|
||||
return cb()
|
||||
})
|
||||
return
|
||||
|
||||
case 0:
|
||||
// pattern *starts* with some non-trivial item.
|
||||
// going to readdir(cwd), but not include the prefix in matches.
|
||||
prefix = null
|
||||
break
|
||||
|
||||
default:
|
||||
// pattern has some string bits in the front.
|
||||
// whatever it starts with, whether that's "absolute" like /foo/bar,
|
||||
// or "relative" like "../baz"
|
||||
prefix = pattern.slice(0, n)
|
||||
prefix = prefix.join("/")
|
||||
break
|
||||
}
|
||||
|
||||
// get the list of entries.
|
||||
var read
|
||||
if (prefix === null) read = "."
|
||||
else if (isAbsolute(prefix)) {
|
||||
read = prefix = path.join("/", prefix)
|
||||
if (this.debug) console.error('absolute: ', prefix, this.root, pattern)
|
||||
} else read = prefix
|
||||
|
||||
if (this.debug) console.error('readdir(%j)', read, this.cwd, this.root)
|
||||
return this._readdir(read, function (er, entries) {
|
||||
if (er) {
|
||||
// not a directory!
|
||||
// this means that, whatever else comes after this, it can never match
|
||||
return cb()
|
||||
}
|
||||
|
||||
// globstar is special
|
||||
if (pattern[n] === minimatch.GLOBSTAR) {
|
||||
// test without the globstar, and with every child both below
|
||||
// and replacing the globstar.
|
||||
var s = [ pattern.slice(0, n).concat(pattern.slice(n + 1)) ]
|
||||
entries.forEach(function (e) {
|
||||
if (e.charAt(0) === "." && !this.dot) return
|
||||
// instead of the globstar
|
||||
s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1)))
|
||||
// below the globstar
|
||||
s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n)))
|
||||
}, this)
|
||||
|
||||
// now asyncForEach over this
|
||||
var l = s.length
|
||||
, errState = null
|
||||
s.forEach(function (gsPattern) {
|
||||
this._process(gsPattern, depth + 1, index, function (er) {
|
||||
if (errState) return
|
||||
if (er) return cb(errState = er)
|
||||
if (--l <= 0) return cb()
|
||||
})
|
||||
}, this)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// not a globstar
|
||||
// It will only match dot entries if it starts with a dot, or if
|
||||
// dot is set. Stuff like @(.foo|.bar) isn't allowed.
|
||||
var pn = pattern[n]
|
||||
if (typeof pn === "string") {
|
||||
var found = entries.indexOf(pn) !== -1
|
||||
entries = found ? entries[pn] : []
|
||||
} else {
|
||||
process.nextTick(emitMatch)
|
||||
var rawGlob = pattern[n]._glob
|
||||
, dotOk = this.dot || rawGlob.charAt(0) === "."
|
||||
|
||||
entries = entries.filter(function (e) {
|
||||
return (e.charAt(0) !== "." || dotOk) &&
|
||||
(typeof pattern[n] === "string" && e === pattern[n] ||
|
||||
e.match(pattern[n]))
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
// If n === pattern.length - 1, then there's no need for the extra stat
|
||||
// *unless* the user has specified "mark" or "stat" explicitly.
|
||||
// We know that they exist, since the readdir returned them.
|
||||
if (n === pattern.length - 1 &&
|
||||
!this.mark &&
|
||||
!this.stat) {
|
||||
entries.forEach(function (e) {
|
||||
if (prefix) {
|
||||
if (prefix !== "/") e = prefix + "/" + e
|
||||
else e = prefix + e
|
||||
}
|
||||
if (e.charAt(0) === "/" && !this.nomount) {
|
||||
e = path.join(this.root, e)
|
||||
}
|
||||
|
||||
function afterStat (f) { return function (er, st) {
|
||||
if (er) return cb()
|
||||
isDir[f] = st.isDirectory()
|
||||
emitMatch()
|
||||
}}
|
||||
|
||||
function emitMatch () {
|
||||
if (me.options.debug) {
|
||||
console.error("emitting match", f)
|
||||
}
|
||||
me.matches.push(f)
|
||||
me.emit("match", f)
|
||||
// move on, since it might also be a partial match
|
||||
// eg, a/**/c matches both a/c and a/c/d/c
|
||||
me._processPartial(f, depth, cb)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Glob.prototype._processPartial = _processPartial
|
||||
function _processPartial (f, depth, cb) {
|
||||
if (this.aborted) return cb()
|
||||
|
||||
var me = this
|
||||
|
||||
var partial = me.minimatch.match(f, true)
|
||||
if (!partial) {
|
||||
if (me.options.debug) {
|
||||
console.error("not a partial", f)
|
||||
this.matches[index] = this.matches[index] || {}
|
||||
this.matches[index][e] = true
|
||||
this.emit("match", e)
|
||||
}, this)
|
||||
return cb.call(this)
|
||||
}
|
||||
|
||||
// if not a match or partial match, just move on.
|
||||
return cb()
|
||||
}
|
||||
|
||||
// partial match
|
||||
// however, this only matters if it's a dir.
|
||||
//if (me.options.debug)
|
||||
if (me.options.debug) {
|
||||
console.error("got a partial", f)
|
||||
}
|
||||
me.emit("partial", f)
|
||||
|
||||
me._processDir(f, depth, cb)
|
||||
}
|
||||
|
||||
Glob.prototype._processDir = _processDir
|
||||
function _processDir (f, depth, cb) {
|
||||
if (this.aborted) return cb()
|
||||
|
||||
// If we're already at the maximum depth, then don't read the dir.
|
||||
if (depth >= this.options.maxDepth) return cb()
|
||||
|
||||
// if the path is at the maximum length, then don't proceed, either.
|
||||
if (f.length >= this.options.maxLength) return cb()
|
||||
|
||||
// now the fun stuff.
|
||||
// if it's a dir, then we'll read all the children, and process them.
|
||||
// if it's not a dir, or we can't access it, then it'll fail.
|
||||
// We log a warning for EACCES and EPERM, but ENOTDIR and ENOENT are
|
||||
// expected and fine.
|
||||
cb = this._afterReaddir(f, depth, cb)
|
||||
if (this.options.sync) return this._processDirSync(f, depth, cb)
|
||||
fs.readdir(f, cb)
|
||||
}
|
||||
|
||||
Glob.prototype._processDirSync = _processDirSync
|
||||
function _processDirSync (f, depth, cb) {
|
||||
try {
|
||||
cb(null, fs.readdirSync(f))
|
||||
} catch (ex) {
|
||||
cb(ex)
|
||||
}
|
||||
}
|
||||
|
||||
Glob.prototype._afterReaddir = _afterReaddir
|
||||
function _afterReaddir (f, depth, cb) {
|
||||
var me = this
|
||||
return function afterReaddir (er, children) {
|
||||
if (er) switch (er.code) {
|
||||
case "UNKNOWN": // probably too deep
|
||||
case "ENOTDIR": // completely expected and normal.
|
||||
isDir[f] = false
|
||||
return cb()
|
||||
case "ENOENT": // should never happen.
|
||||
default: // some other kind of problem.
|
||||
if (!me.options.silent) console.error("glob error", er)
|
||||
if (me.options.strict) return cb(er)
|
||||
return cb()
|
||||
}
|
||||
|
||||
// at this point, we know it's a dir, so save a stat later if
|
||||
// mark is set.
|
||||
isDir[f] = true
|
||||
|
||||
me._processChildren(f, depth, children, cb)
|
||||
}
|
||||
}
|
||||
|
||||
Glob.prototype._processChildren = _processChildren
|
||||
function _processChildren (f, depth, children, cb) {
|
||||
var me = this
|
||||
|
||||
// note: the file ending with / might match, but only if
|
||||
// it's a directory, which we know it is at this point.
|
||||
// For example, /a/b/ or /a/b/** would match /a/b/ but not
|
||||
// /a/b. Note: it'll get the trailing "/" strictly based
|
||||
// on the "mark" param, but that happens later.
|
||||
// This is slightly different from bash's glob.
|
||||
if (!me.minimatch.match(f) && me.minimatch.match(f + "/")) {
|
||||
me.matches.push(f)
|
||||
me.emit("match", f)
|
||||
}
|
||||
|
||||
if (-1 === children.indexOf(".")) children.push(".")
|
||||
if (-1 === children.indexOf("..")) children.push("..")
|
||||
|
||||
var count = children.length
|
||||
if (me.options.debug) {
|
||||
console.error("count=%d %s", count, f, children)
|
||||
}
|
||||
|
||||
if (count === 0) {
|
||||
if (me.options.debug) {
|
||||
console.error("no children?", children, f)
|
||||
}
|
||||
return then()
|
||||
}
|
||||
|
||||
children.forEach(function (c) {
|
||||
if (f === "/") c = f + c
|
||||
else c = f + "/" + c
|
||||
|
||||
if (me.options.debug) {
|
||||
console.error(" processing", c)
|
||||
}
|
||||
me._process(c, depth + 1, then)
|
||||
// now test all the remaining entries as stand-ins for that part
|
||||
// of the pattern.
|
||||
var l = entries.length
|
||||
, errState = null
|
||||
if (l === 0) return cb() // no matches possible
|
||||
entries.forEach(function (e) {
|
||||
var p = pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1))
|
||||
this._process(p, depth + 1, index, function (er) {
|
||||
if (errState) return
|
||||
if (er) return cb(errState = er)
|
||||
if (--l === 0) return cb.call(this)
|
||||
}.bind(this))
|
||||
}, this)
|
||||
})
|
||||
|
||||
function then (er) {
|
||||
count --
|
||||
if (me.options.debug) {
|
||||
console.error("%s THEN %s", f, count, count <= 0 ? "done" : "not done")
|
||||
}
|
||||
|
||||
Glob.prototype._stat = function (f, cb) {
|
||||
assert(this instanceof Glob)
|
||||
var abs = f
|
||||
if (f.charAt(0) === "/") {
|
||||
abs = path.join(this.root, f)
|
||||
} else if (this.changedCwd) {
|
||||
abs = path.resolve(this.cwd, f)
|
||||
}
|
||||
if (this.debug) console.error('stat', [this.cwd, f, '=', abs])
|
||||
if (f.length > this.maxLength) {
|
||||
var er = new Error("Path name too long")
|
||||
er.code = "ENAMETOOLONG"
|
||||
er.path = f
|
||||
return this._afterStat(f, abs, cb, er)
|
||||
}
|
||||
|
||||
if (this.statCache.hasOwnProperty(f)) {
|
||||
var exists = this.statCache[f]
|
||||
, isDir = exists && (Array.isArray(exists) || exists === 2)
|
||||
if (this.sync) return cb.call(this, !!exists, isDir)
|
||||
return process.nextTick(cb.bind(this, !!exists, isDir))
|
||||
}
|
||||
|
||||
if (this.sync) {
|
||||
var er, stat
|
||||
try {
|
||||
stat = fs.statSync(abs)
|
||||
} catch (e) {
|
||||
er = e
|
||||
}
|
||||
if (me.error) return
|
||||
if (er) return me.emit("error", me.error = er)
|
||||
if (count <= 0) cb()
|
||||
this._afterStat(f, abs, cb, er, stat)
|
||||
} else {
|
||||
fs.stat(abs, this._afterStat.bind(this, f, abs, cb))
|
||||
}
|
||||
}
|
||||
|
||||
Glob.prototype._afterStat = function (f, abs, cb, er, stat) {
|
||||
assert(this instanceof Glob)
|
||||
if (er || !stat) {
|
||||
exists = false
|
||||
} else {
|
||||
exists = stat.isDirectory() ? 2 : 1
|
||||
}
|
||||
this.statCache[f] = this.statCache[f] || exists
|
||||
cb.call(this, !!exists, exists === 2)
|
||||
}
|
||||
|
||||
Glob.prototype._readdir = function (f, cb) {
|
||||
assert(this instanceof Glob)
|
||||
var abs = f
|
||||
if (f.charAt(0) === "/") {
|
||||
abs = path.join(this.root, f)
|
||||
} else if (isAbsolute(f)) {
|
||||
abs = f
|
||||
} else if (this.changedCwd) {
|
||||
abs = path.resolve(this.cwd, f)
|
||||
}
|
||||
|
||||
if (this.debug) console.error('readdir', [this.cwd, f, abs])
|
||||
if (f.length > this.maxLength) {
|
||||
var er = new Error("Path name too long")
|
||||
er.code = "ENAMETOOLONG"
|
||||
er.path = f
|
||||
return this._afterReaddir(f, abs, cb, er)
|
||||
}
|
||||
|
||||
if (this.statCache.hasOwnProperty(f)) {
|
||||
var c = this.statCache[f]
|
||||
if (Array.isArray(c)) {
|
||||
if (this.sync) return cb.call(this, null, c)
|
||||
return process.nextTick(cb.bind(this, null, c))
|
||||
}
|
||||
|
||||
if (!c || c === 1) {
|
||||
// either ENOENT or ENOTDIR
|
||||
var code = c ? "ENOTDIR" : "ENOENT"
|
||||
, er = new Error((c ? "Not a directory" : "Not found") + ": " + f)
|
||||
er.path = f
|
||||
er.code = code
|
||||
if (this.debug) console.error(f, er)
|
||||
if (this.sync) return cb.call(this, er)
|
||||
return process.nextTick(cb.bind(this, er))
|
||||
}
|
||||
|
||||
// at this point, c === 2, meaning it's a dir, but we haven't
|
||||
// had to read it yet, or c === true, meaning it's *something*
|
||||
// but we don't have any idea what. Need to read it, either way.
|
||||
}
|
||||
|
||||
if (this.sync) {
|
||||
var er, entries
|
||||
try {
|
||||
entries = fs.readdirSync(abs)
|
||||
} catch (e) {
|
||||
er = e
|
||||
}
|
||||
return this._afterReaddir(f, abs, cb, er, entries)
|
||||
}
|
||||
|
||||
fs.readdir(abs, this._afterReaddir.bind(this, f, abs, cb))
|
||||
}
|
||||
|
||||
Glob.prototype._afterReaddir = function (f, abs, cb, er, entries) {
|
||||
assert(this instanceof Glob)
|
||||
if (entries && !er) {
|
||||
this.statCache[f] = entries
|
||||
// if we haven't asked to stat everything for suresies, then just
|
||||
// assume that everything in there exists, so we can avoid
|
||||
// having to stat it a second time. This also gets us one step
|
||||
// further into ELOOP territory.
|
||||
if (!this.mark && !this.stat) {
|
||||
entries.forEach(function (e) {
|
||||
if (f === "/") e = f + e
|
||||
else e = f + "/" + e
|
||||
this.statCache[e] = true
|
||||
}, this)
|
||||
}
|
||||
|
||||
return cb.call(this, er, entries)
|
||||
}
|
||||
|
||||
// now handle errors, and cache the information
|
||||
if (er) switch (er.code) {
|
||||
case "ENOTDIR": // totally normal. means it *does* exist.
|
||||
this.statCache[f] = 1
|
||||
return cb.call(this, er)
|
||||
case "ENOENT": // not terribly unusual
|
||||
case "ELOOP":
|
||||
case "ENAMETOOLONG":
|
||||
case "UNKNOWN":
|
||||
this.statCache[f] = false
|
||||
return cb.call(this, er)
|
||||
default: // some unusual error. Treat as failure.
|
||||
this.statCache[f] = false
|
||||
if (this.strict) this.emit("error", er)
|
||||
if (!this.silent) console.error("glob error", er)
|
||||
return cb.call(this, er)
|
||||
}
|
||||
}
|
||||
|
||||
var isAbsolute = process.platform === "win32" ? absWin : absUnix
|
||||
|
||||
function absWin (p) {
|
||||
if (absUnix(p)) return true
|
||||
// pull off the device/UNC bit from a windows path.
|
||||
// from node's lib/path.js
|
||||
var splitDeviceRe =
|
||||
/^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?([\\\/])?/
|
||||
, result = splitDeviceRe.exec(p)
|
||||
, device = result[1] || ''
|
||||
, isUnc = device && device.charAt(1) !== ':'
|
||||
, isAbsolute = !!result[2] || isUnc // UNC paths are always absolute
|
||||
|
||||
return isAbsolute
|
||||
}
|
||||
|
||||
function absUnix (p) {
|
||||
return p.charAt(0) === "/" || p === ""
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue