-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[react-packager] Injectible file crawlers (2x crawl speedup)
- Loading branch information
Amjad Masad
committed
Jun 25, 2015
1 parent
336e18d
commit 1109ce3
Showing
8 changed files
with
283 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
packager/react-packager/src/DependencyResolver/crawlers/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
61 changes: 61 additions & 0 deletions
61
packager/react-packager/src/DependencyResolver/crawlers/node.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
70 changes: 70 additions & 0 deletions
70
packager/react-packager/src/DependencyResolver/crawlers/watchman.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
Oops, something went wrong.