Comparing version 3.1.3 to 3.1.4
64
glob.js
@@ -110,3 +110,6 @@ // Approach: | ||
this.root = options.root || path.resolve(this.cwd, "/") | ||
this.root = path.resolve(this.root) | ||
this.nomount = !!options.nomount | ||
if (!pattern) { | ||
@@ -132,3 +135,3 @@ throw new Error("must provide pattern") | ||
this.stat = !!options.stat | ||
this.debug = !!options.debug | ||
this.debug = !!options.debug || !!options.globDebug | ||
this.silent = !!options.silent | ||
@@ -256,2 +259,5 @@ | ||
if (exists) { | ||
if (prefix.charAt(0) === "/" && !this.nomount) { | ||
prefix = path.join(this.root, prefix) | ||
} | ||
this.matches[index] = this.matches[index] || {} | ||
@@ -277,3 +283,2 @@ this.matches[index][prefix] = true | ||
prefix = prefix.join("/") | ||
if (this.debug) console.error("prefix=%s", prefix) | ||
break | ||
@@ -283,6 +288,10 @@ } | ||
// get the list of entries. | ||
if (prefix !== null && (prefix.charAt(0) === "/" || prefix === "")) { | ||
prefix = path.join(this.root, prefix) | ||
} | ||
var read = prefix || this.cwd | ||
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) { | ||
@@ -351,2 +360,6 @@ if (er) { | ||
} | ||
if (e.charAt(0) === "/" && !this.nomount) { | ||
e = path.join(this.root, e) | ||
} | ||
this.matches[index] = this.matches[index] || {} | ||
@@ -379,4 +392,9 @@ this.matches[index][e] = true | ||
assert(this instanceof Glob) | ||
var abs = this.changedCwd ? path.resolve(this.cwd, f) : f | ||
if (this.debug) console.error('stat', [this.cwd, f, abs]) | ||
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) { | ||
@@ -422,3 +440,11 @@ var er = new Error("Path name too long") | ||
assert(this instanceof Glob) | ||
var abs = this.changedCwd ? path.resolve(this.cwd, f) : f | ||
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]) | ||
@@ -505,1 +531,21 @@ if (f.length > this.maxLength) { | ||
} | ||
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 === "" | ||
} |
@@ -5,3 +5,3 @@ { | ||
"description": "a little globber", | ||
"version": "3.1.3", | ||
"version": "3.1.4", | ||
"repository": { | ||
@@ -8,0 +8,0 @@ "type": "git", |
137
README.md
@@ -50,13 +50,43 @@ # Glob | ||
## Glob Class | ||
## glob(pattern, [options], cb) | ||
Create a glob object by instanting the `glob.Glob` class. | ||
* `pattern` {String} Pattern to be matched | ||
* `options` {Object} | ||
* `cb` {Function} | ||
* `err` {Error | null} | ||
* `matches` {Array<String>} filenames found matching the pattern | ||
Perform an asynchronous glob search. | ||
## glob.sync(pattern, [options] | ||
* `pattern` {String} Pattern to be matched | ||
* `options` {Object} | ||
* return: {Array<String>} filenames found matching the pattern | ||
Perform a synchronous glob search. | ||
## Class: glob.Glob | ||
Create a Glob object by instanting the `glob.Glob` class. | ||
```javascript | ||
var Glob = require("glob").Glob | ||
var mg = new Glob(pattern, options) | ||
var mg = new Glob(pattern, options, cb) | ||
``` | ||
It's an EventEmitter. | ||
It's an EventEmitter, and starts walking the filesystem to find matches | ||
immediately. | ||
### new glob.Glob(pattern, [options], [cb]) | ||
* `pattern` {String} pattern to search for | ||
* `options` {Object} | ||
* `cb` {Function} Called when an error occurs, or matches are found | ||
* `err` {Error | null} | ||
* `matches` {Array<String>} filenames found matching the pattern | ||
Note that if the `sync` flag is set in the options, then matches will | ||
be immediately available on the `g.found` member. | ||
### Properties | ||
@@ -69,3 +99,4 @@ | ||
* `aborted` Boolean which is set to true when calling `abort()`. There | ||
is no way at this time to continue a glob search after aborting. | ||
is no way at this time to continue a glob search after aborting, but | ||
you can re-use the statCache to avoid having to duplicate syscalls. | ||
@@ -90,7 +121,9 @@ ### Events | ||
All the options that can be passed to Minimatch can also be passed to | ||
Glob to change pattern matching behavior. Additionally, these ones | ||
are added which are glob-specific, or have glob-specific ramifcations. | ||
Glob to change pattern matching behavior. Also, some have been added, | ||
or have glob-specific ramifications. | ||
All options are false by default, unless otherwise noted. | ||
All options are added to the glob object, as well. | ||
* `cwd` The current working directory in which to search. Defaults | ||
@@ -101,2 +134,5 @@ to `process.cwd()`. | ||
systems, and `C:\` or some such on Windows.) | ||
* `nomount` By default, a pattern starting with a forward-slash will be | ||
"mounted" onto the root setting, so that a valid filesystem path is | ||
returned. Set this flag to disable that behavior. | ||
* `mark` Add a `/` character to directory matches. Note that this | ||
@@ -106,3 +142,6 @@ requires additional stat calls. | ||
* `stat` Set to true to stat *all* results. This reduces performance | ||
somewhat. | ||
somewhat, and is completely unnecessary, unless `readdir` is presumed | ||
to be an untrustworthy indicator of file existence. It will cause | ||
ELOOP to be triggered one level sooner in the case of cyclical | ||
symbolic links. | ||
* `silent` When an unusual error is encountered | ||
@@ -119,2 +158,82 @@ when attempting to read a directory, a warning will be printed to | ||
options object of another, if you know that the filesystem will not | ||
change between calls. | ||
change between calls. (See "Race Conditions" below.) | ||
* `sync` Perform a synchronous glob search. | ||
* `nounique` In some cases, brace-expanded patterns can result in the | ||
same file showing up multiple times in the result set. By default, | ||
this implementation prevents duplicates in the result set. | ||
Set this flag to disable that behavior. | ||
* `nonull` Set to never return an empty set, instead returning a set | ||
containing the pattern itself. This is the default in glob(3). | ||
* `nocase` Perform a case-insensitive match. Note that case-insensitive | ||
filesystems will sometimes result in glob returning results that are | ||
case-insensitively matched anyway, since readdir and stat will not | ||
raise an error. | ||
* `debug` Set to enable debug logging in minimatch and glob. | ||
* `globDebug` Set to enable debug logging in glob, but not minimatch. | ||
## Comparisons to other fnmatch/glob implementations | ||
While strict compliance with the existing standards is a worthwhile | ||
goal, some discrepancies exist between node-glob and other | ||
implementations, and are intentional. | ||
If the pattern starts with a `!` character, then it is negated. Set the | ||
`nonegate` flag to suppress this behavior, and treat leading `!` | ||
characters normally. This is perhaps relevant if you wish to start the | ||
pattern with a negative extglob pattern like `!(a|B)`. Multiple `!` | ||
characters at the start of a pattern will negate the pattern multiple | ||
times. | ||
If a pattern starts with `#`, then it is treated as a comment, and | ||
will not match anything. Use `\#` to match a literal `#` at the | ||
start of a line, or set the `nocomment` flag to suppress this behavior. | ||
The double-star character `**` is supported by default, unless the | ||
`noglobstar` flag is set. This is supported in the manner of bsdglob | ||
and bash 4.1, where `**` only has special significance if it is the only | ||
thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but | ||
`a/**b` will not. **Note that this is different from the way that `**` is | ||
handled by ruby's `Dir` class.** | ||
If an escaped pattern has no matches, and the `nonull` flag is set, | ||
then glob returns the pattern as-provided, rather than | ||
interpreting the character escapes. For example, | ||
`glob.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than | ||
`"*a?"`. This is akin to setting the `nullglob` option in bash, except | ||
that it does not resolve escaped pattern characters. | ||
If brace expansion is not disabled, then it is performed before any | ||
other interpretation of the glob pattern. Thus, a pattern like | ||
`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded | ||
**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are | ||
checked for validity. Since those two are valid, matching proceeds. | ||
## Windows | ||
**Please only use forward-slashes in glob expressions.** | ||
Though windows uses either `/` or `\` as its path separator, only `/` | ||
characters are used by this glob implementation. You must use | ||
forward-slashes **only** in glob expressions. Back-slashes will always | ||
be interpreted as escape characters, not path separators. | ||
Results from absolute patterns such as `/foo/*` are mounted onto the | ||
root setting using `path.join`. On windows, this will by default result | ||
in `/foo/*` matching `C:\foo\bar.txt`. | ||
## Race Conditions | ||
Glob searching, by its very nature, is susceptible to race conditions, | ||
since it relies on directory walking and such. | ||
As a result, it is possible that a file that exists when glob looks for | ||
it may have been deleted or modified by the time it returns the result. | ||
As part of its internal implementation, this program caches all stat | ||
and readdir calls that it makes, in order to cut down on system | ||
overhead. However, this also makes it even more susceptible to races, | ||
especially if the statCache object is reused between glob calls. | ||
Users are thus advised not to use a glob result as a | ||
guarantee of filesystem state in the face of rapid changes. | ||
For the vast majority of operations, this is never a problem. |
var tap = require("tap") | ||
var origCwd = process.cwd() | ||
process.chdir(__dirname) | ||
tap.test("changing cwd and searching for **/d", function (t) { | ||
@@ -46,3 +49,8 @@ var glob = require('glob') | ||
t.test('cd -', function (t) { | ||
process.chdir(origCwd) | ||
t.end() | ||
}) | ||
t.end() | ||
}) |
33510
13
768
234