From 1b65cde4bd490843f9e3c58a112af4f3a621eca8 Mon Sep 17 00:00:00 2001 From: dignifiedquire Date: Thu, 25 Jun 2015 22:26:12 +0200 Subject: [PATCH] feat(file-list): Use glob.sync for better speed --- lib/file-list.js | 68 +++++++++---------- lib/helper.js | 10 --- test/unit/file-list.spec.coffee | 111 ++++++++++++++++++-------------- 3 files changed, 97 insertions(+), 92 deletions(-) diff --git a/lib/file-list.js b/lib/file-list.js index 04649fdc7..228e3d1a2 100644 --- a/lib/file-list.js +++ b/lib/file-list.js @@ -11,6 +11,7 @@ require('core-js') var from = require('core-js/library/fn/array/from') var Promise = require('bluebird') var mm = require('minimatch') +var Glob = require('glob').Glob var fs = Promise.promisifyAll(require('fs')) var File = require('./file') @@ -25,7 +26,8 @@ var log = require('./logger').create('watcher') var GLOB_OPTS = { cwd: '/', follow: true, - nodir: true + nodir: true, + sync: true } // Helper Functions @@ -153,42 +155,42 @@ List.prototype._refresh = function () { return Promise.resolve() } - return helper.glob(pattern, GLOB_OPTS).spread(function (files, mg) { - buckets.set(pattern, new Set()) + var mg = new Glob(pattern, GLOB_OPTS) + var files = mg.found + buckets.set(pattern, new Set()) - if (_.isEmpty(files)) { - log.warn('Pattern "%s" does not match any file.', pattern) - return + if (_.isEmpty(files)) { + log.warn('Pattern "%s" does not match any file.', pattern) + return + } + + return Promise.all(files.map(function (path) { + if (self._isExcluded(path)) { + log.debug('Excluded file "%s"', path) + return Promise.resolve() } - return Promise.all(files.map(function (path) { - if (self._isExcluded(path)) { - log.debug('Excluded file "%s"', path) - return Promise.resolve() - } - - var mtime = mg.statCache[path].mtime - var doNotCache = patternObject.nocache - var file = new File(path, mtime, doNotCache) - - if (file.doNotCache) { - log.debug('Not preprocessing "%s" due to nocache') - return Promise.resolve(file) - } - - return self._preprocess(file).then(function () { - return file - }) - })) - .then(function (files) { - files = _.compact(files) - - if (_.isEmpty(files)) { - log.warn('All files matched by "%s" were excluded.', pattern) - } else { - buckets.set(pattern, new Set(files)) - } + var mtime = mg.statCache[path].mtime + var doNotCache = patternObject.nocache + var file = new File(path, mtime, doNotCache) + + if (file.doNotCache) { + log.debug('Not preprocessing "%s" due to nocache') + return Promise.resolve(file) + } + + return self._preprocess(file).then(function () { + return file }) + })) + .then(function (files) { + files = _.compact(files) + + if (_.isEmpty(files)) { + log.warn('All files matched by "%s" were excluded.', pattern) + } else { + buckets.set(pattern, new Set(files)) + } }) })) .cancellable() diff --git a/lib/helper.js b/lib/helper.js index 88626263c..f414dceef 100644 --- a/lib/helper.js +++ b/lib/helper.js @@ -3,7 +3,6 @@ var path = require('path') var _ = require('lodash') var useragent = require('useragent') var Promise = require('bluebird') -var Glob = require('glob').Glob exports.browserFullNameToShort = function (fullName) { var agent = useragent.parse(fullName) @@ -105,14 +104,5 @@ exports.defer = function () { } } -exports.glob = function glob (pattern, opts) { - return new Promise(function (resolve, reject) { - var mg = new Glob(pattern, opts, function (err, res) { - if (err) return reject(err) - resolve([res, mg]) - }) - }) -} - // export lodash exports._ = _ diff --git a/test/unit/file-list.spec.coffee b/test/unit/file-list.spec.coffee index 88e6ba627..948f47e93 100644 --- a/test/unit/file-list.spec.coffee +++ b/test/unit/file-list.spec.coffee @@ -44,14 +44,8 @@ mockFs = mocks.fs.create 'c.txt': mocks.fs.file 0 'a.js': mocks.fs.file '2012-01-01' -List = proxyquire('../../lib/file-list', { - helper: helper - fs: mockFs -}) - - -describe 'FileList', -> - list = emitter = preprocess = patternList = mg = modified = null +describe.only 'FileList', -> + List = list = emitter = preprocess = patternList = mg = modified = glob = null beforeEach -> @@ -62,12 +56,14 @@ describe 'FileList', -> preprocess = sinon.spy((file, done) -> process.nextTick done) emitter = new EventEmitter() - sinon.stub(helper, 'glob', (pattern, opts) -> - Promise.resolve [patternList[pattern], mg] - ) + glob = Glob: (pattern, opts) -> + {found: patternList[pattern], statCache: mg.statCache} - afterEach -> - helper.glob.restore() + List = proxyquire('../../lib/file-list', { + helper: helper + glob: glob + fs: mockFs + }) it 'returns a flat array of served files', -> list = new List( @@ -174,21 +170,25 @@ describe 'FileList', -> beforeEach -> preprocess = sinon.spy((file, done) -> process.nextTick done) emitter = new EventEmitter() + + glob = Glob: (pattern, opts) -> + {found: patternList[pattern], statCache: mg.statCache} + + List = proxyquire('../../lib/file-list', { + helper: helper + glob: glob + fs: mockFs + }) + list = new List( patterns('/some/*.js', '*.txt'), [], emitter, preprocess ) - sinon.stub(helper, 'glob', (pattern, opts) -> - Promise.resolve [PATTERN_LIST[pattern], MG] - ) list.refresh() - afterEach -> - helper.glob.restore() - it 'returns false when no match is found', -> expect(list._exists('/some/s.js')).to.be.false expect(list._exists('/hello/world.ex')).to.be.false @@ -203,6 +203,16 @@ describe 'FileList', -> mg = _.cloneDeep(MG) preprocess = sinon.spy((file, done) -> process.nextTick done) emitter = new EventEmitter() + + glob = Glob: (pattern, opts) -> + {found: patternList[pattern], statCache: mg.statCache} + + List = proxyquire('../../lib/file-list', { + helper: helper + glob: glob + fs: mockFs + }) + list = new List( patterns('/some/*.js', '*.txt'), [], @@ -210,13 +220,6 @@ describe 'FileList', -> preprocess ) - sinon.stub(helper, 'glob', (pattern, opts) -> - Promise.resolve [patternList[pattern], mg] - ) - - afterEach -> - helper.glob.restore() - it 'resolves patterns', -> list.refresh().then (files) -> expect(list.buckets.size).to.equal 2 @@ -326,6 +329,16 @@ describe 'FileList', -> preprocess = sinon.spy((file, done) -> process.nextTick done) emitter = new EventEmitter() + + glob = Glob: (pattern, opts) -> + {found: patternList[pattern], statCache: mg.statCache} + + List = proxyquire('../../lib/file-list', { + helper: helper + glob: glob + fs: mockFs + }) + list = new List( patterns('/some/*.js', '*.txt'), ['/secret/*.txt'], @@ -333,13 +346,6 @@ describe 'FileList', -> preprocess ) - sinon.stub(helper, 'glob', (pattern, opts) -> - Promise.resolve [patternList[pattern], mg] - ) - - afterEach -> - helper.glob.restore() - it 'does not add excluded files', -> list.refresh().then (before) -> list.addFile('/secret/hello.txt').then (files) -> @@ -419,9 +425,16 @@ describe 'FileList', -> preprocess = sinon.spy((file, done) -> process.nextTick done) emitter = new EventEmitter() - sinon.stub(helper, 'glob', (pattern, opts) -> - Promise.resolve [patternList[pattern], mg] - ) + + + glob = Glob: (pattern, opts) -> + {found: patternList[pattern], statCache: mg.statCache} + + List = proxyquire('../../lib/file-list', { + helper: helper + glob: glob + fs: mockFs + }) mockFs._touchFile '/some/a.js', '2012-04-04' mockFs._touchFile '/some/b.js', '2012-05-05' @@ -429,9 +442,6 @@ describe 'FileList', -> modified = sinon.stub() emitter.on 'file_list_modified', modified - afterEach -> - helper.glob.restore() - it 'updates mtime and fires "file_list_modified"', -> # MATCH: /some/a.js, /some/b.js list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess) @@ -484,16 +494,19 @@ describe 'FileList', -> preprocess = sinon.spy((file, done) -> process.nextTick done) emitter = new EventEmitter() - sinon.stub(helper, 'glob', (pattern, opts) -> - Promise.resolve [patternList[pattern], mg] - ) + + glob = Glob: (pattern, opts) -> + {found: patternList[pattern], statCache: mg.statCache} + + List = proxyquire('../../lib/file-list', { + helper: helper + glob: glob + fs: mockFs + }) modified = sinon.stub() emitter.on 'file_list_modified', modified - afterEach -> - helper.glob.restore() - it 'removes the file from the list and fires "file_list_modified"', -> # MATCH: /some/a.js, /some/b.js, /a.txt list = new List(patterns('/some/*.js', '/a.*'), [], emitter, preprocess) @@ -525,9 +538,9 @@ describe 'FileList', -> preprocess = sinon.spy((file, done) -> process.nextTick done) emitter = new EventEmitter() - sinon.stub(helper, 'glob', (pattern, opts) -> - Promise.resolve [patternList[pattern], mg] - ) + + glob = Glob: (pattern, opts) -> + {found: patternList[pattern], statCache: mg.statCache} modified = sinon.stub() emitter.on 'file_list_modified', modified @@ -538,11 +551,11 @@ describe 'FileList', -> helper._ = _.runInContext() List = proxyquire('../../lib/file-list', { helper: helper + glob: glob fs: mockFs }) afterEach -> - helper.glob.restore() clock.restore() it 'batches multiple changes within an interval', (done) ->