From c3047854adac41c6324c99c99f1d8dcccffe963f Mon Sep 17 00:00:00 2001 From: Cheng Zhao <zcbenz@gmail.com> Date: Mon, 8 Nov 2021 10:31:29 +0900 Subject: [PATCH 1/6] fix: latest node-gyp with old Electron versions --- package.json | 2 +- src/module-type/node-gyp.ts | 11 ++++++++++ test/module-type-node-gyp.ts | 41 +++++++++++++++++++++++++++++++++++ yarn.lock | 42 ++++++++++++++++++++++-------------- 4 files changed, 79 insertions(+), 17 deletions(-) create mode 100644 test/module-type-node-gyp.ts diff --git a/package.json b/package.json index e9121365..86c8b50b 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "lzma-native": "^8.0.1", "node-abi": "^3.0.0", "node-api-version": "^0.1.4", - "node-gyp": "^8.1.0", + "node-gyp": "^8.4.0", "ora": "^5.1.0", "tar": "^6.0.5", "yargs": "^17.0.1" diff --git a/src/module-type/node-gyp.ts b/src/module-type/node-gyp.ts index 78561773..a76e8972 100644 --- a/src/module-type/node-gyp.ts +++ b/src/module-type/node-gyp.ts @@ -36,6 +36,17 @@ export class NodeGyp extends NativeModule { args.push(`--msvs_version=${this.rebuilder.msvsVersion}`); } + // Headers of old Electron versions do not have a valid config.gypi file + // and --force-process-config must be passed to node-gyp >= 8.4.0 to + // correctly build modules for them. + // See also https://github.com/nodejs/node-gyp/pull/2497 + const [major, minor] = this.rebuilder.electronVersion.split('.').slice(0, 2).map(n => parseInt(n, 10)); + if ((major <= 13) || + (major == 14 && minor <= 1) || + (major == 15 && minor <= 2)) { + args.push('--force-process-config'); + } + return args; } diff --git a/test/module-type-node-gyp.ts b/test/module-type-node-gyp.ts new file mode 100644 index 00000000..2d2dacc0 --- /dev/null +++ b/test/module-type-node-gyp.ts @@ -0,0 +1,41 @@ +import { expect } from 'chai'; +import { EventEmitter } from 'events'; +import * as path from 'path'; +import * as os from 'os'; + +import { cleanupTestModule, resetTestModule, TIMEOUT_IN_MILLISECONDS } from './helpers/module-setup'; +import { NodeGyp } from '../src/module-type/node-gyp'; +import { Rebuilder } from '../src/rebuild'; + +describe('node-gyp', function() { + const testModulePath = path.resolve(os.tmpdir(), 'electron-rebuild-test'); + const oldElectronVersion = '12.0.0'; + const newElectronVersion = '16.0.0'; + + this.timeout(TIMEOUT_IN_MILLISECONDS); + + before(async () => await resetTestModule(testModulePath)); + after(async () => await cleanupTestModule(testModulePath)); + + it('adds --force-process-config for old Electron versions', async () => { + const rebuilder = new Rebuilder({ + buildPath: testModulePath, + electronVersion: oldElectronVersion, + lifecycle: new EventEmitter() + }); + const nodeGyp = new NodeGyp(rebuilder, testModulePath); + const args = await nodeGyp.buildArgs([]); + expect(args.includes('--force-process-config')).to.equal(true); + }); + + it('does not add --force-process-config for new Electron versions', async () => { + const rebuilder = new Rebuilder({ + buildPath: testModulePath, + electronVersion: newElectronVersion, + lifecycle: new EventEmitter() + }); + const nodeGyp = new NodeGyp(rebuilder, testModulePath); + const args = await nodeGyp.buildArgs([]); + expect(args.includes('--force-process-config')).to.equal(false); + }); +}); diff --git a/yarn.lock b/yarn.lock index 7091ae31..39425ee3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4624,13 +4624,13 @@ make-fetch-happen@^5.0.0: socks-proxy-agent "^4.0.0" ssri "^6.0.0" -make-fetch-happen@^8.0.14: - version "8.0.14" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz#aaba73ae0ab5586ad8eaa68bd83332669393e222" - integrity sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ== +make-fetch-happen@^9.0.1, make-fetch-happen@^9.0.4: + version "9.0.4" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.0.4.tgz#ceaa100e60e0ef9e8d1ede94614bb2ba83c8bb24" + integrity sha512-sQWNKMYqSmbAGXqJg2jZ+PmHh5JAybvwu0xM8mZR/bsTjGiTASj3ldXJV7KFHy1k/IJIBkjxQFoWIVsv9+PQMg== dependencies: agentkeepalive "^4.1.3" - cacache "^15.0.5" + cacache "^15.2.0" http-cache-semantics "^4.1.0" http-proxy-agent "^4.0.1" https-proxy-agent "^5.0.0" @@ -4641,14 +4641,15 @@ make-fetch-happen@^8.0.14: minipass-fetch "^1.3.2" minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" + negotiator "^0.6.2" promise-retry "^2.0.1" socks-proxy-agent "^5.0.0" ssri "^8.0.0" -make-fetch-happen@^9.0.1, make-fetch-happen@^9.0.4: - version "9.0.4" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.0.4.tgz#ceaa100e60e0ef9e8d1ede94614bb2ba83c8bb24" - integrity sha512-sQWNKMYqSmbAGXqJg2jZ+PmHh5JAybvwu0xM8mZR/bsTjGiTASj3ldXJV7KFHy1k/IJIBkjxQFoWIVsv9+PQMg== +make-fetch-happen@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" + integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== dependencies: agentkeepalive "^4.1.3" cacache "^15.2.0" @@ -4664,7 +4665,7 @@ make-fetch-happen@^9.0.1, make-fetch-happen@^9.0.4: minipass-pipeline "^1.2.4" negotiator "^0.6.2" promise-retry "^2.0.1" - socks-proxy-agent "^5.0.0" + socks-proxy-agent "^6.0.0" ssri "^8.0.0" map-obj@^1.0.0: @@ -5100,15 +5101,15 @@ node-gyp@^7.1.0, node-gyp@^7.1.2: tar "^6.0.2" which "^2.0.2" -node-gyp@^8.1.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.2.0.tgz#ef509ccdf5cef3b4d93df0690b90aa55ff8c7977" - integrity sha512-KG8SdcoAnw2d6augGwl1kOayALUrXW/P2uOAm2J2+nmW/HjZo7y+8TDg7LejxbekOOSv3kzhq+NSUYkIDAX8eA== +node-gyp@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.0.tgz#6e1112b10617f0f8559c64b3f737e8109e5a8338" + integrity sha512-Bi/oCm5bH6F+FmzfUxJpPaxMEyIhszULGR3TprmTeku8/dMFcdTcypk120NeZqEt54r1BrgEKtm2jJiuIKE28Q== dependencies: env-paths "^2.2.0" glob "^7.1.4" graceful-fs "^4.2.6" - make-fetch-happen "^8.0.14" + make-fetch-happen "^9.1.0" nopt "^5.0.0" npmlog "^4.1.2" rimraf "^3.0.2" @@ -6851,7 +6852,16 @@ socks-proxy-agent@^5.0.0: debug "4" socks "^2.3.3" -socks@^2.3.3: +socks-proxy-agent@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz#869cf2d7bd10fea96c7ad3111e81726855e285c3" + integrity sha512-57e7lwCN4Tzt3mXz25VxOErJKXlPfXmkMLnk310v/jwW20jWRVcgsOit+xNkN3eIEdB47GwnfAEBLacZ/wVIKg== + dependencies: + agent-base "^6.0.2" + debug "^4.3.1" + socks "^2.6.1" + +socks@^2.3.3, socks@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== From 4398825c6e314a46316dc934b91c2c22d6e66634 Mon Sep 17 00:00:00 2001 From: Mark Lee <electronjs@lazymalevolence.com> Date: Mon, 8 Nov 2021 07:39:58 -0800 Subject: [PATCH 2/6] refactor(test): use include on expect --- test/module-type-node-gyp.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/module-type-node-gyp.ts b/test/module-type-node-gyp.ts index 2d2dacc0..eee9e18c 100644 --- a/test/module-type-node-gyp.ts +++ b/test/module-type-node-gyp.ts @@ -25,7 +25,7 @@ describe('node-gyp', function() { }); const nodeGyp = new NodeGyp(rebuilder, testModulePath); const args = await nodeGyp.buildArgs([]); - expect(args.includes('--force-process-config')).to.equal(true); + expect(args).to.include('--force-process-config'); }); it('does not add --force-process-config for new Electron versions', async () => { @@ -36,6 +36,6 @@ describe('node-gyp', function() { }); const nodeGyp = new NodeGyp(rebuilder, testModulePath); const args = await nodeGyp.buildArgs([]); - expect(args.includes('--force-process-config')).to.equal(false); + expect(args).to.not.include('--force-process-config'); }); }); From 812abaffb5c66aa8f20932ea381f669c4a7fb752 Mon Sep 17 00:00:00 2001 From: Mark Lee <electronjs@lazymalevolence.com> Date: Mon, 8 Nov 2021 07:51:03 -0800 Subject: [PATCH 3/6] refactor(test): DRY up arg creation --- test/module-type-node-gyp.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/test/module-type-node-gyp.ts b/test/module-type-node-gyp.ts index eee9e18c..2ea673cf 100644 --- a/test/module-type-node-gyp.ts +++ b/test/module-type-node-gyp.ts @@ -17,25 +17,23 @@ describe('node-gyp', function() { before(async () => await resetTestModule(testModulePath)); after(async () => await cleanupTestModule(testModulePath)); - it('adds --force-process-config for old Electron versions', async () => { + function nodeGypArgsForElectronVersion(electronVersion: string): Promise<string[]> { const rebuilder = new Rebuilder({ buildPath: testModulePath, - electronVersion: oldElectronVersion, + electronVersion: electronVersion, lifecycle: new EventEmitter() }); const nodeGyp = new NodeGyp(rebuilder, testModulePath); - const args = await nodeGyp.buildArgs([]); + return nodeGyp.buildArgs([]); + } + + it('adds --force-process-config for old Electron versions', async () => { + const args = await nodeGypArgsForElectronVersion(oldElectronVersion); expect(args).to.include('--force-process-config'); }); it('does not add --force-process-config for new Electron versions', async () => { - const rebuilder = new Rebuilder({ - buildPath: testModulePath, - electronVersion: newElectronVersion, - lifecycle: new EventEmitter() - }); - const nodeGyp = new NodeGyp(rebuilder, testModulePath); - const args = await nodeGyp.buildArgs([]); + const args = await nodeGypArgsForElectronVersion(newElectronVersion); expect(args).to.not.include('--force-process-config'); }); }); From a9d0b32a7328b36dbae9623402ce80caaaa2cbc0 Mon Sep 17 00:00:00 2001 From: Mark Lee <electronjs@lazymalevolence.com> Date: Mon, 8 Nov 2021 07:51:35 -0800 Subject: [PATCH 4/6] refactor(test): speed up new tests by not running npm install --- test/helpers/module-setup.ts | 6 ++++-- test/module-type-node-gyp.ts | 6 ++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/helpers/module-setup.ts b/test/helpers/module-setup.ts index fa34f6fd..3a717940 100644 --- a/test/helpers/module-setup.ts +++ b/test/helpers/module-setup.ts @@ -14,14 +14,16 @@ export function resetMSVSVersion(): void { } } -export async function resetTestModule(testModulePath: string): Promise<void> { +export async function resetTestModule(testModulePath: string, installModules = true): Promise<void> { await fs.remove(testModulePath); await fs.mkdir(testModulePath, { recursive: true }); await fs.copyFile( path.resolve(__dirname, '../../test/fixture/native-app1/package.json'), path.resolve(testModulePath, 'package.json') ); - await spawn('npm', ['install'], { cwd: testModulePath }); + if (installModules) { + await spawn('npm', ['install'], { cwd: testModulePath }); + } resetMSVSVersion(); } diff --git a/test/module-type-node-gyp.ts b/test/module-type-node-gyp.ts index 2ea673cf..e3d5ff2b 100644 --- a/test/module-type-node-gyp.ts +++ b/test/module-type-node-gyp.ts @@ -3,7 +3,7 @@ import { EventEmitter } from 'events'; import * as path from 'path'; import * as os from 'os'; -import { cleanupTestModule, resetTestModule, TIMEOUT_IN_MILLISECONDS } from './helpers/module-setup'; +import { cleanupTestModule, resetTestModule } from './helpers/module-setup'; import { NodeGyp } from '../src/module-type/node-gyp'; import { Rebuilder } from '../src/rebuild'; @@ -12,9 +12,7 @@ describe('node-gyp', function() { const oldElectronVersion = '12.0.0'; const newElectronVersion = '16.0.0'; - this.timeout(TIMEOUT_IN_MILLISECONDS); - - before(async () => await resetTestModule(testModulePath)); + before(async () => await resetTestModule(testModulePath, false)); after(async () => await cleanupTestModule(testModulePath)); function nodeGypArgsForElectronVersion(electronVersion: string): Promise<string[]> { From a70b2c44b189390e131c00cf2ac3ed6d51523fb0 Mon Sep 17 00:00:00 2001 From: Mark Lee <electronjs@lazymalevolence.com> Date: Mon, 8 Nov 2021 08:14:49 -0800 Subject: [PATCH 5/6] test(node-gyp): exhaustively test the conditional --- test/module-type-node-gyp.ts | 72 ++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/test/module-type-node-gyp.ts b/test/module-type-node-gyp.ts index e3d5ff2b..08a2dbfc 100644 --- a/test/module-type-node-gyp.ts +++ b/test/module-type-node-gyp.ts @@ -1,37 +1,61 @@ -import { expect } from 'chai'; import { EventEmitter } from 'events'; -import * as path from 'path'; -import * as os from 'os'; +import { expect } from 'chai'; +import os from 'os'; +import path from 'path'; import { cleanupTestModule, resetTestModule } from './helpers/module-setup'; import { NodeGyp } from '../src/module-type/node-gyp'; import { Rebuilder } from '../src/rebuild'; -describe('node-gyp', function() { - const testModulePath = path.resolve(os.tmpdir(), 'electron-rebuild-test'); - const oldElectronVersion = '12.0.0'; - const newElectronVersion = '16.0.0'; +describe('node-gyp', () => { + describe('buildArgs', () => { + const testModulePath = path.resolve(os.tmpdir(), 'electron-rebuild-test'); + + before(async () => await resetTestModule(testModulePath, false)); + after(async () => await cleanupTestModule(testModulePath)); + + function nodeGypArgsForElectronVersion(electronVersion: string): Promise<string[]> { + const rebuilder = new Rebuilder({ + buildPath: testModulePath, + electronVersion: electronVersion, + lifecycle: new EventEmitter() + }); + const nodeGyp = new NodeGyp(rebuilder, testModulePath); + return nodeGyp.buildArgs([]); + } - before(async () => await resetTestModule(testModulePath, false)); - after(async () => await cleanupTestModule(testModulePath)); + context('sufficiently old Electron versions which lack a bundled config.gypi', () => { + it('adds --force-process-config for < 14', async () => { + const args = await nodeGypArgsForElectronVersion('12.0.0'); + expect(args).to.include('--force-process-config'); + }); - function nodeGypArgsForElectronVersion(electronVersion: string): Promise<string[]> { - const rebuilder = new Rebuilder({ - buildPath: testModulePath, - electronVersion: electronVersion, - lifecycle: new EventEmitter() + it('adds --force-process-config for between 14.0.0 and < 14.2.0', async () => { + const args = await nodeGypArgsForElectronVersion('14.1.0'); + expect(args).to.include('--force-process-config'); + }); + + it('adds --force-process-config for versions between 15.0.0 and < 15.3.0', async () => { + const args = await nodeGypArgsForElectronVersion('15.2.0'); + expect(args).to.include('--force-process-config'); + }); }); - const nodeGyp = new NodeGyp(rebuilder, testModulePath); - return nodeGyp.buildArgs([]); - } - it('adds --force-process-config for old Electron versions', async () => { - const args = await nodeGypArgsForElectronVersion(oldElectronVersion); - expect(args).to.include('--force-process-config'); - }); + context('for sufficiently new Electron versions', () => { + it('does not add --force-process-config for ^14.2.0', async () => { + const args = await nodeGypArgsForElectronVersion('14.2.0'); + expect(args).to.not.include('--force-process-config'); + }); - it('does not add --force-process-config for new Electron versions', async () => { - const args = await nodeGypArgsForElectronVersion(newElectronVersion); - expect(args).to.not.include('--force-process-config'); + it('does not add --force-process-config for ^15.3.0', async () => { + const args = await nodeGypArgsForElectronVersion('15.3.0'); + expect(args).to.not.include('--force-process-config'); + }); + + it('does not add --force-process-config for >= 16.0.0', async () => { + const args = await nodeGypArgsForElectronVersion('16.0.0-beta.1'); + expect(args).to.not.include('--force-process-config'); + }); + }); }); }); From f2bd27fc6915b561f9549f2724fbe50fd722f7a7 Mon Sep 17 00:00:00 2001 From: Mark Lee <electronjs@lazymalevolence.com> Date: Mon, 8 Nov 2021 20:47:52 -0800 Subject: [PATCH 6/6] refactor: use semver to compare versions --- package.json | 6 +++++- src/module-type/node-gyp.ts | 6 ++---- test/module-type-node-gyp.ts | 2 +- yarn.lock | 5 +++++ 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 86c8b50b..3f2951ad 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "node-api-version": "^0.1.4", "node-gyp": "^8.4.0", "ora": "^5.1.0", + "semver": "^7.3.5", "tar": "^6.0.5", "yargs": "^17.0.1" }, @@ -64,6 +65,7 @@ "@types/mocha": "^9.0.0", "@types/node": "^16.0.1", "@types/node-abi": "^3.0.0", + "@types/semver": "^7.3.9", "@types/tar": "^4.0.3", "@types/yargs": "^17.0.2", "@typescript-eslint/eslint-plugin": "^4.0.1", @@ -119,7 +121,9 @@ "node_modules" ], "mocha": { - "extensions": ["ts"], + "extensions": [ + "ts" + ], "require": "ts-node/register" }, "nyc": { diff --git a/src/module-type/node-gyp.ts b/src/module-type/node-gyp.ts index a76e8972..73eb8edc 100644 --- a/src/module-type/node-gyp.ts +++ b/src/module-type/node-gyp.ts @@ -3,6 +3,7 @@ import detectLibc from 'detect-libc'; import NodeGypRunner from 'node-gyp'; import path from 'path'; import { promisify } from 'util'; +import semver from 'semver'; import { ELECTRON_GYP_DIR } from '../constants'; import { getClangEnvironmentVars } from '../clang-fetcher'; @@ -40,10 +41,7 @@ export class NodeGyp extends NativeModule { // and --force-process-config must be passed to node-gyp >= 8.4.0 to // correctly build modules for them. // See also https://github.com/nodejs/node-gyp/pull/2497 - const [major, minor] = this.rebuilder.electronVersion.split('.').slice(0, 2).map(n => parseInt(n, 10)); - if ((major <= 13) || - (major == 14 && minor <= 1) || - (major == 15 && minor <= 2)) { + if (!semver.satisfies(this.rebuilder.electronVersion, '^14.2.0 || ^15.3.0 || >= 16.0.0-alpha.1')) { args.push('--force-process-config'); } diff --git a/test/module-type-node-gyp.ts b/test/module-type-node-gyp.ts index 08a2dbfc..9ebd1700 100644 --- a/test/module-type-node-gyp.ts +++ b/test/module-type-node-gyp.ts @@ -53,7 +53,7 @@ describe('node-gyp', () => { }); it('does not add --force-process-config for >= 16.0.0', async () => { - const args = await nodeGypArgsForElectronVersion('16.0.0-beta.1'); + const args = await nodeGypArgsForElectronVersion('16.0.0-alpha.1'); expect(args).to.not.include('--force-process-config'); }); }); diff --git a/yarn.lock b/yarn.lock index 39425ee3..68d9b9af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -844,6 +844,11 @@ resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.1.tgz#d8f1c0d0dc23afad6dc16a9e993a0865774b4065" integrity sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g== +"@types/semver@^7.3.9": + version "7.3.9" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.9.tgz#152c6c20a7688c30b967ec1841d31ace569863fc" + integrity sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ== + "@types/tar@^4.0.3": version "4.0.5" resolved "https://registry.yarnpkg.com/@types/tar/-/tar-4.0.5.tgz#5f953f183e36a15c6ce3f336568f6051b7b183f3"