1 | 'use strict';
|
2 |
|
3 | function path() {
|
4 | const data = _interopRequireWildcard(require('path'));
|
5 |
|
6 | path = function () {
|
7 | return data;
|
8 | };
|
9 |
|
10 | return data;
|
11 | }
|
12 |
|
13 | function _fbWatchman() {
|
14 | const data = _interopRequireDefault(require('fb-watchman'));
|
15 |
|
16 | _fbWatchman = function () {
|
17 | return data;
|
18 | };
|
19 |
|
20 | return data;
|
21 | }
|
22 |
|
23 | var _constants = _interopRequireDefault(require('../constants'));
|
24 |
|
25 | var fastPath = _interopRequireWildcard(require('../lib/fast_path'));
|
26 |
|
27 | var _normalizePathSep = _interopRequireDefault(
|
28 | require('../lib/normalizePathSep')
|
29 | );
|
30 |
|
31 | function _interopRequireDefault(obj) {
|
32 | return obj && obj.__esModule ? obj : {default: obj};
|
33 | }
|
34 |
|
35 | function _getRequireWildcardCache(nodeInterop) {
|
36 | if (typeof WeakMap !== 'function') return null;
|
37 | var cacheBabelInterop = new WeakMap();
|
38 | var cacheNodeInterop = new WeakMap();
|
39 | return (_getRequireWildcardCache = function (nodeInterop) {
|
40 | return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
41 | })(nodeInterop);
|
42 | }
|
43 |
|
44 | function _interopRequireWildcard(obj, nodeInterop) {
|
45 | if (!nodeInterop && obj && obj.__esModule) {
|
46 | return obj;
|
47 | }
|
48 | if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
|
49 | return {default: obj};
|
50 | }
|
51 | var cache = _getRequireWildcardCache(nodeInterop);
|
52 | if (cache && cache.has(obj)) {
|
53 | return cache.get(obj);
|
54 | }
|
55 | var newObj = {};
|
56 | var hasPropertyDescriptor =
|
57 | Object.defineProperty && Object.getOwnPropertyDescriptor;
|
58 | for (var key in obj) {
|
59 | if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
|
60 | var desc = hasPropertyDescriptor
|
61 | ? Object.getOwnPropertyDescriptor(obj, key)
|
62 | : null;
|
63 | if (desc && (desc.get || desc.set)) {
|
64 | Object.defineProperty(newObj, key, desc);
|
65 | } else {
|
66 | newObj[key] = obj[key];
|
67 | }
|
68 | }
|
69 | }
|
70 | newObj.default = obj;
|
71 | if (cache) {
|
72 | cache.set(obj, newObj);
|
73 | }
|
74 | return newObj;
|
75 | }
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | const watchmanURL = 'https://facebook.github.io/watchman/docs/troubleshooting';
|
84 |
|
85 | function WatchmanError(error) {
|
86 | error.message =
|
87 | `Watchman error: ${error.message.trim()}. Make sure watchman ` +
|
88 | `is running for this project. See ${watchmanURL}.`;
|
89 | return error;
|
90 | }
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 | async function capabilityCheck(client, caps) {
|
100 | return new Promise((resolve, reject) => {
|
101 | client.capabilityCheck(
|
102 |
|
103 | caps,
|
104 | (error, response) => {
|
105 | if (error) {
|
106 | reject(error);
|
107 | } else {
|
108 | resolve(response);
|
109 | }
|
110 | }
|
111 | );
|
112 | });
|
113 | }
|
114 |
|
115 | module.exports = async function watchmanCrawl(options) {
|
116 | const fields = ['name', 'exists', 'mtime_ms', 'size'];
|
117 | const {data, extensions, ignore, rootDir, roots} = options;
|
118 | const defaultWatchExpression = ['allof', ['type', 'f']];
|
119 | const clocks = data.clocks;
|
120 | const client = new (_fbWatchman().default.Client)();
|
121 |
|
122 |
|
123 | const capabilities = await capabilityCheck(client, {
|
124 |
|
125 |
|
126 | optional: ['suffix-set']
|
127 | });
|
128 |
|
129 | if (
|
130 | capabilities !== null &&
|
131 | capabilities !== void 0 &&
|
132 | capabilities.capabilities['suffix-set']
|
133 | ) {
|
134 |
|
135 |
|
136 | defaultWatchExpression.push(['suffix', extensions]);
|
137 | } else {
|
138 |
|
139 | defaultWatchExpression.push([
|
140 | 'anyof',
|
141 | ...extensions.map(extension => ['suffix', extension])
|
142 | ]);
|
143 | }
|
144 |
|
145 | let clientError;
|
146 | client.on('error', error => (clientError = WatchmanError(error)));
|
147 |
|
148 | const cmd = (...args) =>
|
149 | new Promise((resolve, reject) =>
|
150 | client.command(args, (error, result) =>
|
151 | error ? reject(WatchmanError(error)) : resolve(result)
|
152 | )
|
153 | );
|
154 |
|
155 | if (options.computeSha1) {
|
156 | const {capabilities} = await cmd('list-capabilities');
|
157 |
|
158 | if (capabilities.indexOf('field-content.sha1hex') !== -1) {
|
159 | fields.push('content.sha1hex');
|
160 | }
|
161 | }
|
162 |
|
163 | async function getWatchmanRoots(roots) {
|
164 | const watchmanRoots = new Map();
|
165 | await Promise.all(
|
166 | roots.map(async root => {
|
167 | const response = await cmd('watch-project', root);
|
168 | const existing = watchmanRoots.get(response.watch);
|
169 |
|
170 |
|
171 | const canBeFiltered = !existing || existing.length > 0;
|
172 |
|
173 | if (canBeFiltered) {
|
174 | if (response.relative_path) {
|
175 | watchmanRoots.set(
|
176 | response.watch,
|
177 | (existing || []).concat(response.relative_path)
|
178 | );
|
179 | } else {
|
180 |
|
181 |
|
182 |
|
183 | watchmanRoots.set(response.watch, []);
|
184 | }
|
185 | }
|
186 | })
|
187 | );
|
188 | return watchmanRoots;
|
189 | }
|
190 |
|
191 | async function queryWatchmanForDirs(rootProjectDirMappings) {
|
192 | const results = new Map();
|
193 | let isFresh = false;
|
194 | await Promise.all(
|
195 | Array.from(rootProjectDirMappings).map(
|
196 | async ([root, directoryFilters]) => {
|
197 | var _since$scm;
|
198 |
|
199 | const expression = Array.from(defaultWatchExpression);
|
200 | const glob = [];
|
201 |
|
202 | if (directoryFilters.length > 0) {
|
203 | expression.push([
|
204 | 'anyof',
|
205 | ...directoryFilters.map(dir => ['dirname', dir])
|
206 | ]);
|
207 |
|
208 | for (const directory of directoryFilters) {
|
209 | for (const extension of extensions) {
|
210 | glob.push(`${directory}/**/*.${extension}`);
|
211 | }
|
212 | }
|
213 | } else {
|
214 | for (const extension of extensions) {
|
215 | glob.push(`**/*.${extension}`);
|
216 | }
|
217 | }
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 | const since = clocks.get(fastPath.relative(rootDir, root));
|
227 | const query =
|
228 | since !== undefined
|
229 | ? {
|
230 | expression,
|
231 | fields,
|
232 | since
|
233 | }
|
234 | : {
|
235 | expression,
|
236 | fields,
|
237 | glob,
|
238 | glob_includedotfiles: true
|
239 | };
|
240 | const response = await cmd('query', root, query);
|
241 |
|
242 | if ('warning' in response) {
|
243 | console.warn('watchman warning: ', response.warning);
|
244 | }
|
245 |
|
246 |
|
247 |
|
248 | const isSourceControlQuery =
|
249 | typeof since !== 'string' &&
|
250 | (since === null || since === void 0
|
251 | ? void 0
|
252 | : (_since$scm = since.scm) === null || _since$scm === void 0
|
253 | ? void 0
|
254 | : _since$scm['mergebase-with']) !== undefined;
|
255 |
|
256 | if (!isSourceControlQuery) {
|
257 | isFresh = isFresh || response.is_fresh_instance;
|
258 | }
|
259 |
|
260 | results.set(root, response);
|
261 | }
|
262 | )
|
263 | );
|
264 | return {
|
265 | isFresh,
|
266 | results
|
267 | };
|
268 | }
|
269 |
|
270 | let files = data.files;
|
271 | let removedFiles = new Map();
|
272 | const changedFiles = new Map();
|
273 | let results;
|
274 | let isFresh = false;
|
275 |
|
276 | try {
|
277 | const watchmanRoots = await getWatchmanRoots(roots);
|
278 | const watchmanFileResults = await queryWatchmanForDirs(watchmanRoots);
|
279 |
|
280 |
|
281 | if (watchmanFileResults.isFresh) {
|
282 | files = new Map();
|
283 | removedFiles = new Map(data.files);
|
284 | isFresh = true;
|
285 | }
|
286 |
|
287 | results = watchmanFileResults.results;
|
288 | } finally {
|
289 | client.end();
|
290 | }
|
291 |
|
292 | if (clientError) {
|
293 | throw clientError;
|
294 | }
|
295 |
|
296 | for (const [watchRoot, response] of results) {
|
297 | const fsRoot = (0, _normalizePathSep.default)(watchRoot);
|
298 | const relativeFsRoot = fastPath.relative(rootDir, fsRoot);
|
299 | clocks.set(
|
300 | relativeFsRoot,
|
301 | typeof response.clock === 'string' ? response.clock : response.clock.clock
|
302 | );
|
303 |
|
304 | for (const fileData of response.files) {
|
305 | const filePath =
|
306 | fsRoot + path().sep + (0, _normalizePathSep.default)(fileData.name);
|
307 | const relativeFilePath = fastPath.relative(rootDir, filePath);
|
308 | const existingFileData = data.files.get(relativeFilePath);
|
309 |
|
310 |
|
311 | if (isFresh && existingFileData && fileData.exists) {
|
312 | removedFiles.delete(relativeFilePath);
|
313 | }
|
314 |
|
315 | if (!fileData.exists) {
|
316 |
|
317 | if (existingFileData) {
|
318 | files.delete(relativeFilePath);
|
319 |
|
320 |
|
321 | if (!isFresh) {
|
322 | removedFiles.set(relativeFilePath, existingFileData);
|
323 | }
|
324 | }
|
325 | } else if (!ignore(filePath)) {
|
326 | const mtime =
|
327 | typeof fileData.mtime_ms === 'number'
|
328 | ? fileData.mtime_ms
|
329 | : fileData.mtime_ms.toNumber();
|
330 | const size = fileData.size;
|
331 | let sha1hex = fileData['content.sha1hex'];
|
332 |
|
333 | if (typeof sha1hex !== 'string' || sha1hex.length !== 40) {
|
334 | sha1hex = undefined;
|
335 | }
|
336 |
|
337 | let nextData;
|
338 |
|
339 | if (
|
340 | existingFileData &&
|
341 | existingFileData[_constants.default.MTIME] === mtime
|
342 | ) {
|
343 | nextData = existingFileData;
|
344 | } else if (
|
345 | existingFileData &&
|
346 | sha1hex &&
|
347 | existingFileData[_constants.default.SHA1] === sha1hex
|
348 | ) {
|
349 | nextData = [
|
350 | existingFileData[0],
|
351 | mtime,
|
352 | existingFileData[2],
|
353 | existingFileData[3],
|
354 | existingFileData[4],
|
355 | existingFileData[5]
|
356 | ];
|
357 | } else {
|
358 | var _sha1hex;
|
359 |
|
360 |
|
361 | nextData = [
|
362 | '',
|
363 | mtime,
|
364 | size,
|
365 | 0,
|
366 | '',
|
367 | (_sha1hex = sha1hex) !== null && _sha1hex !== void 0
|
368 | ? _sha1hex
|
369 | : null
|
370 | ];
|
371 | }
|
372 |
|
373 | files.set(relativeFilePath, nextData);
|
374 | changedFiles.set(relativeFilePath, nextData);
|
375 | }
|
376 | }
|
377 | }
|
378 |
|
379 | data.files = files;
|
380 | return {
|
381 | changedFiles: isFresh ? undefined : changedFiles,
|
382 | hasteMap: data,
|
383 | removedFiles
|
384 | };
|
385 | };
|