Skip to content

Commit

Permalink
New: Added ignore option (fixes #115)
Browse files Browse the repository at this point in the history
  • Loading branch information
vegetableman committed Jan 2, 2015
1 parent 941d53c commit 31797f5
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 6 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ filesystem.
* `nocomment` Suppress `comment` behavior. (See below.)
* `nonull` Return the pattern when no matches are found.
* `nodir` Do not match directories, only files.
* `ignore` Add a pattern or an array of patterns to exclude matches.

## Comparisons to other fnmatch/glob implementations

Expand Down
Empty file modified benchclean.sh
100644 → 100755
Empty file.
Empty file modified benchmark.sh
100644 → 100755
Empty file.
17 changes: 17 additions & 0 deletions common.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ exports.ownProp = ownProp
exports.makeAbs = makeAbs
exports.finish = finish
exports.mark = mark
exports.isIgnored = isIgnored

function ownProp (obj, field) {
return Object.prototype.hasOwnProperty.call(obj, field)
Expand Down Expand Up @@ -74,6 +75,14 @@ function setopts (self, pattern, options) {
self.statCache = options.statCache || Object.create(null)
self.symlinks = options.symlinks || Object.create(null)

self.ignore = options.ignore || []
if(!Array.isArray(self.ignore))
self.ignore = [self.ignore]
if(self.ignore.length)
self.ignore = self.ignore.map(function(pattern) {
return {pattern: pattern, endsWithGlobStar: pattern.slice(-3) === '/**', spattern: pattern.slice(0, -3)}
})

self.changedCwd = false
var cwd = process.cwd()
if (!ownProp(options, "cwd"))
Expand Down Expand Up @@ -175,3 +184,11 @@ function makeAbs (self, f) {
}
return abs
}

// If pattern ends with globstar '**', return true for the accompanying parent directory.
// If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents
function isIgnored (self, path) {
return self.ignore.some(function(p) {
return minimatch(path, p.pattern) || (p.endsWithGlobStar && minimatch(path, p.spattern))
})
}
16 changes: 12 additions & 4 deletions glob.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ var alphasort = common.alphasort
var isAbsolute = common.isAbsolute
var setopts = common.setopts
var ownProp = common.ownProp
var isIgnored = common.isIgnored
var inflight = require("inflight")
var util = require("util")

Expand Down Expand Up @@ -269,14 +270,17 @@ Glob.prototype._process = function (pattern, index, inGlobStar, cb) {

var abs = this._makeAbs(read)

//if ignored, skip processing
if(isIgnored(this, abs))
return cb()

var isGlobStar = remain[0] === minimatch.GLOBSTAR
if (isGlobStar)
this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb)
else
this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb)
}


Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) {
var self = this
this._readdir(abs, inGlobStar, function (er, entries) {
Expand Down Expand Up @@ -304,7 +308,8 @@ Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, in
var m
if (negate && !prefix) {
m = !e.match(pn)
} else {
}
else {
m = e.match(pn)
}
if (m)
Expand Down Expand Up @@ -340,7 +345,9 @@ Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, in
if (e.charAt(0) === "/" && !this.nomount) {
e = path.join(this.root, e)
}
this._emitMatch(index, e)

if(!isIgnored(this, e))
this._emitMatch(index, e)
}
// This was the last one, and no stats were needed
return cb()
Expand Down Expand Up @@ -583,7 +590,8 @@ Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) {
prefix = prefix.replace(/\\/g, "/")

// Mark this as a match
this._emitMatch(index, prefix)
if(!isIgnored(this, prefix))
this._emitMatch(index, prefix)
cb()
}

Expand Down
12 changes: 10 additions & 2 deletions sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var alphasort = common.alphasort
var isAbsolute = common.isAbsolute
var setopts = common.setopts
var ownProp = common.ownProp
var isIgnored = common.isIgnored

function globSync (pattern, options) {
if (typeof options === 'function' || arguments.length === 3)
Expand Down Expand Up @@ -97,13 +98,18 @@ GlobSync.prototype._process = function (pattern, index, inGlobStar) {

var abs = this._makeAbs(read)

//if ignored, skip processing
if(isIgnored(this, abs))
return

var isGlobStar = remain[0] === minimatch.GLOBSTAR
if (isGlobStar)
this._processGlobStar(prefix, read, abs, remain, index, inGlobStar)
else
this._processReaddir(prefix, read, abs, remain, index, inGlobStar)
}


GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) {
var entries = this._readdir(abs, inGlobStar)

Expand Down Expand Up @@ -159,7 +165,8 @@ GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index,
if (e.charAt(0) === "/" && !this.nomount) {
e = path.join(this.root, e)
}
this.matches[index][e] = true
if(!isIgnored(this, e))
this.matches[index][e] = true
}
// This was the last one, and no stats were needed
return
Expand Down Expand Up @@ -351,7 +358,8 @@ GlobSync.prototype._processSimple = function (prefix, index) {
prefix = prefix.replace(/\\/g, "/")

// Mark this as a match
this.matches[index][prefix] = true
if(!isIgnored(this, prefix))
this.matches[index][prefix] = true
}

// Returns either 'DIR', 'FILE', or false
Expand Down
2 changes: 2 additions & 0 deletions test/bash-results.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@
"./test/global-leakage.js",
"./test/globstar-match.js",
"./test/has-magic.js",
"./test/ignore-sync.js",
"./test/ignore.js",
"./test/mark-sync.js",
"./test/mark.js",
"./test/negation-test.js",
Expand Down
67 changes: 67 additions & 0 deletions test/ignore-sync.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
require('./global-leakage.js')
// Ignore option test
// Show that glob ignores results matching pattern on ignore option

var glob = require('../glob.js')
var test = require('tap').test

test('get all', function(t) {
var results = glob('*', {sync: true, cwd: 'a'})
t.same(results, ['abcdef', 'abcfed', 'b', 'bc', 'c', 'cb', 'symlink'])
t.end()
});

test('ignore b', function(t) {
var results = glob('*', {sync: true, cwd: 'a', ignore: 'b'})
t.same(results, ['abcdef', 'abcfed', 'bc', 'c', 'cb', 'symlink'])
t.end()
});

test('ignore all with first letter as b', function(t) {
var results = glob('*', {sync: true, cwd: 'a', ignore: 'b*'});
t.same(results, ['abcdef', 'abcfed', 'c', 'cb', 'symlink'])
t.end()
});

test('ignore b/c/d in b/c', function(t) {
var results = glob('b/**', {sync: true, cwd: 'a', ignore: 'b/c/d'});
t.same(results, ['b', 'b/c'])
t.end()
});

// matches based on pattern specified
test('ignores d in b/c only if pattern starts with b/c', function(t) {
var results = glob('b/**', {sync: true, cwd: 'a', ignore: 'd'});
t.same(results, ['b', 'b/c', 'b/c/d'])
t.end()
});

test('ignore b/c and it\'s contents using globstar', function(t) {
var results = glob('b/**', {sync: true, cwd: 'a', ignore: 'b/c/**'})
t.same(results, ['b'])
t.end()
});

test('ignore, get all d but that in b', function(t) {
var results = glob('**/d', {sync: true, cwd: 'a', ignore: 'b/c/d'})
t.same(results, ['c/d'])
t.end()
});

test('ignore, get all a/**/[gh] except a/abcfed/g/h', function(t) {
var results = glob('a/**/[gh]', {sync: true, ignore: ['a/abcfed/g/h']})
t.same(results, ['a/abcdef/g', 'a/abcdef/g/h', 'a/abcfed/g'])
t.end()
});

test('ignore, using multiple ignores', function(t) {
var results = glob('*', {sync: true, cwd: 'a', ignore: ['c', 'bc', 'symlink', 'abcdef']})
t.same(results, ['abcfed', 'b', 'cb'])
t.end()
});

test('ignore, using multiple ignores and globstar', function(t) {
var results = glob('a/**', {sync: true, ignore: ['a/c/**', 'a/bc/**', 'a/symlink/**', 'a/abcdef/**']})
t.same(results, ['a', 'a/abcfed', 'a/abcfed/g', 'a/abcfed/g/h', 'a/b', 'a/b/c', 'a/b/c/d', 'a/cb', 'a/cb/e', 'a/cb/e/f'])
t.end()
});
97 changes: 97 additions & 0 deletions test/ignore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
require('./global-leakage.js')
// Ignore option test
// Show that glob ignores results matching pattern on ignore option

var glob = require('../glob.js')
var test = require('tap').test

test('get all', function(t) {
var results = glob('*', {cwd: 'a'}, function (er, results) {
if (er)
throw er
t.same(results, ['abcdef', 'abcfed', 'b', 'bc', 'c', 'cb', 'symlink'])
t.end()
})
});

test('ignore b', function(t) {
var results = glob('*', {cwd: 'a', ignore: 'b'}, function (er, results) {
if (er)
throw er
t.same(results, ['abcdef', 'abcfed', 'bc', 'c', 'cb', 'symlink'])
t.end()
})
});

test('ignore all with first letter as b', function(t) {
var results = glob('*', {cwd: 'a', ignore: 'b*'}, function (er, results) {
if (er)
throw er
t.same(results, ['abcdef', 'abcfed', 'c', 'cb', 'symlink'])
t.end()
});
});

test('ignore b/c/d in b/c', function(t) {
var results = glob('b/**', {cwd: 'a', ignore: 'b/c/d'}, function (er, results) {
if (er)
throw er
t.same(results, ['b', 'b/c'])
t.end()
});
});

// matches based on pattern specified
test('ignores d in b/c only if pattern starts with b/c', function(t) {
var results = glob('b/**', {cwd: 'a', ignore: 'd'}, function (er, results) {
if (er)
throw er
t.same(results, ['b', 'b/c', 'b/c/d'])
t.end()
});
});

test('ignore b/c and it\'s contents using globstar', function(t) {
var results = glob('b/**', {cwd: 'a', ignore: 'b/c/**'}, function (er, results) {
if (er)
throw er
t.same(results, ['b'])
t.end()
})
});

test('ignore, get all d but that in b', function(t) {
var results = glob('**/d', {cwd: 'a', ignore: 'b/c/d'}, function (er, results) {
if (er)
throw er
t.same(results, ['c/d'])
t.end()
})
});

test('ignore, get all a/**/[gh] except a/abcfed/g/h', function(t) {
var results = glob('a/**/[gh]', {ignore: ['a/abcfed/g/h']}, function (er, results) {
if (er)
throw er
t.same(results, ['a/abcdef/g', 'a/abcdef/g/h', 'a/abcfed/g'])
t.end()
})
});

test('ignore, using multiple ignores', function(t) {
var results = glob('*', {cwd: 'a', ignore: ['c', 'bc', 'symlink', 'abcdef']}, function (er, results) {
if (er)
throw er
t.same(results, ['abcfed', 'b', 'cb'])
t.end()
})
});

test('ignore, using multiple ignores and globstar', function(t) {
var results = glob('a/**', {ignore: ['a/c/**', 'a/bc/**', 'a/symlink/**', 'a/abcdef/**']}, function (er, results) {
if (er)
throw er
t.same(results, ['a', 'a/abcfed', 'a/abcfed/g', 'a/abcfed/g/h', 'a/b', 'a/b/c', 'a/b/c/d', 'a/cb', 'a/cb/e', 'a/cb/e/f'])
t.end()
})
});

0 comments on commit 31797f5

Please sign in to comment.