mirror of https://github.com/status-im/metro.git
[react-packager] Injectible file crawlers (2x crawl speedup)
This commit is contained in:
parent
693fd0bbe5
commit
737a32417f
|
@ -13,6 +13,8 @@ jest
|
||||||
.dontMock('crypto')
|
.dontMock('crypto')
|
||||||
.dontMock('absolute-path')
|
.dontMock('absolute-path')
|
||||||
.dontMock('../docblock')
|
.dontMock('../docblock')
|
||||||
|
.dontMock('../../crawlers')
|
||||||
|
.dontMock('../../crawlers/node')
|
||||||
.dontMock('../../replacePatterns')
|
.dontMock('../../replacePatterns')
|
||||||
.dontMock('../../../lib/getAssetDataFromName')
|
.dontMock('../../../lib/getAssetDataFromName')
|
||||||
.dontMock('../../fastfs')
|
.dontMock('../../fastfs')
|
||||||
|
@ -22,6 +24,8 @@ jest
|
||||||
.dontMock('../../Package')
|
.dontMock('../../Package')
|
||||||
.dontMock('../../ModuleCache');
|
.dontMock('../../ModuleCache');
|
||||||
|
|
||||||
|
const Promise = require('promise');
|
||||||
|
|
||||||
jest.mock('fs');
|
jest.mock('fs');
|
||||||
|
|
||||||
describe('DependencyGraph', function() {
|
describe('DependencyGraph', function() {
|
||||||
|
@ -36,7 +40,8 @@ describe('DependencyGraph', function() {
|
||||||
fileWatcher = {
|
fileWatcher = {
|
||||||
on: function() {
|
on: function() {
|
||||||
return this;
|
return this;
|
||||||
}
|
},
|
||||||
|
isWatchman: () => Promise.resolve(false)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -8,17 +8,19 @@
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const path = require('path');
|
const Activity = require('../../Activity');
|
||||||
|
const AssetModule_DEPRECATED = require('../AssetModule_DEPRECATED');
|
||||||
const Fastfs = require('../fastfs');
|
const Fastfs = require('../fastfs');
|
||||||
const ModuleCache = require('../ModuleCache');
|
const ModuleCache = require('../ModuleCache');
|
||||||
const AssetModule_DEPRECATED = require('../AssetModule_DEPRECATED');
|
|
||||||
const declareOpts = require('../../lib/declareOpts');
|
|
||||||
const isAbsolutePath = require('absolute-path');
|
|
||||||
const debug = require('debug')('DependencyGraph');
|
|
||||||
const getAssetDataFromName = require('../../lib/getAssetDataFromName');
|
|
||||||
const util = require('util');
|
|
||||||
const Promise = require('promise');
|
const Promise = require('promise');
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
|
const crawl = require('../crawlers');
|
||||||
|
const debug = require('debug')('DependencyGraph');
|
||||||
|
const declareOpts = require('../../lib/declareOpts');
|
||||||
|
const getAssetDataFromName = require('../../lib/getAssetDataFromName');
|
||||||
|
const isAbsolutePath = require('absolute-path');
|
||||||
|
const path = require('path');
|
||||||
|
const util = require('util');
|
||||||
|
|
||||||
const validateOpts = declareOpts({
|
const validateOpts = declareOpts({
|
||||||
roots: {
|
roots: {
|
||||||
|
@ -68,13 +70,18 @@ class DependencyGraph {
|
||||||
return this._loading;
|
return this._loading;
|
||||||
}
|
}
|
||||||
|
|
||||||
const modulePattern = new RegExp(
|
const crawlActivity = Activity.startEvent('fs crawl');
|
||||||
'\.(' + ['js', 'json'].concat(this._assetExts).join('|') + ')$'
|
const allRoots = this._opts.roots.concat(this._opts.assetRoots_DEPRECATED);
|
||||||
);
|
this._crawling = crawl(allRoots, {
|
||||||
|
ignore: this._opts.ignoreFilePath,
|
||||||
|
exts: ['js', 'json'].concat(this._opts.assetExts),
|
||||||
|
fileWatcher: this._opts.fileWatcher,
|
||||||
|
});
|
||||||
|
this._crawling.then((files) => Activity.endEvent(crawlActivity));
|
||||||
|
|
||||||
this._fastfs = new Fastfs(this._opts.roots,this._opts.fileWatcher, {
|
this._fastfs = new Fastfs(this._opts.roots,this._opts.fileWatcher, {
|
||||||
pattern: modulePattern,
|
|
||||||
ignore: this._opts.ignoreFilePath,
|
ignore: this._opts.ignoreFilePath,
|
||||||
|
crawling: this._crawling,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._fastfs.on('change', this._processFileChange.bind(this));
|
this._fastfs.on('change', this._processFileChange.bind(this));
|
||||||
|
@ -454,14 +461,10 @@ class DependencyGraph {
|
||||||
|
|
||||||
this._assetMap_DEPRECATED = Object.create(null);
|
this._assetMap_DEPRECATED = Object.create(null);
|
||||||
|
|
||||||
const pattern = new RegExp(
|
|
||||||
'\.(' + this._opts.assetExts.join('|') + ')$'
|
|
||||||
);
|
|
||||||
|
|
||||||
const fastfs = new Fastfs(
|
const fastfs = new Fastfs(
|
||||||
this._opts.assetRoots_DEPRECATED,
|
this._opts.assetRoots_DEPRECATED,
|
||||||
this._opts.fileWatcher,
|
this._opts.fileWatcher,
|
||||||
{ pattern, ignore: this._opts.ignoreFilePath }
|
{ ignore: this._opts.ignoreFilePath, crawling: this._crawling }
|
||||||
);
|
);
|
||||||
|
|
||||||
fastfs.on('change', this._processAssetChange_DEPRECATED.bind(this));
|
fastfs.on('change', this._processAssetChange_DEPRECATED.bind(this));
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const nodeCrawl = require('./node');
|
||||||
|
//const watchmanCrawl = require('./watchman');
|
||||||
|
|
||||||
|
function crawl(roots, options) {
|
||||||
|
return nodeCrawl(roots, options);
|
||||||
|
|
||||||
|
// Although, in theory, watchman should be much faster;
|
||||||
|
// there is currently a bottleneck somewhere in the
|
||||||
|
// encoding/decoding that is causing it to be slower
|
||||||
|
// than node crawling. However, this should be fixed soon.
|
||||||
|
// https://github.com/facebook/watchman/issues/113
|
||||||
|
/*
|
||||||
|
const {fileWatcher} = options;
|
||||||
|
return fileWatcher.isWatchman().then(isWatchman => {
|
||||||
|
|
||||||
|
console.log(isWatchman);
|
||||||
|
if (!isWatchman) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we're dealing with a version of watchman
|
||||||
|
// that's using `watch-project`
|
||||||
|
// TODO(amasad): properly expose (and document) used sane internals.
|
||||||
|
return fileWatcher.getWatchers().then(([watcher]) => !!watcher.watchProjectInfo.root);
|
||||||
|
}).then(isWatchman => {
|
||||||
|
if (isWatchman) {
|
||||||
|
return watchmanCrawl(roots, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nodeCrawl(roots, options);
|
||||||
|
});*/
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = crawl;
|
|
@ -0,0 +1,61 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Promise = require('promise');
|
||||||
|
const debug = require('debug')('DependencyGraph');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const readDir = Promise.denodeify(fs.readdir);
|
||||||
|
const stat = Promise.denodeify(fs.stat);
|
||||||
|
|
||||||
|
function nodeRecReadDir(roots, {ignore, exts}) {
|
||||||
|
const queue = roots.slice();
|
||||||
|
const retFiles = [];
|
||||||
|
const extPattern = new RegExp(
|
||||||
|
'\.(' + exts.join('|') + ')$'
|
||||||
|
);
|
||||||
|
|
||||||
|
function search() {
|
||||||
|
const currDir = queue.shift();
|
||||||
|
if (!currDir) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
return readDir(currDir)
|
||||||
|
.then(files => files.map(f => path.join(currDir, f)))
|
||||||
|
.then(files => Promise.all(
|
||||||
|
files.map(f => stat(f).catch(handleBrokenLink))
|
||||||
|
).then(stats => [
|
||||||
|
// Remove broken links.
|
||||||
|
files.filter((file, i) => !!stats[i]),
|
||||||
|
stats.filter(Boolean),
|
||||||
|
]))
|
||||||
|
.then(([files, stats]) => {
|
||||||
|
files.forEach((filePath, i) => {
|
||||||
|
if (ignore(filePath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats[i].isDirectory()) {
|
||||||
|
queue.push(filePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filePath.match(extPattern)) {
|
||||||
|
retFiles.push(filePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return search();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return search().then(() => retFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBrokenLink(e) {
|
||||||
|
debug('WARNING: error stating, possibly broken symlink', e.message);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = nodeRecReadDir;
|
|
@ -0,0 +1,70 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const Promise = require('promise');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
function watchmanRecReadDir(roots, {ignore, fileWatcher, exts}) {
|
||||||
|
const files = [];
|
||||||
|
return Promise.all(
|
||||||
|
roots.map(
|
||||||
|
root => fileWatcher.getWatcherForRoot(root)
|
||||||
|
)
|
||||||
|
).then(
|
||||||
|
watchers => {
|
||||||
|
// All watchman roots for all watches we have.
|
||||||
|
const watchmanRoots = watchers.map(
|
||||||
|
watcher => watcher.watchProjectInfo.root
|
||||||
|
);
|
||||||
|
|
||||||
|
// Actual unique watchers (because we use watch-project we may end up with
|
||||||
|
// duplicate "real" watches, and that's by design).
|
||||||
|
// TODO(amasad): push this functionality into the `FileWatcher`.
|
||||||
|
const uniqueWatchers = watchers.filter(
|
||||||
|
(watcher, i) => watchmanRoots.indexOf(watcher.watchProjectInfo.root) === i
|
||||||
|
);
|
||||||
|
|
||||||
|
return Promise.all(
|
||||||
|
uniqueWatchers.map(watcher => {
|
||||||
|
const watchedRoot = watcher.watchProjectInfo.root;
|
||||||
|
|
||||||
|
// Build up an expression to filter the output by the relevant roots.
|
||||||
|
const dirExpr = ['anyof'];
|
||||||
|
for (let i = 0; i < roots.length; i++) {
|
||||||
|
const root = roots[i];
|
||||||
|
if (isDescendant(watchedRoot, root)) {
|
||||||
|
dirExpr.push(['dirname', path.relative(watchedRoot, root)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cmd = Promise.promisify(watcher.client.command.bind(watcher.client));
|
||||||
|
return cmd(['query', watchedRoot, {
|
||||||
|
'suffix': exts,
|
||||||
|
'expression': ['allof', ['type', 'f'], 'exists', dirExpr],
|
||||||
|
'fields': ['name'],
|
||||||
|
}]).then(resp => {
|
||||||
|
if ('warning' in resp) {
|
||||||
|
console.warn('watchman warning: ', resp.warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.files.forEach(filePath => {
|
||||||
|
filePath = path.join(
|
||||||
|
watchedRoot,
|
||||||
|
filePath
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!ignore(filePath)) {
|
||||||
|
files.push(filePath);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}).then(() => files);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDescendant(root, child) {
|
||||||
|
return path.relative(root, child).indexOf('..') !== 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = watchmanRecReadDir;
|
|
@ -4,28 +4,46 @@ const Promise = require('promise');
|
||||||
const {EventEmitter} = require('events');
|
const {EventEmitter} = require('events');
|
||||||
|
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const debug = require('debug')('DependencyGraph');
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const readDir = Promise.denodeify(fs.readdir);
|
|
||||||
const readFile = Promise.denodeify(fs.readFile);
|
const readFile = Promise.denodeify(fs.readFile);
|
||||||
const stat = Promise.denodeify(fs.stat);
|
const stat = Promise.denodeify(fs.stat);
|
||||||
|
|
||||||
const hasOwn = Object.prototype.hasOwnProperty;
|
const hasOwn = Object.prototype.hasOwnProperty;
|
||||||
|
|
||||||
class Fastfs extends EventEmitter {
|
class Fastfs extends EventEmitter {
|
||||||
constructor(roots, fileWatcher, {ignore, pattern}) {
|
constructor(roots, fileWatcher, {ignore, crawling}) {
|
||||||
super();
|
super();
|
||||||
this._fileWatcher = fileWatcher;
|
this._fileWatcher = fileWatcher;
|
||||||
this._ignore = ignore;
|
this._ignore = ignore;
|
||||||
this._pattern = pattern;
|
|
||||||
this._roots = roots.map(root => new File(root, { isDir: true }));
|
this._roots = roots.map(root => new File(root, { isDir: true }));
|
||||||
this._fastPaths = Object.create(null);
|
this._fastPaths = Object.create(null);
|
||||||
|
this._crawling = crawling;
|
||||||
}
|
}
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
const queue = this._roots.slice();
|
const rootsPattern = new RegExp(
|
||||||
return this._search(queue).then(() => {
|
'^(' + this._roots.map(root => escapeRegExp(root.path)).join('|') + ')'
|
||||||
|
);
|
||||||
|
|
||||||
|
return this._crawling.then(files => {
|
||||||
|
files.forEach(filePath => {
|
||||||
|
if (filePath.match(rootsPattern)) {
|
||||||
|
const newFile = new File(filePath, { isDir: false });
|
||||||
|
const parent = this._fastPaths[path.dirname(filePath)];
|
||||||
|
if (parent) {
|
||||||
|
parent.addChild(newFile);
|
||||||
|
} else {
|
||||||
|
this._add(newFile);
|
||||||
|
for (let file = newFile; file; file = file.parent) {
|
||||||
|
if (!this._fastPaths[file.path]) {
|
||||||
|
this._fastPaths[file.path] = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
this._fileWatcher.on('all', this._processFileChange.bind(this));
|
this._fileWatcher.on('all', this._processFileChange.bind(this));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -134,32 +152,6 @@ class Fastfs extends EventEmitter {
|
||||||
this._getAndAssertRoot(file.path).addChild(file);
|
this._getAndAssertRoot(file.path).addChild(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
_search(queue) {
|
|
||||||
const dir = queue.shift();
|
|
||||||
if (!dir) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
return readAndStatDir(dir.path).then(([filePaths, stats]) => {
|
|
||||||
filePaths.forEach((filePath, i) => {
|
|
||||||
if (this._ignore(filePath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stats[i].isDirectory()) {
|
|
||||||
queue.push(
|
|
||||||
new File(filePath, { isDir: true, fstat: stats[i] })
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filePath.match(this._pattern)) {
|
|
||||||
this._add(new File(filePath, { fstat: stats[i] }));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return this._search(queue);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_processFileChange(type, filePath, root, fstat) {
|
_processFileChange(type, filePath, root, fstat) {
|
||||||
const absPath = path.join(root, filePath);
|
const absPath = path.join(root, filePath);
|
||||||
|
@ -182,10 +174,7 @@ class Fastfs extends EventEmitter {
|
||||||
delete this._fastPaths[path.normalize(absPath)];
|
delete this._fastPaths[path.normalize(absPath)];
|
||||||
|
|
||||||
if (type !== 'delete') {
|
if (type !== 'delete') {
|
||||||
this._add(new File(absPath, {
|
this._add(new File(absPath, { isDir: false }));
|
||||||
isDir: false,
|
|
||||||
fstat
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('change', type, filePath, root, fstat);
|
this.emit('change', type, filePath, root, fstat);
|
||||||
|
@ -193,16 +182,12 @@ class Fastfs extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
class File {
|
class File {
|
||||||
constructor(filePath, {isDir, fstat}) {
|
constructor(filePath, { isDir }) {
|
||||||
this.path = filePath;
|
this.path = filePath;
|
||||||
this.isDir = Boolean(isDir);
|
this.isDir = Boolean(isDir);
|
||||||
if (this.isDir) {
|
if (this.isDir) {
|
||||||
this.children = Object.create(null);
|
this.children = Object.create(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fstat) {
|
|
||||||
this._stat = Promise.resolve(fstat);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
read() {
|
read() {
|
||||||
|
@ -290,21 +275,8 @@ function isDescendant(root, child) {
|
||||||
return path.relative(root, child).indexOf('..') !== 0;
|
return path.relative(root, child).indexOf('..') !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readAndStatDir(dir) {
|
function escapeRegExp(str) {
|
||||||
return readDir(dir)
|
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
|
||||||
.then(files => Promise.all(files.map(f => path.join(dir, f))))
|
|
||||||
.then(files => Promise.all(
|
|
||||||
files.map(f => stat(f).catch(handleBrokenLink))
|
|
||||||
).then(stats => [
|
|
||||||
// Remove broken links.
|
|
||||||
files.filter((file, i ) => !!stats[i]),
|
|
||||||
stats.filter(Boolean),
|
|
||||||
]));
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleBrokenLink(e) {
|
|
||||||
debug('WARNING: error stating, possibly broken symlink', e.message);
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Fastfs;
|
module.exports = Fastfs;
|
||||||
|
|
|
@ -33,7 +33,7 @@ describe('FileWatcher', function() {
|
||||||
|
|
||||||
pit('it should get the watcher instance when ready', function() {
|
pit('it should get the watcher instance when ready', function() {
|
||||||
var fileWatcher = new FileWatcher(['rootDir']);
|
var fileWatcher = new FileWatcher(['rootDir']);
|
||||||
return fileWatcher._loading.then(function(watchers) {
|
return fileWatcher.getWatchers().then(function(watchers) {
|
||||||
watchers.forEach(function(watcher) {
|
watchers.forEach(function(watcher) {
|
||||||
expect(watcher instanceof Watcher).toBe(true);
|
expect(watcher instanceof Watcher).toBe(true);
|
||||||
});
|
});
|
||||||
|
@ -48,7 +48,7 @@ describe('FileWatcher', function() {
|
||||||
var fileWatcher = new FileWatcher(['rootDir']);
|
var fileWatcher = new FileWatcher(['rootDir']);
|
||||||
var handler = jest.genMockFn();
|
var handler = jest.genMockFn();
|
||||||
fileWatcher.on('all', handler);
|
fileWatcher.on('all', handler);
|
||||||
return fileWatcher._loading.then(function(){
|
return fileWatcher.getWatchers().then(function(){
|
||||||
cb(1, 2, 3, 4);
|
cb(1, 2, 3, 4);
|
||||||
jest.runAllTimers();
|
jest.runAllTimers();
|
||||||
expect(handler.mock.calls[0]).toEqual([1, 2, 3, 4]);
|
expect(handler.mock.calls[0]).toEqual([1, 2, 3, 4]);
|
||||||
|
|
|
@ -8,13 +8,14 @@
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var EventEmitter = require('events').EventEmitter;
|
const EventEmitter = require('events').EventEmitter;
|
||||||
var sane = require('sane');
|
const sane = require('sane');
|
||||||
var Promise = require('promise');
|
const Promise = require('promise');
|
||||||
var util = require('util');
|
const exec = require('child_process').exec;
|
||||||
var exec = require('child_process').exec;
|
|
||||||
|
|
||||||
var detectingWatcherClass = new Promise(function(resolve) {
|
const MAX_WAIT_TIME = 25000;
|
||||||
|
|
||||||
|
const detectingWatcherClass = new Promise(function(resolve) {
|
||||||
exec('which watchman', function(err, out) {
|
exec('which watchman', function(err, out) {
|
||||||
if (err || out.length === 0) {
|
if (err || out.length === 0) {
|
||||||
resolve(sane.NodeWatcher);
|
resolve(sane.NodeWatcher);
|
||||||
|
@ -24,53 +25,76 @@ var detectingWatcherClass = new Promise(function(resolve) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = FileWatcher;
|
let inited = false;
|
||||||
|
|
||||||
var MAX_WAIT_TIME = 25000;
|
class FileWatcher extends EventEmitter {
|
||||||
|
|
||||||
// Singleton
|
constructor(rootConfigs) {
|
||||||
var fileWatcher = null;
|
if (inited) {
|
||||||
|
throw new Error('FileWatcher can only be instantiated once');
|
||||||
|
}
|
||||||
|
inited = true;
|
||||||
|
|
||||||
function FileWatcher(rootConfigs) {
|
super();
|
||||||
if (fileWatcher) {
|
this._watcherByRoot = Object.create(null);
|
||||||
// This allows us to optimize watching in the future by merging roots etc.
|
|
||||||
throw new Error('FileWatcher can only be instantiated once');
|
this._loading = Promise.all(
|
||||||
|
rootConfigs.map(createWatcher)
|
||||||
|
).then(watchers => {
|
||||||
|
watchers.forEach((watcher, i) => {
|
||||||
|
this._watcherByRoot[rootConfigs[i].dir] = watcher;
|
||||||
|
watcher.on(
|
||||||
|
'all',
|
||||||
|
// args = (type, filePath, root, stat)
|
||||||
|
(...args) => this.emit('all', ...args)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return watchers;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._loading.done();
|
||||||
}
|
}
|
||||||
|
|
||||||
fileWatcher = this;
|
getWatchers() {
|
||||||
|
return this._loading;
|
||||||
|
}
|
||||||
|
|
||||||
this._loading = Promise.all(
|
getWatcherForRoot(root) {
|
||||||
rootConfigs.map(createWatcher)
|
return this._loading.then(() => this._watcherByRoot[root]);
|
||||||
).then(function(watchers) {
|
}
|
||||||
watchers.forEach(function(watcher) {
|
|
||||||
watcher.on('all', function(type, filepath, root, stat) {
|
isWatchman() {
|
||||||
fileWatcher.emit('all', type, filepath, root, stat);
|
return detectingWatcherClass.then(
|
||||||
});
|
Watcher => Watcher === sane.WatchmanWatcher
|
||||||
});
|
);
|
||||||
return watchers;
|
}
|
||||||
});
|
|
||||||
this._loading.done();
|
end() {
|
||||||
|
return this._loading.then(
|
||||||
|
(watchers) => watchers.map(
|
||||||
|
watcher => Promise.denodeify(watcher.close).call(watcher)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static createDummyWatcher() {
|
||||||
|
const ev = new EventEmitter();
|
||||||
|
ev.end = function() {
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
return ev;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
util.inherits(FileWatcher, EventEmitter);
|
|
||||||
|
|
||||||
FileWatcher.prototype.end = function() {
|
|
||||||
return this._loading.then(function(watchers) {
|
|
||||||
watchers.forEach(function(watcher) {
|
|
||||||
return Promise.denodeify(watcher.close).call(watcher);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
function createWatcher(rootConfig) {
|
function createWatcher(rootConfig) {
|
||||||
return detectingWatcherClass.then(function(Watcher) {
|
return detectingWatcherClass.then(function(Watcher) {
|
||||||
var watcher = new Watcher(rootConfig.dir, {
|
const watcher = new Watcher(rootConfig.dir, {
|
||||||
glob: rootConfig.globs,
|
glob: rootConfig.globs,
|
||||||
dot: false,
|
dot: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
var rejectTimeout = setTimeout(function() {
|
const rejectTimeout = setTimeout(function() {
|
||||||
reject(new Error([
|
reject(new Error([
|
||||||
'Watcher took too long to load',
|
'Watcher took too long to load',
|
||||||
'Try running `watchman version` from your terminal',
|
'Try running `watchman version` from your terminal',
|
||||||
|
@ -86,10 +110,4 @@ function createWatcher(rootConfig) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
FileWatcher.createDummyWatcher = function() {
|
module.exports = FileWatcher;
|
||||||
var ev = new EventEmitter();
|
|
||||||
ev.end = function() {
|
|
||||||
return Promise.resolve();
|
|
||||||
};
|
|
||||||
return ev;
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in New Issue