From c4d94ea7d2e5c4e27956f10be2dcf98170f60ae6 Mon Sep 17 00:00:00 2001 From: Leonardo Villela Date: Mon, 17 Feb 2020 01:41:48 +0000 Subject: [PATCH 1/5] fix: crash on unix based systems without find --- CHANGELOG.md | 1 + packages/jest-haste-map/package.json | 6 ++-- .../src/crawlers/__tests__/node.test.js | 29 +++++++++++++++++++ packages/jest-haste-map/src/crawlers/node.ts | 17 +++++++---- yarn.lock | 2 +- 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bd86745e036..f0f2232d47fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ - `[jest-cli]` Set `coverageProvider` correctly when provided in config ([#9562](https://github.com/facebook/jest/pull/9562)) - `[jest-cli]` Allow specifying `.cjs` and `.mjs` config files by `--config` CLI option ([#9578](https://github.com/facebook/jest/pull/9578)) - `[jest-config]` Ensure pattern of `replacePosixSep` is a string ([#9546]https://github.com/facebook/jest/pull/9546) +- `[jest-haste-map]` Fix crash on unix based systems without find ([#9571](https://github.com/facebook/jest/pull/9571)) - `[jest-matcher-utils]` Fix diff highlight of symbol-keyed object. ([#9499](https://github.com/facebook/jest/pull/9499)) - `[@jest/reporters]` Notifications should be fire&forget rather than having a timeout ([#9567](https://github.com/facebook/jest/pull/9567)) - `[jest-resolve]` Fix module identity preservation with symlinks and browser field resolution ([#9511](https://github.com/facebook/jest/pull/9511)) diff --git a/packages/jest-haste-map/package.json b/packages/jest-haste-map/package.json index 3dd28cea3f7c..931df0c57ee4 100644 --- a/packages/jest-haste-map/package.json +++ b/packages/jest-haste-map/package.json @@ -19,7 +19,8 @@ "jest-worker": "^25.1.0", "micromatch": "^4.0.2", "sane": "^4.0.3", - "walker": "^1.0.7" + "walker": "^1.0.7", + "which": "^2.0.2" }, "devDependencies": { "@jest/test-utils": "^25.1.0", @@ -28,7 +29,8 @@ "@types/graceful-fs": "^4.1.2", "@types/micromatch": "^4.0.0", "@types/node": "*", - "@types/sane": "^2.0.0" + "@types/sane": "^2.0.0", + "@types/which": "^1.3.2" }, "optionalDependencies": { "fsevents": "^2.1.2" diff --git a/packages/jest-haste-map/src/crawlers/__tests__/node.test.js b/packages/jest-haste-map/src/crawlers/__tests__/node.test.js index 6130a2f8ffe8..863ecb8c4ad2 100644 --- a/packages/jest-haste-map/src/crawlers/__tests__/node.test.js +++ b/packages/jest-haste-map/src/crawlers/__tests__/node.test.js @@ -124,6 +124,8 @@ jest.mock('fs', () => { }; }); +jest.mock('which', () => jest.fn().mockResolvedValue()); + const pearMatcher = path => /pear/.test(path); const createMap = obj => new Map(Object.keys(obj).map(key => [key, obj[key]])); @@ -291,6 +293,33 @@ describe('node crawler', () => { }); }); + it('uses node fs APIs on Unix based OS without find binary', () => { + process.platform = 'linux'; + const which = require('which'); + which.mockReturnValueOnce(Promise.reject()); + + nodeCrawl = require('../node'); + + return nodeCrawl({ + data: { + files: new Map(), + }, + extensions: ['js'], + ignore: pearMatcher, + rootDir, + roots: ['/project/fruits'], + }).then(({hasteMap, removedFiles}) => { + expect(hasteMap.files).toEqual( + createMap({ + 'fruits/directory/strawberry.js': ['', 33, 42, 0, '', null], + 'fruits/tomato.js': ['', 32, 42, 0, '', null], + }), + ); + expect(removedFiles).toEqual(new Map()); + expect(which).toBeCalledWith('find'); + }); + }); + it('uses node fs APIs if "forceNodeFilesystemAPI" is set to true, regardless of platform', () => { process.platform = 'linux'; diff --git a/packages/jest-haste-map/src/crawlers/node.ts b/packages/jest-haste-map/src/crawlers/node.ts index 833f51f80f14..f3ea66c2e4d5 100644 --- a/packages/jest-haste-map/src/crawlers/node.ts +++ b/packages/jest-haste-map/src/crawlers/node.ts @@ -8,6 +8,7 @@ import * as fs from 'fs'; import * as path from 'path'; import {spawn} from 'child_process'; +import which = require('which'); import H from '../constants'; import * as fastPath from '../lib/fast_path'; import { @@ -21,6 +22,14 @@ type Result = Array<[/* id */ string, /* mtime */ number, /* size */ number]>; type Callback = (result: Result) => void; +function hasNativeFindSupport(forceNodeFilesystemAPI: boolean): Promise { + if (forceNodeFilesystemAPI) return Promise.reject(); + + return process.platform === 'win32' + ? Promise.reject() + : ((which('find') as unknown) as Promise); +} + function find( roots: Array, extensions: Array, @@ -193,10 +202,8 @@ export = function nodeCrawl( }); }; - if (forceNodeFilesystemAPI || process.platform === 'win32') { - find(roots, extensions, ignore, callback); - } else { - findNative(roots, extensions, ignore, callback); - } + hasNativeFindSupport(forceNodeFilesystemAPI) + .then(() => findNative(roots, extensions, ignore, callback)) + .catch(() => find(roots, extensions, ignore, callback)); }); }; diff --git a/yarn.lock b/yarn.lock index 10e8dc2054c6..ebb58e5c97db 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14745,7 +14745,7 @@ which@1.3.1, which@^1.2.1, which@^1.2.9, which@^1.3.0, which@^1.3.1: dependencies: isexe "^2.0.0" -which@^2.0.1: +which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== From c3997c2c3e350dea9b56363812f41a78ea447f97 Mon Sep 17 00:00:00 2001 From: Leonardo Villela Date: Mon, 17 Feb 2020 01:47:28 +0000 Subject: [PATCH 2/5] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0f2232d47fb..cddb71d584a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ - `[jest-cli]` Set `coverageProvider` correctly when provided in config ([#9562](https://github.com/facebook/jest/pull/9562)) - `[jest-cli]` Allow specifying `.cjs` and `.mjs` config files by `--config` CLI option ([#9578](https://github.com/facebook/jest/pull/9578)) - `[jest-config]` Ensure pattern of `replacePosixSep` is a string ([#9546]https://github.com/facebook/jest/pull/9546) -- `[jest-haste-map]` Fix crash on unix based systems without find ([#9571](https://github.com/facebook/jest/pull/9571)) +- `[jest-haste-map]` Fix crash on unix based systems without find ([#9579](https://github.com/facebook/jest/pull/9579)) - `[jest-matcher-utils]` Fix diff highlight of symbol-keyed object. ([#9499](https://github.com/facebook/jest/pull/9499)) - `[@jest/reporters]` Notifications should be fire&forget rather than having a timeout ([#9567](https://github.com/facebook/jest/pull/9567)) - `[jest-resolve]` Fix module identity preservation with symlinks and browser field resolution ([#9511](https://github.com/facebook/jest/pull/9511)) From a8f28fe25ec3cf27f8a15fa6dc1090e37409e670 Mon Sep 17 00:00:00 2001 From: Leonardo Villela Date: Mon, 17 Feb 2020 23:42:54 +0000 Subject: [PATCH 3/5] Use which sync interface --- .../src/crawlers/__tests__/node.test.js | 8 ++++--- packages/jest-haste-map/src/crawlers/node.ts | 23 ++++++++++++------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/packages/jest-haste-map/src/crawlers/__tests__/node.test.js b/packages/jest-haste-map/src/crawlers/__tests__/node.test.js index 863ecb8c4ad2..cac3e5329ad3 100644 --- a/packages/jest-haste-map/src/crawlers/__tests__/node.test.js +++ b/packages/jest-haste-map/src/crawlers/__tests__/node.test.js @@ -124,7 +124,7 @@ jest.mock('fs', () => { }; }); -jest.mock('which', () => jest.fn().mockResolvedValue()); +jest.mock('which'); const pearMatcher = path => /pear/.test(path); const createMap = obj => new Map(Object.keys(obj).map(key => [key, obj[key]])); @@ -296,7 +296,9 @@ describe('node crawler', () => { it('uses node fs APIs on Unix based OS without find binary', () => { process.platform = 'linux'; const which = require('which'); - which.mockReturnValueOnce(Promise.reject()); + which.sync.mockImplementation(() => { + throw new Error(); + }); nodeCrawl = require('../node'); @@ -316,7 +318,7 @@ describe('node crawler', () => { }), ); expect(removedFiles).toEqual(new Map()); - expect(which).toBeCalledWith('find'); + expect(which.sync).toBeCalledWith('find'); }); }); diff --git a/packages/jest-haste-map/src/crawlers/node.ts b/packages/jest-haste-map/src/crawlers/node.ts index f3ea66c2e4d5..a60baf293cd6 100644 --- a/packages/jest-haste-map/src/crawlers/node.ts +++ b/packages/jest-haste-map/src/crawlers/node.ts @@ -22,12 +22,17 @@ type Result = Array<[/* id */ string, /* mtime */ number, /* size */ number]>; type Callback = (result: Result) => void; -function hasNativeFindSupport(forceNodeFilesystemAPI: boolean): Promise { - if (forceNodeFilesystemAPI) return Promise.reject(); +function hasNativeFindSupport(forceNodeFilesystemAPI: boolean): boolean { + if (forceNodeFilesystemAPI || process.platform === 'win32') { + return false; + } - return process.platform === 'win32' - ? Promise.reject() - : ((which('find') as unknown) as Promise); + try { + which.sync('find'); + return true; + } catch { + return false; + } } function find( @@ -202,8 +207,10 @@ export = function nodeCrawl( }); }; - hasNativeFindSupport(forceNodeFilesystemAPI) - .then(() => findNative(roots, extensions, ignore, callback)) - .catch(() => find(roots, extensions, ignore, callback)); + if (hasNativeFindSupport(forceNodeFilesystemAPI)) { + findNative(roots, extensions, ignore, callback); + } else { + find(roots, extensions, ignore, callback); + } }); }; From 10225a0c5447ee401f3dedc1d62d99d9de342c1d Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 18 Feb 2020 09:06:46 +0100 Subject: [PATCH 4/5] Revert "Use which sync interface" This reverts commit a8f28fe25ec3cf27f8a15fa6dc1090e37409e670. --- .../src/crawlers/__tests__/node.test.js | 8 +++---- packages/jest-haste-map/src/crawlers/node.ts | 23 +++++++------------ 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/packages/jest-haste-map/src/crawlers/__tests__/node.test.js b/packages/jest-haste-map/src/crawlers/__tests__/node.test.js index cac3e5329ad3..863ecb8c4ad2 100644 --- a/packages/jest-haste-map/src/crawlers/__tests__/node.test.js +++ b/packages/jest-haste-map/src/crawlers/__tests__/node.test.js @@ -124,7 +124,7 @@ jest.mock('fs', () => { }; }); -jest.mock('which'); +jest.mock('which', () => jest.fn().mockResolvedValue()); const pearMatcher = path => /pear/.test(path); const createMap = obj => new Map(Object.keys(obj).map(key => [key, obj[key]])); @@ -296,9 +296,7 @@ describe('node crawler', () => { it('uses node fs APIs on Unix based OS without find binary', () => { process.platform = 'linux'; const which = require('which'); - which.sync.mockImplementation(() => { - throw new Error(); - }); + which.mockReturnValueOnce(Promise.reject()); nodeCrawl = require('../node'); @@ -318,7 +316,7 @@ describe('node crawler', () => { }), ); expect(removedFiles).toEqual(new Map()); - expect(which.sync).toBeCalledWith('find'); + expect(which).toBeCalledWith('find'); }); }); diff --git a/packages/jest-haste-map/src/crawlers/node.ts b/packages/jest-haste-map/src/crawlers/node.ts index a60baf293cd6..f3ea66c2e4d5 100644 --- a/packages/jest-haste-map/src/crawlers/node.ts +++ b/packages/jest-haste-map/src/crawlers/node.ts @@ -22,17 +22,12 @@ type Result = Array<[/* id */ string, /* mtime */ number, /* size */ number]>; type Callback = (result: Result) => void; -function hasNativeFindSupport(forceNodeFilesystemAPI: boolean): boolean { - if (forceNodeFilesystemAPI || process.platform === 'win32') { - return false; - } +function hasNativeFindSupport(forceNodeFilesystemAPI: boolean): Promise { + if (forceNodeFilesystemAPI) return Promise.reject(); - try { - which.sync('find'); - return true; - } catch { - return false; - } + return process.platform === 'win32' + ? Promise.reject() + : ((which('find') as unknown) as Promise); } function find( @@ -207,10 +202,8 @@ export = function nodeCrawl( }); }; - if (hasNativeFindSupport(forceNodeFilesystemAPI)) { - findNative(roots, extensions, ignore, callback); - } else { - find(roots, extensions, ignore, callback); - } + hasNativeFindSupport(forceNodeFilesystemAPI) + .then(() => findNative(roots, extensions, ignore, callback)) + .catch(() => find(roots, extensions, ignore, callback)); }); }; From ee303a1d31eb26006fd35cad8024feb6b93108c6 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 18 Feb 2020 09:10:22 +0100 Subject: [PATCH 5/5] use promise --- packages/jest-haste-map/src/crawlers/node.ts | 29 ++++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/jest-haste-map/src/crawlers/node.ts b/packages/jest-haste-map/src/crawlers/node.ts index f3ea66c2e4d5..c1d4ba50b1fc 100644 --- a/packages/jest-haste-map/src/crawlers/node.ts +++ b/packages/jest-haste-map/src/crawlers/node.ts @@ -22,12 +22,19 @@ type Result = Array<[/* id */ string, /* mtime */ number, /* size */ number]>; type Callback = (result: Result) => void; -function hasNativeFindSupport(forceNodeFilesystemAPI: boolean): Promise { - if (forceNodeFilesystemAPI) return Promise.reject(); +async function hasNativeFindSupport( + forceNodeFilesystemAPI: boolean, +): Promise { + if (forceNodeFilesystemAPI || process.platform === 'win32') { + return false; + } - return process.platform === 'win32' - ? Promise.reject() - : ((which('find') as unknown) as Promise); + try { + await which('find'); + return true; + } catch { + return false; + } } function find( @@ -163,7 +170,7 @@ function findNative( }); } -export = function nodeCrawl( +export = async function nodeCrawl( options: CrawlerOptions, ): Promise<{ removedFiles: FileData; @@ -178,6 +185,8 @@ export = function nodeCrawl( roots, } = options; + const useNativeFind = await hasNativeFindSupport(forceNodeFilesystemAPI); + return new Promise(resolve => { const callback = (list: Result) => { const files = new Map(); @@ -202,8 +211,10 @@ export = function nodeCrawl( }); }; - hasNativeFindSupport(forceNodeFilesystemAPI) - .then(() => findNative(roots, extensions, ignore, callback)) - .catch(() => find(roots, extensions, ignore, callback)); + if (useNativeFind) { + findNative(roots, extensions, ignore, callback); + } else { + find(roots, extensions, ignore, callback); + } }); };