Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

watchman.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. 'use strict';
  2. function path() {
  3. const data = _interopRequireWildcard(require('path'));
  4. path = function () {
  5. return data;
  6. };
  7. return data;
  8. }
  9. function _fbWatchman() {
  10. const data = _interopRequireDefault(require('fb-watchman'));
  11. _fbWatchman = function () {
  12. return data;
  13. };
  14. return data;
  15. }
  16. function _constants() {
  17. const data = _interopRequireDefault(require('../constants'));
  18. _constants = function () {
  19. return data;
  20. };
  21. return data;
  22. }
  23. function fastPath() {
  24. const data = _interopRequireWildcard(require('../lib/fast_path'));
  25. fastPath = function () {
  26. return data;
  27. };
  28. return data;
  29. }
  30. function _normalizePathSep() {
  31. const data = _interopRequireDefault(require('../lib/normalizePathSep'));
  32. _normalizePathSep = function () {
  33. return data;
  34. };
  35. return data;
  36. }
  37. function _interopRequireDefault(obj) {
  38. return obj && obj.__esModule ? obj : {default: obj};
  39. }
  40. function _getRequireWildcardCache(nodeInterop) {
  41. if (typeof WeakMap !== 'function') return null;
  42. var cacheBabelInterop = new WeakMap();
  43. var cacheNodeInterop = new WeakMap();
  44. return (_getRequireWildcardCache = function (nodeInterop) {
  45. return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
  46. })(nodeInterop);
  47. }
  48. function _interopRequireWildcard(obj, nodeInterop) {
  49. if (!nodeInterop && obj && obj.__esModule) {
  50. return obj;
  51. }
  52. if (obj === null || (typeof obj !== 'object' && typeof obj !== 'function')) {
  53. return {default: obj};
  54. }
  55. var cache = _getRequireWildcardCache(nodeInterop);
  56. if (cache && cache.has(obj)) {
  57. return cache.get(obj);
  58. }
  59. var newObj = {};
  60. var hasPropertyDescriptor =
  61. Object.defineProperty && Object.getOwnPropertyDescriptor;
  62. for (var key in obj) {
  63. if (key !== 'default' && Object.prototype.hasOwnProperty.call(obj, key)) {
  64. var desc = hasPropertyDescriptor
  65. ? Object.getOwnPropertyDescriptor(obj, key)
  66. : null;
  67. if (desc && (desc.get || desc.set)) {
  68. Object.defineProperty(newObj, key, desc);
  69. } else {
  70. newObj[key] = obj[key];
  71. }
  72. }
  73. }
  74. newObj.default = obj;
  75. if (cache) {
  76. cache.set(obj, newObj);
  77. }
  78. return newObj;
  79. }
  80. /**
  81. * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  82. *
  83. * This source code is licensed under the MIT license found in the
  84. * LICENSE file in the root directory of this source tree.
  85. */
  86. const watchmanURL = 'https://facebook.github.io/watchman/docs/troubleshooting';
  87. function WatchmanError(error) {
  88. error.message =
  89. `Watchman error: ${error.message.trim()}. Make sure watchman ` +
  90. `is running for this project. See ${watchmanURL}.`;
  91. return error;
  92. }
  93. /**
  94. * Wrap watchman capabilityCheck method as a promise.
  95. *
  96. * @param client watchman client
  97. * @param caps capabilities to verify
  98. * @returns a promise resolving to a list of verified capabilities
  99. */
  100. async function capabilityCheck(client, caps) {
  101. return new Promise((resolve, reject) => {
  102. client.capabilityCheck(
  103. // @ts-expect-error: incorrectly typed
  104. caps,
  105. (error, response) => {
  106. if (error) {
  107. reject(error);
  108. } else {
  109. resolve(response);
  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)(); // https://facebook.github.io/watchman/docs/capabilities.html
  121. // Check adds about ~28ms
  122. const capabilities = await capabilityCheck(client, {
  123. // If a required capability is missing then an error will be thrown,
  124. // we don't need this assertion, so using optional instead.
  125. optional: ['suffix-set']
  126. });
  127. if (
  128. capabilities !== null &&
  129. capabilities !== void 0 &&
  130. capabilities.capabilities['suffix-set']
  131. ) {
  132. // If available, use the optimized `suffix-set` operation:
  133. // https://facebook.github.io/watchman/docs/expr/suffix.html#suffix-set
  134. defaultWatchExpression.push(['suffix', extensions]);
  135. } else {
  136. // Otherwise use the older and less optimal suffix tuple array
  137. defaultWatchExpression.push([
  138. 'anyof',
  139. ...extensions.map(extension => ['suffix', extension])
  140. ]);
  141. }
  142. let clientError;
  143. client.on('error', error => (clientError = WatchmanError(error)));
  144. const cmd = (...args) =>
  145. new Promise((resolve, reject) =>
  146. client.command(args, (error, result) =>
  147. error ? reject(WatchmanError(error)) : resolve(result)
  148. )
  149. );
  150. if (options.computeSha1) {
  151. const {capabilities} = await cmd('list-capabilities');
  152. if (capabilities.indexOf('field-content.sha1hex') !== -1) {
  153. fields.push('content.sha1hex');
  154. }
  155. }
  156. async function getWatchmanRoots(roots) {
  157. const watchmanRoots = new Map();
  158. await Promise.all(
  159. roots.map(async root => {
  160. const response = await cmd('watch-project', root);
  161. const existing = watchmanRoots.get(response.watch); // A root can only be filtered if it was never seen with a
  162. // relative_path before.
  163. const canBeFiltered = !existing || existing.length > 0;
  164. if (canBeFiltered) {
  165. if (response.relative_path) {
  166. watchmanRoots.set(
  167. response.watch,
  168. (existing || []).concat(response.relative_path)
  169. );
  170. } else {
  171. // Make the filter directories an empty array to signal that this
  172. // root was already seen and needs to be watched for all files or
  173. // directories.
  174. watchmanRoots.set(response.watch, []);
  175. }
  176. }
  177. })
  178. );
  179. return watchmanRoots;
  180. }
  181. async function queryWatchmanForDirs(rootProjectDirMappings) {
  182. const results = new Map();
  183. let isFresh = false;
  184. await Promise.all(
  185. Array.from(rootProjectDirMappings).map(
  186. async ([root, directoryFilters]) => {
  187. var _since$scm;
  188. const expression = Array.from(defaultWatchExpression);
  189. const glob = [];
  190. if (directoryFilters.length > 0) {
  191. expression.push([
  192. 'anyof',
  193. ...directoryFilters.map(dir => ['dirname', dir])
  194. ]);
  195. for (const directory of directoryFilters) {
  196. for (const extension of extensions) {
  197. glob.push(`${directory}/**/*.${extension}`);
  198. }
  199. }
  200. } else {
  201. for (const extension of extensions) {
  202. glob.push(`**/*.${extension}`);
  203. }
  204. } // Jest is only going to store one type of clock; a string that
  205. // represents a local clock. However, the Watchman crawler supports
  206. // a second type of clock that can be written by automation outside of
  207. // Jest, called an "scm query", which fetches changed files based on
  208. // source control mergebases. The reason this is necessary is because
  209. // local clocks are not portable across systems, but scm queries are.
  210. // By using scm queries, we can create the haste map on a different
  211. // system and import it, transforming the clock into a local clock.
  212. const since = clocks.get(fastPath().relative(rootDir, root));
  213. const query =
  214. since !== undefined // Use the `since` generator if we have a clock available
  215. ? {
  216. expression,
  217. fields,
  218. since
  219. } // Otherwise use the `glob` filter
  220. : {
  221. expression,
  222. fields,
  223. glob,
  224. glob_includedotfiles: true
  225. };
  226. const response = await cmd('query', root, query);
  227. if ('warning' in response) {
  228. console.warn('watchman warning: ', response.warning);
  229. } // When a source-control query is used, we ignore the "is fresh"
  230. // response from Watchman because it will be true despite the query
  231. // being incremental.
  232. const isSourceControlQuery =
  233. typeof since !== 'string' &&
  234. (since === null || since === void 0
  235. ? void 0
  236. : (_since$scm = since.scm) === null || _since$scm === void 0
  237. ? void 0
  238. : _since$scm['mergebase-with']) !== undefined;
  239. if (!isSourceControlQuery) {
  240. isFresh = isFresh || response.is_fresh_instance;
  241. }
  242. results.set(root, response);
  243. }
  244. )
  245. );
  246. return {
  247. isFresh,
  248. results
  249. };
  250. }
  251. let files = data.files;
  252. let removedFiles = new Map();
  253. const changedFiles = new Map();
  254. let results;
  255. let isFresh = false;
  256. try {
  257. const watchmanRoots = await getWatchmanRoots(roots);
  258. const watchmanFileResults = await queryWatchmanForDirs(watchmanRoots); // Reset the file map if watchman was restarted and sends us a list of
  259. // files.
  260. if (watchmanFileResults.isFresh) {
  261. files = new Map();
  262. removedFiles = new Map(data.files);
  263. isFresh = true;
  264. }
  265. results = watchmanFileResults.results;
  266. } finally {
  267. client.end();
  268. }
  269. if (clientError) {
  270. throw clientError;
  271. }
  272. for (const [watchRoot, response] of results) {
  273. const fsRoot = (0, _normalizePathSep().default)(watchRoot);
  274. const relativeFsRoot = fastPath().relative(rootDir, fsRoot);
  275. clocks.set(
  276. relativeFsRoot, // Ensure we persist only the local clock.
  277. typeof response.clock === 'string' ? response.clock : response.clock.clock
  278. );
  279. for (const fileData of response.files) {
  280. const filePath =
  281. fsRoot + path().sep + (0, _normalizePathSep().default)(fileData.name);
  282. const relativeFilePath = fastPath().relative(rootDir, filePath);
  283. const existingFileData = data.files.get(relativeFilePath); // If watchman is fresh, the removed files map starts with all files
  284. // and we remove them as we verify they still exist.
  285. if (isFresh && existingFileData && fileData.exists) {
  286. removedFiles.delete(relativeFilePath);
  287. }
  288. if (!fileData.exists) {
  289. // No need to act on files that do not exist and were not tracked.
  290. if (existingFileData) {
  291. files.delete(relativeFilePath); // If watchman is not fresh, we will know what specific files were
  292. // deleted since we last ran and can track only those files.
  293. if (!isFresh) {
  294. removedFiles.set(relativeFilePath, existingFileData);
  295. }
  296. }
  297. } else if (!ignore(filePath)) {
  298. const mtime =
  299. typeof fileData.mtime_ms === 'number'
  300. ? fileData.mtime_ms
  301. : fileData.mtime_ms.toNumber();
  302. const size = fileData.size;
  303. let sha1hex = fileData['content.sha1hex'];
  304. if (typeof sha1hex !== 'string' || sha1hex.length !== 40) {
  305. sha1hex = undefined;
  306. }
  307. let nextData;
  308. if (
  309. existingFileData &&
  310. existingFileData[_constants().default.MTIME] === mtime
  311. ) {
  312. nextData = existingFileData;
  313. } else if (
  314. existingFileData &&
  315. sha1hex &&
  316. existingFileData[_constants().default.SHA1] === sha1hex
  317. ) {
  318. nextData = [
  319. existingFileData[0],
  320. mtime,
  321. existingFileData[2],
  322. existingFileData[3],
  323. existingFileData[4],
  324. existingFileData[5]
  325. ];
  326. } else {
  327. var _sha1hex;
  328. // See ../constants.ts
  329. nextData = [
  330. '',
  331. mtime,
  332. size,
  333. 0,
  334. '',
  335. (_sha1hex = sha1hex) !== null && _sha1hex !== void 0
  336. ? _sha1hex
  337. : null
  338. ];
  339. }
  340. files.set(relativeFilePath, nextData);
  341. changedFiles.set(relativeFilePath, nextData);
  342. }
  343. }
  344. }
  345. data.files = files;
  346. return {
  347. changedFiles: isFresh ? undefined : changedFiles,
  348. hasteMap: data,
  349. removedFiles
  350. };
  351. };